_exit.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include <fcntl.h>

extern int _argc, _arg_len;
extern char **_argv, *_arg_lin;
extern struct WBStartup *WBenchMsg;
extern void *MathBase, *MathTransBase;
extern void *MathIeeeDoubBasBase, *MathIeeeDoubTransBase;
extern long _detach_curdir;
extern void *_oldtrap, **_trapaddr;

void (*_cln)();

_exit(code)
{
	long ret = code;
	register int fd;

	if (_devtab) {
		for (fd = 0 ; fd < _numdev ; fd++)
			close(fd);
		_FreeMem(_devtab, _numdev*(long)sizeof(struct _dev));
	}
	if (_cln)
		(*_cln)();
	if (_detach_curdir)				/* for DETACHed programs */
		UnLock(_detach_curdir);
	if (_trapaddr)					/* clean up signal handling */
		*_trapaddr = _oldtrap;
	if (MathTransBase)
		_CloseLibrary(MathTransBase);
	if (MathBase)
		_CloseLibrary(MathBase);
	if (MathIeeeDoubBasBase)
		_CloseLibrary(MathIeeeDoubBasBase);
	if (MathIeeeDoubTransBase)
		_CloseLibrary(MathIeeeDoubTransBase);
	{
#asm
	mc68881
	move.l	4,a6				;get ExecBase
	btst.b	#4,$129(a6)			;check for 68881 flag in AttnFlags
	beq		1$					;skip if not
	move.l	a5,-(sp)
	lea		2$,a5
	jsr		-30(a6)				;do it in supervisor mode
	move.l	(sp)+,a5
	bra		1$
2$
	clr.l	-(sp)
	frestore (sp)+				;reset the ffp stuff
	rte							;and return
1$
#endasm
	}
	if (WBenchMsg == 0) {
		if (_arg_lin) {
			_FreeMem(_arg_lin, (long)_arg_len);
			_FreeMem(_argv, (long)(_argc+1)*sizeof(*_argv));
		}
	}
	else {
		_Forbid();
		_ReplyMsg(WBenchMsg);
	}
	{
#asm
		move.l	-4(a5),d0		;pick up return exit code
		move.l	__savsp#,sp		;get back original stack pointer
		rts						;and exit
#endasm
	}
}

_main.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

/*
 *	This is common startup code for both the CLI and the WorkBench.
 *	When called from the WorkBench, argc is 0 and argv points to a
 *	WBStartup type of structure.
 */

#include <fcntl.h>
#include <exec/alerts.h>
#include <exec/memory.h>
#include <libraries/dosextens.h>
#include <workbench/startup.h>
#include <functions.h>

extern long _savsp, _stkbase;

extern int errno;
extern int Enable_Abort;

extern int _argc, _arg_len;
extern char **_argv, *_arg_lin;
extern struct WBStartup *WBenchMsg;

extern struct _dev *_devtab;
extern short _numdev;

_main(alen, aptr)
long alen;
char *aptr;
{
	register struct Process *pp, *_FindTask();
	void *_OpenLibrary(), *_GetMsg(), *_AllocMem();
	long _Input(), _Output(), _Open();

#ifdef DETACH
	void do_detach();

	do_detach(&alen, &aptr);
#endif

	if ((_devtab = _AllocMem(_numdev*(long)sizeof(struct _dev),
													MEMF_CLEAR)) == 0) {
		Alert(AG_NoMemory, 0L);
#asm
		move.l	__savsp,sp		;get back original stack pointer
		rts						;and exit
#endasm
	}

	_devtab[0].mode = O_RDONLY;
	_devtab[1].mode = _devtab[2].mode = O_WRONLY;

	_stkbase = _savsp - *((long *)_savsp+1) + 8;
	*(long *)_stkbase = 0x4d414e58L;

	pp = _FindTask(0L);
#ifdef DETACH
	if (alen) {
#else
	if (pp->pr_CLI) {
#endif
		_cli_parse(pp, alen, aptr);
		Enable_Abort = 1;
#ifndef DETACH
		_devtab[0].mode |= O_STDIO;		/* shouldn't close if CLI */
		_devtab[1].mode |= O_STDIO;
#endif
	}
	else {
		_WaitPort(&pp->pr_MsgPort);
		WBenchMsg = _GetMsg(&pp->pr_MsgPort);
		if (WBenchMsg->sm_ArgList)
			_CurrentDir(WBenchMsg->sm_ArgList->wa_Lock);
		_wb_parse(pp, WBenchMsg);
		_argv = (char **)WBenchMsg;
	}
	_devtab[0].fd = _Input();
	if (_devtab[1].fd = _Output())
		_devtab[2].fd = _Open("*", MODE_OLDFILE);
	main(_argc, _argv);
	exit(0);
}

#ifdef DETACH
extern long _stack, _priority, _BackGroundIO;
extern char *_procname;
BPTR _Backstdout = 0;
extern struct FileLock *_detach_curdir;
extern char *_detach_name;
static long _alen = 0;
static char *_aptr = 0;

static void
do_detach(alen, aptr)
long *alen;
char **aptr;
{
	register struct Process *pp, *_FindTask();
	void *sav, *_OpenLibrary(), *_GetMsg(), *_AllocMem();
	long _Open();
	register unsigned short c;
	register char *cp;
	register struct CommandLineInterface *cli;
	register long l;
	long *lp;
	struct MemList *mm;
	struct FileLock *CurrentDir();

	pp = _FindTask(0L);
	if (pp->pr_CLI) {			/* first time through!! */
		CurrentDir(_detach_curdir = CurrentDir(0L));
		_detach_curdir = DupLock(_detach_curdir);

		cli = (struct CommandLineInterface *) ((long)pp->pr_CLI << 2);
		l = cli->cli_Module;
		if ((sav = _OpenLibrary(DOSNAME, 33L)) == 0) {

			lp = (long *)*((long *)*((long *)*((long *)*((long *)
											_savsp+2)+1)-3)-3)+107;
			if (*lp != cli->cli_Module)
				exit(100);
		}
		else {
			_CloseLibrary(sav);
			lp = 0;
		}
		if (lp)
			*lp = 0;
		if (_stack == 0)
			_stack = cli->cli_DefaultStack * 4;
		if (_BackGroundIO)
			_Backstdout = (BPTR)_Open("*", MODE_OLDFILE);
		_alen = *alen;
		_aptr = _AllocMem(_alen, 0L);
		movmem(*aptr, _aptr, (int)_alen);
		cp = (char *)((long)cli->cli_CommandName << 2);
		_detach_name = AllocMem((long)cp[0]+1, 0L);
		movmem(cp, _detach_name, cp[0]+1);
#asm
		move.l	__savsp,-(sp)
#endasm
		CreateProc(_procname, _priority, l, _stack);
		cli->cli_Module = 0;
#asm
		move.l	(sp)+,sp
		move.l	#0,d0
		rts
#endasm
	}
	else if (strcmp(pp->pr_Task.tc_Node.ln_Name, _procname) == 0) { /* second time */
		lp = (long *)((long)pp->pr_SegList << 2);
		lp = (long *)(lp[3] << 2);
		sav = lp;
		c = 2;
		while (lp) {
			lp = (long *)(*lp << 2);
			c++;
		}
		mm = _AllocMem((long)sizeof(struct MemList)+
							(c-1)*sizeof(struct MemEntry), 0L);
		lp = sav;
		mm->ml_NumEntries = c;
		c = 0;
		while (lp) {
			mm->ml_me[c].me_Addr = (APTR)lp - 1;
			mm->ml_me[c].me_Length = lp[-1];
			lp = (long *)(*lp << 2);
			c++;
		}
		mm->ml_me[c].me_Addr = (APTR)_aptr;
		mm->ml_me[c++].me_Length = _alen;
		mm->ml_me[c].me_Addr = (APTR)_detach_name;
		mm->ml_me[c++].me_Length = _detach_name[0] + 1;

		AddTail(&((struct Task *)pp)->tc_MemEntry, mm);

		CurrentDir(_detach_curdir);

		pp->pr_COS = _Backstdout;

		*alen = _alen;
		*aptr = _aptr;
	}
}
#endif

abort.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

_abort()
{
	long _Output();

	_Write(_Output(), "^C\n", 4L);
	exit(1);
}

access.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include	<errno.h>
#include	<libraries/dos.h>

access(filename, mode)
char *filename;
int mode;
{
	long l, _Lock();
	int ret = -1;

	if ((l = _Lock(filename, ACCESS_READ)) == 0) {
		errno = ENOENT;
		return(-1);
	}
	switch(mode) {
	case 2:			/* write */
		_UnLock(l);
		if ((l = _Lock(filename, ACCESS_WRITE)) == 0) {
			errno = EACCES;
			return(-1);
		}
		/* FALL THRU */
	case 0:			/* existence */
	case 1:			/* execute (if file) or search (if directory) */
	case 4:			/* read */
		ret = 0;
		break;
	}
	_UnLock(l);
	return(ret);
}

chkabort.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

long
Chk_Abort()
{
	long x, _SetSignal(), _Write();
	extern int Enable_Abort;

	if ((x = _SetSignal(0L, 0x1000L))&0x1000) {
		if (Enable_Abort == 0)
			return(x);
		_abort();
	}
	return(0);
}

cliparse.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

/*
 *	This routine is called from the _main() routine and is used to
 *	parse the arguments passed from the CLI to the program. It sets
 *	up an array of pointers to arguments in the global variables and
 *	and sets up _argc and _argv which will be passed by _main() to
 *	the main() procedure. If no arguments are ever going to be
 *	parsed, this routine may be replaced by a stub routine to reduce
 *	program size.
 *
 *	If _arg_lin is non-zero, the _exit() routine will call FreeMem()
 *	with _arg_lin as the memory to free and _arg_len as the size.
 *
 */

#include <libraries/dosextens.h>

extern int _argc, _arg_len;
extern char **_argv, *_arg_lin;
extern char *_detach_name;			/* for DETACHED programs */

_cli_parse(pp, alen, aptr)
struct Process *pp;
long alen;
register char *aptr;
{
	register char *cp;
	register struct CommandLineInterface *cli;
	register int c;
	void *_AllocMem();

	if (pp->pr_CLI) {
		cli = (struct CommandLineInterface *) ((long)pp->pr_CLI << 2);
		cp = (char *)((long)cli->cli_CommandName << 2);
	}
	else
		cp = _detach_name;
	_arg_len = cp[0]+alen+2;
	if ((_arg_lin = _AllocMem((long)_arg_len, 0L)) == 0)
		return;
	c = cp[0];
	strncpy(_arg_lin, cp+1, c);
	strcpy(_arg_lin+c, " ");
	strncat(_arg_lin, aptr, (int)alen);
	_arg_lin[c] = 0;
	for (_argc=1,aptr=cp=_arg_lin+c+1;;_argc++) {
		while ((c=*cp) == ' ' || c == '\t' || c == '\f' ||
												c == '\r' || c == '\n')
			cp++;
		if (*cp < ' ')
			break;
		if (*cp == '"') {
			cp++;
			while (c = *cp++) {
				*aptr++ = c;
				if (c == '"') {
					if (*cp == '"')
						cp++;
					else {
						aptr[-1] = 0;
						break;
					}
				}
			}
		}
		else {
			while ((c=*cp++) && c != ' ' && c != '\t' && c != '\f' &&
												c != '\r' && c != '\n')
				*aptr++ = c;
			*aptr++ = 0;
		}
		if (c == 0)
			--cp;
	}
	*aptr = 0;
	if ((_argv = _AllocMem((long)(_argc+1)*sizeof(*_argv), 0L)) == 0) {
		_argc = 0;
		return;
	}
	for (c=0,cp=_arg_lin;c<_argc;c++) {
		_argv[c] = cp;
		cp += strlen(cp) + 1;
	}
	_argv[c] = 0;
}

close.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include <errno.h>
#include <fcntl.h>

close(fd)
register int fd;
{
	register struct _dev *refp;
	register int i, err;

	refp = _devtab + fd;
	if (fd < 0 || fd >= _numdev || refp->fd == 0) {
		errno = EBADF;
		return(-1);
	}
	if ((refp->mode & O_STDIO) == 0)
		_Close(refp->fd);
	refp->fd = 0;
	return(0);
}

crt0.a68
;:ts=8
; Copyright (C) 1986,1987 by Manx Software Systems, Inc.
;


;	Initial startup routine for Aztec C.

;	NOTE: code down to "start" must be placed at beginning of
;		all programs linked with Aztec Linker using small
;		code or small data.


	mc68881
	entry	.begin
	public	.begin
.begin
	bsr	_geta4			;get A4
	lea	__H1_end,a1
	lea	__H2_org,a2
	cmp.l	a1,a2			;check if BSS and DATA together
	bne	start			;no, don't have to clear
	move.w	#((__H2_end-__H2_org)/4)-1,d1
	bmi	start			;skip if no bss
	move.l	#0,d2
loop
	move.l	d2,(a1)+		;clear out memory
	dbra	d1,loop

start
	move.l	sp,__savsp		;save stack pointer
	move.l	4,a6			;get Exec's library base pointer
	move.l	a6,_SysBase		;put where we can get it
	movem.l	d0/a0,-(sp)		;save CLI command parameters

	btst.b	#4,$129(a6)		;check for 68881 flag in AttnFlags
	beq	1$			;skip if not
	lea	2$,a5
	jsr	-30(a6)			;do it in supervisor mode
	bra	1$
2$
	clr.l	-(sp)
	frestore (sp)+			;reset the ffp stuff
	rte				;and return
1$

	lea	dos_name,a1		;get name of dos library
	jsr	-408(a6)		;open the library any version
	move.l	d0,_DOSBase		;set it up
	bne	3$			;skip if okay

  	move.l  #$38007,d7		;AG_OpenLib | AO_DOSLib
	jsr     -108(a6)		;Alert
	bra	4$
3$
	jsr	__main			;call the startup stuff
4$
	add.w	#8,sp			;pop args
	rts				;and return

dos_name:
	dc.b	'dos.library',0

	public	_geta4
_geta4:
	far	data
	lea	__H1_org+32766,a4
	rts

	public	__main,__H0_org

	dseg

	public	_SysBase,__savsp,_DOSBase
	public	__H1_org,__H1_end,__H2_org,__H2_end

dospkt.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include <exec/memory.h>
#include <libraries/dosextens.h>

long
dos_packet(port, type, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
struct MsgPort *port;
long type, arg1, arg2, arg3, arg4, arg5, arg6, arg7;
{
	register struct StandardPacket *sp;
	register struct MsgPort *rp, *CreatePort();
	void *AllocMem();
	long ret;

	if ((rp = CreatePort(0L, 0L)) == 0)
		return(0);
	if ((sp = AllocMem((long)sizeof(*sp), MEMF_PUBLIC|MEMF_CLEAR)) == 0) {
		DeletePort(rp);
		return(0);
	}
	sp->sp_Msg.mn_Node.ln_Name = (char *)&sp->sp_Pkt;
	sp->sp_Pkt.dp_Link = &sp->sp_Msg;
	sp->sp_Pkt.dp_Port = rp;
	sp->sp_Pkt.dp_Type = type;
	sp->sp_Pkt.dp_Arg1 = arg1;
	sp->sp_Pkt.dp_Arg2 = arg2;
	sp->sp_Pkt.dp_Arg3 = arg3;
	sp->sp_Pkt.dp_Arg4 = arg4;
	sp->sp_Pkt.dp_Arg5 = arg5;
	sp->sp_Pkt.dp_Arg6 = arg6;
	sp->sp_Pkt.dp_Arg7 = arg7;
	PutMsg(port, &sp->sp_Msg);
	WaitPort(rp);
	GetMsg(rp);
	ret = sp->sp_Pkt.dp_Res1;
	FreeMem(sp, (long)sizeof(*sp));
	DeletePort(rp);
	return(ret);
}

exec.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include	<exec/types.h>
#include	<exec/tasks.h>
#include	<libraries/dosextens.h>

execl(file, arg0)
char *file, *arg0;
{
	return(execv(file, &arg0));
}

execv(arg, argv)
char *arg, **argv;
{
	return(execit(arg, argv, 0));
}

execlp(file, arg0)
char *file, *arg0;
{
	return(execvp(file, &arg0));
}

execvp(arg, argv)
char *arg, **argv;
{
	return(execit(arg, argv, 1));
}

struct ex {
	long	dosbase;
	BPTR	seglist;
	long *	stack;
	long	savret;
	BPTR *	cliseg;
	BPTR *	cliseg2;
	long	cmdlen;
	char *	cmdstr;
	char *	cmdnam;
	long	dirlck;
};

static
execit(arg, argv, flg)
char *arg, **argv;
{
	register struct ex *ex;
	register struct CommandLineInterface *cli;
	struct Process *pp;
	struct Process *FindTask();
	register char **ap, *cp;
	register int i;
	int len;
	long *l, *k, *bcpl, sav, flck;
	union {
		long *lp;
		long ll;
	} dir;
	extern char _exec, _exectab;
	extern long DOSBase;
	extern long _savsp;
	long CurrentDir(), Lock(), DupLock(), OpenLibrary();
	void *AllocMem();

	for (len=0,ap=argv+1;*ap;ap++,len+=strlen(*ap)+1)
		;
	pp = FindTask(0L);
	cli = (struct CommandLineInterface *)((long)pp->pr_CLI <<  2);
	if (cli == 0)
		return(-1);
	if ((sav = OpenLibrary("dos.library", 33L)) == 0) {

		bcpl = (long *)*((long *)*((long *)*((long *)*((long *)
										_savsp+2)+1)-3)-3)+107;
		if (*bcpl != cli->cli_Module)
			return(-1);
	}
	else {
		CloseLibrary(sav);
		bcpl = 0;
	}
	len += &_exectab-&_exec + 1 + 8 + sizeof(struct ex);
	len = (len + 3) & ~3;
	if ((k = AllocMem((long)len, 0L)) == 0)
		return(-1);
	movmem(&_exec, k, len);
	*k = len;
	ex = (struct ex *)((char *)k + (long)(&_exectab-&_exec));

	dir.ll = 0;
	if (flck = Lock(arg, ACCESS_READ))
		goto found;
	if (flg == 0)
		return(-1);
	dir.lp = (long *) cli->cli_CommandDir;
	while (dir.lp) {
		dir.ll <<= 2;
		sav = CurrentDir(dir.lp[1]);
		flck = Lock(arg, ACCESS_READ);
		CurrentDir(sav);
		if (flck) {
			dir.ll = DupLock(dir.lp[1]);
			goto found;
		}
		dir.ll = *dir.lp;
	}
	dir.ll = Lock("c:", ACCESS_READ);
	sav = CurrentDir(dir.lp);
	flck = Lock(arg, ACCESS_READ);
	CurrentDir(sav);
	if (flck)
		goto found;
	return(-1);
found:
	UnLock(flck);

	cp = (char *)(ex + 1);
	strcpy(cp, " ");
	for (ap=argv+1;*ap;ap++) {
		strcat(cp, *ap);
		strcat(cp, " ");
	}
	strcat(cp, "\r");

	ex->dosbase = DOSBase;
	ex->seglist = cli->cli_Module;
	ex->stack = (long *)_savsp+1;
	l = ex->stack - 1;
	ex->savret = *l;
	*l = (long)(k + 2);
	ex->cliseg = &cli->cli_Module;
	ex->cliseg2 = bcpl;
	ex->cmdlen = strlen(cp);
	ex->cmdstr = cp;
	cp = (char *)((long)cli->cli_CommandName<<2);
	*cp++ = strlen(arg);
	strcpy(cp, arg);
	ex->cmdnam = cp;
	ex->dirlck = dir.ll;
	exit(0);
}

#asm
_LVOCurrentDir	equ	-126
_LVOUnLock		equ	-90
_LVOUnLoadSeg	equ	-156
_LVOLoadSeg		equ	-150
_LVOExit		equ	-144

	public	__exec
__exec
	dc.l	0					;len of segment
	dc.l	0					;pointer to next segment
	move.l	stack(pc),sp		;get a good stack location
	move.l	savret(pc),-(sp)	;set up for real return
	move.l	seglist(pc),d1		;get seglist of current program
	move.l	dosbase(pc),a6		;get pointer to library
	jsr		_LVOUnLoadSeg(a6)	;unload the program

	pea		-1					;push a -1 for no dir
	move.l	dirlck(pc),d1		;get lock for program directory
	beq		1$					;must be in current dir
	jsr		_LVOCurrentDir(a6)	;set to current dir
	move.l	d0,(sp)				;save old current dir
1$
	move.l	cmdnam(pc),d1		;get pointer to cmd name
	jsr		_LVOLoadSeg(a6)		;load the new program
	move.l	(sp)+,d1			;get current dir back
	bmi		3$					;if high bit set on BPTR, no dir
	move.l	d0,-(sp)			;save segment list
	jsr		_LVOCurrentDir(a6)	;put back the right current dir
	move.l	d0,d1
	jsr		_LVOUnLock(a6)		;get rid of the Lock on the program dir
	move.l	(sp)+,d0			;get back segment list
3$
	tst.l	d0					;check on load
	bne		2$					;skip if loaded okay
	jsr		fixlist				;add us to the seglist
	move.l	#1,d0				;do exit(1)
	move.l	stack(pc),a1		;get stack ptr
	sub.w	#4,a1				;point at return address
	move.l	a1,sp				;set up stack
	rts							;and return to real caller

2$
	jsr		fixlist
	move.l	cmdlen(pc),d0		;set up for program call
	move.l	cmdstr(pc),a0
	jmp		4(a1)				;and transfer to program

fixlist
	move.l	cliseg(pc),a0		;pointer to CLI segment list
	move.l	d0,(a0)				;point CLI at new segment
fix1
	move.l	(a0),d0				;get chain to next
	beq		fix2				;at end, break out of loop
	lsl.l	#2,d0				;convert BPTR to real address
	move.l	d0,a0				;copy to a0
	bra		fix1				;and loop
fix2
	lea		__exec+4(pc),a2		;pointer to this segment
	move.l	a2,d0				;copy to d0
	lsr.l	#2,d0				;convert to BPTR
	move.l	d0,(a0)				;add us to list
	move.l	cliseg(pc),a0		;pointer to CLI segment list
	move.l	(a0),d0				;first hunk
	move.l	cliseg2(pc),a1		;pointer to BCPL copy of segment list
	move.l	a1,d1				;check for zero
	beq		1$					;skip if 1.2
	move.l	d0,(a1)				;point at new segment
1$
	lsl.l	#2,d0				;convert BPTR to real address
	move.l	d0,a1				;save in a1 for jump
	rts

	public	__exectab
__exectab:

dosbase	dc.l	0				;address of DOS library
seglist	dc.l	0				;BPTR to seglist of current program
stack	dc.l	0				;Ptr to return address
savret	dc.l	0				;place to save real return address
cliseg	dc.l	0				;pointer to cli seg list
cliseg2	dc.l	0				;pointer to bcpl seg list
cmdlen	dc.l	0				;length of command string
cmdstr	dc.l	0				;pointer to command string
cmdnam	dc.l	0				;pointer to program name
dirlck	dc.l	0				;lock on program directory if non-zero

#endasm

exit.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

int (*cls_)();

exit(code)
{
	if (cls_)
		(*cls_)();
	_exit(code);
}

fexec.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include	<exec/types.h>
#include	<exec/tasks.h>
#include	<libraries/dosextens.h>

static long ret_val;

wait()
{
	return(ret_val);
}

fexecl(file, arg0)
char *file, *arg0;
{
	return(fexecv(file, &arg0));
}

fexecv(cmd, argv)
char *cmd, **argv;
{
	register struct CommandLineInterface *cli;
	struct Process *pp;
	struct Process *FindTask();
	struct FileHandle *fhp;
	APTR sav_ret;
	register char **ap, *cp, *arg;
	int i;
	long len, seg, sav, stksiz;
	char buf[40];
	long *bcpl;
	union {
		long *lp;
		long ll;
	} l, stk;
	long oldcin, oldcout;
	long doexec(), LoadSeg(), CurrentDir(), OpenLibrary();
	void *AllocMem();
	extern long _savsp;

	pp = FindTask(0L);
	if ((cli = (struct CommandLineInterface *)((long)pp->pr_CLI << 2)) == 0) {
		return(-1);
	}
	if ((sav = OpenLibrary("dos.library", 33L)) == 0) {

		bcpl = (long *)*((long *)*((long *)*((long *)*((long *)
										_savsp+2)+1)-3)-3)+107;
		if (*bcpl != cli->cli_Module)
			return(-1);
	}
	else {
		CloseLibrary(sav);
		bcpl = 0;
	}
	if (seg = LoadSeg(cmd))
		goto found;
	l.lp = (long *) cli->cli_CommandDir;
	while (l.ll) {
		l.ll <<= 2;
		sav = CurrentDir(l.lp[1]);
		seg = LoadSeg(cmd);
		CurrentDir(sav);
		if (seg)
			goto found;
		l.ll = *l.lp;
	}
	strcpy(buf, "c:");
	strcat(buf, cmd);
	if (seg = LoadSeg(buf))
		goto found;
	return(-1);
found:
	stksiz = 4 * cli->cli_DefaultStack;
	if ((stk.lp = AllocMem(stksiz+8, 0L)) == 0) {
		UnLoadSeg(seg);
		return(-1);
	}
	for (len=1,ap=argv+1;*ap;ap++)
		len += strlen(*ap) + 1;
	if ((cp = arg = AllocMem(len, 0L)) == 0) {
		UnLoadSeg(seg);
		FreeMem(stk.lp, stksiz+8);
		return(-1);
	}
	*stk.lp = stksiz + 8;
	stk.ll += stksiz;
	stk.lp[0] = stksiz;
	stk.lp[1] = ((long *)_savsp)[2];
	sav_ret = pp->pr_ReturnAddr;
	pp->pr_ReturnAddr = (APTR) stk.lp;

	sav = cli->cli_Module;
	cli->cli_Module = seg;
	if (bcpl)
		*bcpl = seg;

	for (ap=argv+1;*ap;ap++) {
		strcpy(cp, *ap);
		strcat(cp, " ");
		cp += strlen(cp);
	}
	arg[len-1] = '\n';

	cp = (char *)((long)cli->cli_CommandName << 2);
	movmem(cp, buf, 40);
	strcpy(cp+1, cmd);
	cp[0] = strlen(cmd);

	fhp = (struct FileHandle *) (pp->pr_CIS << 2);
	strncpy(fhp->fh_Buf<<2, arg, (int)(len < 200?len:199));
	fhp->fh_Pos = 0;
	fhp->fh_End = len < 200?len:199;
	oldcin = pp->pr_CIS;
	oldcout = pp->pr_COS;   	

	ret_val = doexec(len, stksiz, stksiz+8, len, arg, (seg+1)<<2, stk.ll);

	pp->pr_CIS =  oldcin;
	pp->pr_COS =  oldcout;   	
	fhp->fh_Pos = fhp->fh_End;
	UnLoadSeg(cli->cli_Module);
	pp->pr_ReturnAddr = sav_ret;
	cli->cli_Module = sav;
	if (bcpl)
		*bcpl = sav;
	FreeMem(arg, len);
	movmem(buf, cp, 40);
	return(0);
}

static long
doexec()
{
#asm
	movem.l	d3-d7/a2-a5,-(sp)		;save registers
	lea		savsp(pc),a0
	move.l	sp,(a0)					;save our sp
	movem.l	8(a5),d0/d2/d3/d4/a0/a4/a7	;load params
	move.l	4(sp),a3				;get old sp from CLI
	movem.l	4(a3),a1/a2/a5/a6		;get BCPL environment
	move.l	d0,12(a1)				;set length
	move.l	a0,d1					;copy to dreg
	lsr.l	#2,d1					;convert to BPTR
	move.l	d1,8(a1)				;set ptr
	move.l	a0,d1					;copy to d1 as well
	jsr		(a4)					;call new program
	movem.l	(sp)+,d2/d3				;get stk siz and old sp
	move.l	sp,a1					;save current sp
	move.l	savsp(pc),sp			;get back our sp
	movem.l	(sp)+,d3-d7/a2-a5		;get back registers
	move.l	d0,-(sp)				;save return code
	sub.l	d2,a1					;back up a bit
	sub.l	#8,a1					;back up over header
	move.l	(a1),d0					;get size to free
	move.l	4,a6					;get ExecBase
	jsr		-210(a6)				;free the memory
	move.l	(sp)+,d0				;get the return code
#endasm
}

#asm
savsp:
	dc.l	0
#endasm
freeseg.a68
;:ts=8
; Copyright (C) 1986,1987 by Manx Software Systems, Inc.
;

_LVOFreeMem	equ	-210

	far	code
	far	data
	public	_freeseg
_freeseg:
	movem.l	a2/a3/a6,-(sp)
	move.l	16(sp),a0		;get address of segment Jmptab entry
	cmp.w	#$4ef9,(a0)		;check if valid entry
	bne	done			;no, skip
	move.l	__H0_org#+12,a2		;get address of segment data table
	lea	__H1_org#,a1		;get address of data segment
	sub.l	a1,a0			;calculate the segment Jmptab offset
	move.l	(a2)+,d1		;get number of entries
	asl.l	#3,d1			;multiply by size of entry
	move.l	a2,a3			;copy start of table
	add.l	d1,a3			;point past last entry

1$:
	sub.l	#8,a3			;back up to next entry
	cmp.l	a2,a3			;check if at beginning
	blt	done			;didn't find it
	tst.l	(a3)			;check file offset
	beq	1$			;if zero, null entry, skip
	cmp.w	4(a3),a0		;check against table entry
	blt	1$			;not in this segment

;------ found it, now do the work.

	move.l	a3,d3			;copy to d1
	sub.l	a2,d3			;get offset
	lsr.l	#3,d3			;divide by eight to get offset
	add.l	#1,d3			;add 1 to get real segment number

	move.l	#__H1_org#,a1		;get data hunk
	add.w	4(a3),a1		;add in table offset
	add.w	6(a3),a2		;add hunk data offset
loop:
	move.w	(a2)+,d0		;get hunk number
	beq	done			;all done
	move.l	__H0_org#+16,a0		;BPTR to Hunk table
	add.l	a0,a0			;double it
	add.l	a0,a0			;and again
	add.l	d0,d0			;double hunk number
	add.l	d0,d0			;and again
	move.l	(a0,d0),d1		;get hunk BPTR
	clr.l	(a0,d0)			;clear it out

2$
	move.l	(a0),a0			;skip to next
	add.l	a0,a0			;convert to ptr
	add.l	a0,a0
	cmp.l	(a0),d1			;is it the one we want?
	bne	2$			;no, keep going
	add.l	d1,d1			;convert to pointer
	add.l	d1,d1

	movem.l	d1/a1,-(sp)		;save regs
	move.l	d1,a1			;copy to a1
	move.l	(a1),(a0)		;remove from chain
	sub.l	#4,a1			;back up to size
	move.l	(a1),d0			;get size
	move.l	4,a6			;get ExecBase
	jsr	_LVOFreeMem(a6)		;free the memory
	movem.l	(sp)+,d1/a1

	add.l	#4,d1			;point to real hunk start

	move.w	(a2)+,d2		;get number of symbols
	beq	loop			;no symbols, skip

1$:
	move.w	6(a1),a0		;get offset for bsr
	move.l	2(a1),d0		;get offset
	sub.l	d1,d0			;unrelocate it
	move.w	#$6100,(a1)+		;bsr pc-relative
	move.w	a0,(a1)+		;put bsr offset
	move.l	d0,(a1)+		;put it back
	move.b	d3,-4(a1)		;save the segment number
	sub.w	#1,d2			;dec number of symbols
	bne	1$			;go back

	bra	loop			;do next hunk

done:
	movem.l	(sp)+,a2/a3/a6		;restore regs
	rts				;and do the real call

getenv.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

struct lib {
	struct lib *succ, *prev;
	char type, priority;
	char *name;
	short flags;
	short negsize;
	short possize;
	short version;
	short revision;
	char *ID;
	long sum;
	short opencnt;
	char *env;
};

char *
getenv(str)
char *str;
{
	register struct lib *lp, *_OpenLibrary();
	register char *cp, *np, *malloc(), *index();
	register int i;

	if ((lp = _OpenLibrary("environment", 0L)) == 0)
		return(0);
	_CloseLibrary(lp);
	Forbid();
	cp = lp->env;
	i = strlen(str);
	while (*cp) {
		if ((np = index(cp, '=')) && np-cp == i && strncmp(cp, str, i) == 0) {
			cp = malloc(strlen(++np)+1);
			strcpy(cp, np);
			Permit();
			return(cp);
		}
		cp += strlen(cp) + 1;
	}
	Permit();
	return(0);
}

heapmem.c
/* Copyright (C) 1987 by Manx Software Systems, Inc. */

unsigned long _Heapsize = 40 * 1024L;

typedef long size_t;
#define bump(p,i) ((l_t *)((char *)(p)+(i)))
#define ptrdiff(p1,p2) (unsigned long)((char *)(p1)-(char *)(p2))

typedef struct list {
	struct list *next;
} l_t;
static l_t first, *current;
static l_t *endmarker = &first, *restart = &first;
static size_t keep;

#define INUSE	1
#define inuse(p) (*(size_t *)(p)&INUSE)
#define markblk(p) (*(size_t *)(p) |= INUSE)
#define unmark(p) (*(size_t *)(p) &= ~INUSE)
#define chain(p)	((l_t *)(*(size_t *)(p) & ~INUSE))

#define BLOCK	(512*sizeof(l_t))	/* # of bytes to ask sbrk for */

char *
realloc(area, size)
register char *area; unsigned size;
{
	register char *cp, *end;
	size_t osize;
	char *malloc();

	end = (char *)chain((l_t *)area-1);
	if ((osize = ptrdiff(end, area)) > size) {
		osize = size;
		end = (char *)bump(area, osize);
	}
	free(area);
	if ((cp = malloc(size)) != 0 && cp != area) {
		movmem(area, cp, osize);
		if ((char *)current >= area && (char *)current < end)
			*(size_t *)bump(cp, ptrdiff(current,area)) = keep;
	}
	return cp;
}

char *
lmalloc(size)
unsigned long size;
{
	register l_t *ptr, *temp, *lastfree;
	register size_t len;
	int times;
	char *sbrk();

	size = ((size+sizeof(l_t)*2-1)/sizeof(l_t))*sizeof(l_t);
	if (current == 0) {
		first.next = &first;
		markblk(&first);
		current = &first;
	}
	for (times = 0, lastfree = ptr = current ; ; ptr = chain(ptr)) {
		if (ptr == endmarker) {
			if (++times > 1) {
				len = BLOCK;
				if ((temp = (l_t *)sbrk((int)len)) == (l_t *)-1)
					return 0;
				if (temp != bump(ptr,sizeof(l_t))) {
					/* non-contiguous allocation */
					ptr->next = temp;
					markblk(ptr);
					len -= sizeof(l_t);
					ptr = temp;
				}
				temp = bump(ptr, len);
				ptr->next = temp;
				temp->next = &first;	/* new end marker */
				markblk(temp);
				endmarker = temp;
				if (chain(lastfree) == ptr)
					ptr = lastfree;
			}
		}
		if (inuse(ptr))
			continue;
		lastfree = ptr;
		while (!inuse(temp = chain(ptr)))
			ptr->next = temp->next;
		len = ptrdiff(temp,ptr);
		if (len >= size) {
			if (len > size) {
				ptr->next = bump(ptr, size);
				keep = *(size_t *)ptr->next;
				ptr->next->next = temp;
			}
			current = ptr->next;
			markblk(ptr);
			return (char *)(ptr+1);
		}
	}
}

char *
malloc(size)
unsigned size;
{
	return(lmalloc((unsigned long)size));
}

free(p)
char *p;
{
	register l_t *ptr;

	ptr = (l_t *)p - 1;
	if (!inuse(ptr))
		return -1;
	unmark(ptr);
	current = ptr;
	return 0;
}

#include	<exec/types.h>
#include	<exec/memory.h>

char *AllocMem();

static char *data;
static size_t amt;

static
cleanup()
{
	FreeMem(data, amt);
	data = 0;
}

char *
sbrk(size)
unsigned size;
{
	register char *cp;
	static char *ptr;
	extern int (*_cln)();

	if (size&1)
		size++;
	if (data == 0) {
		_cln = cleanup;
		amt = _Heapsize;
		while ((data = AllocMem(amt, 0L)) == 0)
			amt -= 1024;
		ptr = data;
	}
	if (ptr+size >= data+amt)
		return(-1);
	cp = ptr;
	ptr += size;
	return(cp);
}

intman.a68
;:ts=8
; Copyright (C) 1986,1987 by Manx Software Systems, Inc.
;

	far	code

	public	_geta4

	public	_int_start
_int_start
	move.l	(sp)+,a0
	movem.l	d2/d3/a4,-(sp)
	move.l	a0,-(sp)
	jmp	_geta4

	public	_int_end
_int_end
	move.l	(sp)+,a0
	movem.l	(sp)+,d2/d3/a4
	jmp	(a0)

ioctl.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include <sgtty.h>
#include <fcntl.h>
#include <errno.h>
#include <libraries/dosextens.h>

ioctl(fd, cmd, arg)
struct sgttyb *arg;
{
	register struct _dev *refp;
	register struct FileHandle *fhp;
	register struct Process *mp, *FindTask();

	Chk_Abort();
	refp = _devtab + fd;
	if (fd < 0 || fd >= _numdev || refp->fd == 0) {
		errno = EBADF;
		return(-1);
	}
	switch (cmd) {
	case TIOCGETP:
		arg->sg_flags = (refp->mode&O_CONRAW)?RAW:0;
		break;
	case TIOCSETP:
		mp = FindTask(0L);
		fhp = (struct FileHandle *)(refp->fd << 2);
		if (fhp->fh_Type == mp->pr_ConsoleTask) {
			for (refp=_devtab;refp<_devtab+_numdev;refp++) {
				fhp = (struct FileHandle *)(refp->fd << 2);
				if (fhp->fh_Type != mp->pr_ConsoleTask)
					continue;
				if (arg->sg_flags & RAW)
					refp->mode |= O_CONRAW;
				else
					refp->mode &= ~O_CONRAW;
			}
			dos_packet(mp->pr_ConsoleTask, 994L, arg->sg_flags&RAW?-1L:0L);
		}
		break;
	}
	return 0;
}

isatty.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include <fcntl.h>
#include <errno.h>

isatty(fd)
{
	long _IsInteractive();
	register struct _dev *refp;

	refp = _devtab + fd;
	if (fd < 0 || fd >= _numdev || refp->fd == 0) {
		errno = EBADF;
		return(-1);
	}
	return(_IsInteractive(_devtab[fd].fd) != 0);
}

lseek.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include	<errno.h>
#include	<fcntl.h>

long _IoErr(), _Seek();

long
lseek(fd, pos, mode)
register int fd;
long pos;
{
	register struct _dev *refp;
	register long err;

	Chk_Abort();
	refp = _devtab + fd;
	if (fd < 0 || fd >= _numdev || refp->fd == 0) {
		errno = EBADF;
		return(-1);
	}
	if ((err = _Seek(refp->fd, pos, (long)mode-1)) == -1) {
		errno = _IoErr();
		return(-1);
	}
	return(_Seek(refp->fd, 0L, 0L));
}

makefile
.c.o:
	cc +b +x3,5 $(CFLAGS) -o $@ $*.c
.c.o32:
	cc +bl +x3,5 $(CFLAGS) -o $@ $*.c
.c.l:
	cc +bcd +x3,5 $(CFLAGS) -o $@ $*.c
.c.l32:
	cc +bp +x3,5 $(CFLAGS) -o $@ $*.c

.a68.o:
	as -o $@ $*.a68
.a68.o32:
	as -o $@ $*.a68
.a68.l:
	as -cdo $@ $*.a68
.a68.l32:
	as -cdo $@ $*.a68

C=_main.o abort.o access.o crt0.o exec.o\
	fexec.o open.o close.o read.o write.o\
	lseek.o exit.o getenv.o ioctl.o isatty.o\
	setenv.o rename.o stat.o stkchk.o stkover.o\
	unlink.o segload.o freeseg.o dospkt.o setcon.o\
	syserr.o _exit.o chkabort.o intman.o cliparse.o\
	wbparse.o vars.o heapmem.o detach.o signal.o
C32=_main.o32 abort.o32 access.o32 crt0.o32 exec.o32\
	fexec.o32 open.o32 close.o32 read.o32 write.o32\
	lseek.o32 exit.o32 getenv.o32 ioctl.o32 isatty.o32\
	rename.o32 setenv.o32 stat.o32 stkchk.o32 stkover.o32\
	unlink.o32 segload.o32 freeseg.o32 dospkt.o32 setcon.o32\
	syserr.o32 _exit.o32 chkabort.o32 intman.o32 cliparse.o32\
	wbparse.o32 vars.o32 heapmem.o32 detach.o32 signal.o32
LC=_main.l abort.l access.l crt0.l exec.l\
	fexec.l open.l close.l read.l write.l\
	lseek.l exit.l getenv.l ioctl.l isatty.l\
	setenv.l rename.l stat.l stkchk.l stkover.l\
	unlink.l segload.l freeseg.l dospkt.l setcon.l\
	syserr.l _exit.l chkabort.l intman.l cliparse.l\
	wbparse.l vars.l heapmem.l detach.l signal.l
LC32=_main.l32 abort.l32 access.l32 crt0.l32 exec.l32\
	fexec.l32 open.l32 close.l32 read.l32 write.l32\
	lseek.l32 exit.l32 getenv.l32 ioctl.l32 isatty.l32\
	rename.l32 setenv.l32 stat.l32 stkchk.l32 stkover.l32\
	unlink.l32 segload.l32 freeseg.l32 dospkt.l32 setcon.l32\
	syserr.l32 _exit.l32 chkabort.l32 intman.l32 cliparse.l32\
	wbparse.l32 vars.l32 heapmem.l32 detach.l32 signal.l32

all:	16 32 l16 l32

16:		$(C)

32:		$(C32)

l16:	$(LC)

l32:	$(LC32)

detach.o:	_main.c
	cc +b +x3,5 $(CFLAGS) -DDETACH -o $@ _main.c

detach.o32:	_main.c
	cc +bl +x3,5 $(CFLAGS) -DDETACH -o $@ _main.c

detach.l:	_main.c
	cc +bcd +x3,5 $(CFLAGS) -DDETACH -o $@ _main.c

detach.l32:	_main.c
	cc +bp +x3,5 $(CFLAGS) -DDETACH -o $@ _main.c

open.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include	<errno.h>
#include	<fcntl.h>
#include	<libraries/dos.h>

creat(name, mode)
char *name;
{
	return(open(name, O_WRONLY|O_TRUNC|O_CREAT, mode));
}

open(name, flag, mode)
register char *name;
{
	register struct _dev *refp;
	register int fd, err;
	register long file, lib;
	long _Open(), _IoErr(), _DeleteFile(), _Lock(), _OpenLibrary();

	Chk_Abort();
	refp = _devtab;
	for (fd=0;fd<_numdev;fd++)
		if (refp[fd].fd == 0)
			goto found;
	err = EMFILE;
	goto xerr;
found:
	if (flag & O_TRUNC) {
		if (file = _Lock(name, ACCESS_WRITE)) {
			_UnLock(file);
			if (_DeleteFile(name) == 0 && (err=_IoErr()) != 205)
				goto xerr;
		}
	}
	file = _Open(name, MODE_OLDFILE);
	if (file == 0) {
		if ((flag&O_CREAT) == 0) {
			err = ENOENT;
			goto xerr;
		}
		if ((file = _Open(name, MODE_NEWFILE)) == 0) {
			err = _IoErr();
			goto xerr;
		}
	/*
	 *	this kludge is necessary till the RAM: driver gets fixed
	 */
	 	if (lib = _OpenLibrary("dos.library", 33L))
			_CloseLibrary(lib);
		else {
			_Write(file, "", 1L);
			_Seek(file, 0L, -1L);
		}
	}
	else if ((flag&(O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) {
		_Close(file);
		err = EEXIST;
xerr:
		errno = err;
		return(-1);
	}
	refp[fd].fd = file;
	refp[fd].mode = flag;
	if (flag & O_APPEND)
		_Seek(file, 0L, OFFSET_END);
	return(fd);
}

read.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include	<errno.h>
#include	<fcntl.h>

long _IoErr(), _Read();

read(fd, buf, len)
char *buf;
register int fd;
unsigned int len;
{
	register struct _dev *refp;
	register long err;

	Chk_Abort();
	refp = _devtab + fd;
	if (fd < 0 || fd >= _numdev || refp->fd == 0) {
		errno = EBADF;
		return(-1);
	}
	if ((refp->mode & 3) == O_WRONLY) {
		errno = EINVAL;
		return(-1);
	}
	if ((err = _Read(refp->fd, buf, (long)len)) == -1) {
		errno = _IoErr();
		return(-1);
	}
	return((int)err);
}

rename.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include	<errno.h>
#include	<libraries/dos.h>

long _Rename(), _IoErr(), _Lock(), _UnLock();

rename(old, new)
char *old, *new;
{
	long l;

	if (l = _Lock(new, ACCESS_READ)) {
		_UnLock(l);
		errno = EEXIST;
		return(-1);
	}
	if (_Rename(old, new) == 0) {
		errno = _IoErr();
		return(-1);
	}
	return(0);
}

segload.a68
;:ts=8
; Copyright (C) 1986,1987 by Manx Software Systems, Inc.
;

_LVOAlert	equ	-108
_LVOOpenLibrary	equ	-552
_LVOSeek	equ	-66
_LVOLoadSeg	equ	-150
AN_BadOverlay   equ	$0700000C

;
;	Register usage:
;			D3 - segment number
;			D2 - number of symbols in hunk
;			D1 - hunk address

;			A4 - pointer to loader data table
;			A3 - pointer to segment data table
;			A2 - pointer to hunk data table
;			A1 - pointer to segment Jmptab
;

	far	code
	far	data
	public	_segload		;this entry is for forcing
_segload				; a segment in from C
	movem.l	d0-d2/a0-a4,-(sp)
	move.l	36(sp),a1		;get table address
	cmp.w	#$4ef9,(a1)		;see if already loaded
	beq	done			;yes, so return
	add.w	#4,a1			;no, skip to seg #
	bra	entry2			;and go to common code

	public	.segload
.segload
	movem.l	d0-d2/a0-a4,-(sp)
	move.l	32(sp),a0		;get return address
	move.l	a0,a1			;make a copy
	sub.w	#4,a0			;back up to bsr
	move.l	a0,32(sp)		;and put back for rts
entry2:
	move.l	#0,d0			;clear high bits
	move.b	(a1),d0			;get segment number
	move.l	#__H0_org#+8,a4		;point to loader table
	move.l	4(a4),a3		;point to segment data table
	add.w	#4,a3			;skip count
	move.l	a3,a2			;save table start
	sub.w	#1,d0			;sub 1 since 0 never in table
	asl.w	#3,d0			;multiply by 8
	add.w	d0,a3			;point to segment data

;------- get the segment into memory

	jsr	loadseg			;load the segment

;------- adjust the segment jump table

	move.l	#__H1_org#,a1		;get data hunk
	add.w	4(a3),a1		;add in table offset
	add.w	6(a3),a2		;add hunk data offset
loop:
	move.w	(a2)+,d0		;get hunk number
	beq	done			;all done
	move.w	(a2)+,d2		;get number of symbols
	beq	loop			;no symbols, skip
	move.l	8(a4),a0		;BPTR to Hunk table
	add.l	a0,a0			;double it
	add.l	a0,a0			;and again
	add.l	d0,d0			;double hunk number
	add.l	d0,d0			;and again
	move.l	(a0,d0),d1		;get hunk BPTR
	add.l	#1,d1			;point at real start
	add.l	d1,d1			;convert to real pointer
	add.l	d1,d1			;and again

1$:
	move.w	2(a1),a0		;save bsr offset for unloadseg
	clr.b	4(a1)			;clear high byte
	move.l	4(a1),d0		;get offset
	add.l	d1,d0			;relocate it
	move.w	#$4ef9,(a1)+		;jmp absolute long
	move.l	d0,(a1)+		;put it back
	move.w	a0,(a1)+		;save bsr offset
	sub.w	#1,d2			;dec number of symbols
	bne	1$			;go back

	bra	loop			;do next hunk

done:
	movem.l	(sp)+,d0-d2/a0-a4	;restore regs
	rts				;and do the real call

loadseg:
	movem.l	d2/d3/a6,-(sp)		;save our regs
	lea	libname(pc),a1		;get dos library name
	move.l	#0,d0			;any version
	move.l	4,a6			;get ExecBase
	jsr	_LVOOpenLibrary(a6)	;open the library
	move.l	d0,a6			;set up for later call
	move.l	d0,d2			;save it
	beq	overr			;whoops, guru time!

retry:
	move.l	(a4),d1			;get program file descriptor
	move.l	(a3),d2			;get file offset
	move.l	#-1,d3			;offset from beginning
	jsr	_LVOSeek(a6)		;seek to file pos
	tst.l	d1			;check return
	bmi	retry			;error, try again
	move.l	#0,d1			;special param for LoadSeg
	move.l	8(a4),d2		;hunk tab BPTR
	move.l	(a4),d3			;program file descriptor
	jsr	_LVOLoadSeg(a6)		;load this segment
	tst.l	d1			;check return
	beq	retry			;error, keep trying

	move.l	8(a4),a0		;get BPTR to hunk table
1$:
	add.l	a0,a0
	add.l	a0,a0			;convert to pointer
2$:
	tst.l	(a0)			;check for end
	beq	3$			;found it
	move.l	(a0),a0			;get next hunk
	bra	1$
3$:
	move.l	d0,(a0)			;add new list to seglist

	movem.l	(sp)+,d2/d3/a6		;restore registers
	rts				;and return

overr:
	move.l	#AN_BadOverlay,d7	;bad overlay alert message
	move.l	4,a6
	jsr	_LVOAlert(a6)		;call alert code
	rts

libname:
	dc.b	'dos.library',0

	end
setcon.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include <libraries/dosextens.h>

set_raw()
{
	struct Process *mp, *FindTask();

	mp = FindTask(0L);     
    if (mp->pr_Task.tc_Node.ln_Type == NT_PROCESS && mp->pr_ConsoleTask)
		dos_packet(mp->pr_ConsoleTask, 994L, -1L);
}

set_con()
{
	struct Process *mp, *FindTask();

	mp = FindTask(0L);     
    if (mp->pr_Task.tc_Node.ln_Type == NT_PROCESS && mp->pr_ConsoleTask)
		dos_packet(mp->pr_ConsoleTask, 994L, 0L);
}

setenv.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include <stdio.h>
#include <exec/memory.h>

void *_AllocMem();

#define ENVINC (128L)

static struct lib {
	struct lib *succ, *prev;
	char type, priority;
	char *name;
	short flags;
	short negsize;
	short possize;
	short version;
	short revision;
	char *ID;
	long sum;
	short opencnt;
	char *env;
	long size;
};

setenv(name, buf)
char *name, *buf;
{
	register char *cp, *ep;
	register char *arg;
	register struct lib *lp, *_OpenLibrary(), *make_env();
	register long offset;
	char *strchr();

	if ((lp = _OpenLibrary("environment", 0L)) == 0)
		lp = make_env();
	else
		_CloseLibrary(lp);
	Forbid();
	cp = arg = lp->env;
	while (*cp) {
		ep = strchr(cp, '=');
		*ep = 0;
		if (strcmp(cp, name) == 0) {
			ep += strlen(ep+1) + 2;
			movmem(ep, cp, (int)(lp->size-(ep-arg)));
			break;
		}
		*ep = '=';
		cp += strlen(cp) + 1;
	}
	if (strlen(buf)) {
		for (cp=arg;*cp;cp += strlen(cp)+1)
			;
		offset = cp - arg;
		while (offset+strlen(buf)+strlen(name)+3 >= lp->size) {
			if ((cp = _AllocMem(lp->size+ENVINC, MEMF_PUBLIC | MEMF_CLEAR)) == 0) {
				puts("Not enough memory to grow environment.");
				exit(1);
			}
			movmem(arg, cp, (int)lp->size);
			_FreeMem(arg, lp->size);
			lp->env = arg = cp;
			lp->size += ENVINC;
		}
		cp = arg + offset;
		strcpy(cp, name);
		strcat(cp, "=");
		strcat(cp, buf);
		cp += strlen(cp) + 1;
		*cp = 0;
	}
	Permit();
}

static struct envlib {
	short vectors[12];
	struct lib lp;
	short code[4];
	char name[12];
} envinit = {
	{ 0x6044, 0x0000, 0x0000, 0x603e, 0x0000, 0x0000,
		0x6038, 0x0000, 0x0000, 0x602e, 0x0000, 0x0000, },
	{ 0, 0, 0, 0, 0, 0, 24, 42 + 8 + 12 + 2, 1, 1, 0, 0, 1, 0, ENVINC },
	{ 0x200e, 0x4e75, 0x7000, 0x4e75 },
	"environment" };

static struct lib *
make_env()
{
	register struct lib *lp;
	register struct envlib *elp;
	register char *p;

	elp = _AllocMem((long)sizeof(struct envlib), MEMF_PUBLIC);
	p = _AllocMem(ENVINC, MEMF_PUBLIC | MEMF_CLEAR);
	if (elp==NULL || p==NULL) {
		puts("Couldn't make environment library!");
		if (elp)
			FreeMem(elp, (long)sizeof(struct envlib));
		if (p)
			FreeMem(p, ENVINC);
		exit(1);
	}
	movmem(&envinit, elp, sizeof(struct envlib));
	lp = &elp->lp;
	lp->name = elp->name;
	lp->env = p;
	AddLibrary(lp);
	return(lp);
}

signal.c
/* Copyright Manx Software Systems, Inc. 1987.  All rights reserved */
#include <signal.h>
#include <errno.h>

void (*_sigfuns[_NUMSIG])();
static char setup;

void (*signal(sig, func))()
register int sig;
void (*func)();
{
	register void (*retval)();

	if (!setup) {
		_sig_setup();
		setup = 1;
	}
	if ((sig -= _FSTSIG) < 0 || sig >= _NUMSIG) {
		errno = EINVAL;
		return SIG_ERR;
	}
	retval = _sigfuns[sig];
	_sigfuns[sig] = func;
	return retval;
}

int raise(sig)
int sig;
{
	register void (*handler)();

	if (sig < _FSTSIG || sig >= _FSTSIG+_NUMSIG)
		return -1;
	if ((handler = _sigfuns[sig - _FSTSIG]) == SIG_DFL)
		_exit(255);
	if (handler != SIG_IGN)
		(*handler)(sig);
	return 0;
}

#include <exec/types.h>
#include <exec/tasks.h>
#include <exec/execbase.h>

extern int _trapintercept;
extern void *_oldtrap, **_trapaddr;

_sig_setup()
{
	struct Task *tp, *_FindTask();
	extern struct ExecBase *SysBase;

	tp = _FindTask(0L);
	_trapaddr = (void *)&tp->tc_TrapCode;
	_oldtrap= tp->tc_TrapCode;
	tp->tc_TrapCode = (APTR)&_trapintercept;
	if (SysBase->AttnFlags & AFF_68881) {
#asm
		mc68881

		fmove.l	FPCR,d0
		or.w	#$1400,d0
		fmove.l	d0,FPCR
#endasm
	}
}

_traphand(code)
long code;
{
	if (code == 5 || code == 7 || code == 50 || code == 53)
		raise(SIGFPE);
	else if (code == 2 || code == 3)
		raise(SIGSEGV);
	else if (code == 4)
		raise(SIGILL);
}

#asm
	far	data
	public	_geta4

	public	__trapintercept
__trapintercept:
	movem.l	d0/a0,-(sp)		;need a data register
	move.l	8(sp),d0		;get trap number
	cmp.w	#50,d0			;is it 881 div0?
	beq		2$				;yes, do it
	cmp.w	#53,d0			;is it 881 overflow
	beq		2$				;yes, do it
	cmp.w	#7,d0			;is it in right range?
	bgt		1$				;no, do default
	cmp.w	#6,d0			;is it CHK
	bne		2$				;no, go handle it
1$:
	movem.l	(sp)+,d0/a0		;else restore d0/a0 contents
	move.l	__oldtrap,-(sp)	;get regular handler
	rts						;jump to it

2$:
	move.l	usp,a0			;get user stack pointer
	move.l	14(sp),-(a0)	;save old pc
	move.w	10(sp),-(a0)	;save old sr
	movem.l	d0-d7/a0-a6,-(a0)	;save old registers
	movem.l	(sp)+,d1/d2		;restore d0/a0
	move.l	d1,(a0)			;set d0
	move.l	d2,32(a0)		;set a0
	move.l	d0,-(a0)		;pass trap number on stack
	lea		3$,a1			;get return in case they want to continue
	move.l	a1,-(a0)		;set return address
	move.l	a0,usp			;set new user stack pointer
	lea		__traphand,a0	;get trap handler
	move.l	a0,6(sp)		;modify rte address
	addq.l	#4,sp			;remove trap #
	jsr		_geta4			;set up A4 register
	rte						;go and do the handler

3$:
	add.w	#4,sp			;pop arg
	movem.l	(sp)+,d0-d7/a0-a6	;restore old registers
	move.w	(sp)+,ccr		;restore old condition codes
	rts						;and continue where we left off

#endasm

stat.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include	<stat.h>
#include	<exec/exec.h>
#include	<libraries/dosextens.h>

stat(name, buf)
char *name;
struct stat *buf;
{
	long l, _Lock();
	struct FileInfoBlock *fp, *AllocMem();

	if ((l=_Lock(name, ACCESS_READ)) == 0)
		return(-1);
	if ((fp = AllocMem((long)sizeof *fp, 0L)) == 0) {
		_UnLock(l);
		return(-1);
	}
	_Examine(l, fp);
	buf->st_attr = fp->fib_Protection;
	buf->st_mtime = fp->fib_Date.ds_Days * 24 * 60 * 60 +
					fp->fib_Date.ds_Minute * 60 +
					fp->fib_Date.ds_Tick/TICKS_PER_SECOND;
	buf->st_size = fp->fib_Size;
	_FreeMem(fp, (long) sizeof *fp);
	_UnLock(l);
	return(0);
}

stkchk.a68
;:ts=8
; Copyright (C) 1986,1987 by Manx Software Systems, Inc.
;

	public	__stkbase
	public	__stkover

	public	__stkchk
__stkchk:
	move.l	__stkbase,a0
	cmp.l	a7,a0
	bge	crunch
	cmp.l	#'MANX',(a0)
	bne	crunch
	rts
crunch:
	jmp	__stkover

stkover.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

/*
 *	This routine is called whenever the stack checking code detects an
 *	overrun of the bottom of the stack.
 */

_stkover()
{
	long _Output();

#asm
	move.l	__savsp#,d0
	sub.l	#16,d0
	move.l	d0,a7
#endasm
	_Write(_Output(), "Stack overflow!!\n", 17L);
	_exit(100);
}

syserr.c
/* Copyright (C) 1987 by Manx Software Systems */

char *sys_errlist[] = {
	"No error",
	"File not found",
	"Bad file handle",
	"Insufficient memory",
	"File exists",
	"Invalid function number",
	"Too many open files",
	"Not a console device",
	"Invalid access code",
	/* math library */
	"Result too large",
	"Argument out of domain"
};

int sys_nerr =  sizeof (sys_errlist) / sizeof (char *);

unlink.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include	<errno.h>

long _DeleteFile(), _IoErr();

unlink(name)
char *name;
{
	if (_DeleteFile(name) == 0) {
		errno = _IoErr();
		return(-1);
	}
	return(0);
}
vars.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include <fcntl.h>
#include <workbench/startup.h>

void *SysBase, *DOSBase, *MathBase, *MathTransBase;
void *MathIeeeDoubBasBase, *MathIeeeDoubTransBase;

long _savsp, _stkbase;

int errno;
int Enable_Abort;

int _argc, _arg_len;
char **_argv, *_arg_lin;
struct WBStartup *WBenchMsg;

struct _dev *_devtab;
short _numdev = 20;

char *_detach_name = 0;			/* for DETACHED programs */
long _detach_curdir = 0;

void *_oldtrap, **_trapaddr;	/* for signal() cleanup */

wbparse.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

/*
 *	This routine is called from the _main() routine and is used to
 *	open a window for standard I/O to use. The window is actually
 *	defined by setting the ToolType, "WINDOW", to the desired window
 *	specification. If this is not required, this routine may be
 *	replaced by a stub in the users main program. Note that even if
 *	this code is called by _main(), if the WINDOW tool type is not
 *	defined, there will be no window.
 *
 *	EXAMPLE:	WINDOW=CON:0/0/640/200/Test Window
 */

#include <libraries/dosextens.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <workbench/icon.h>

void *IconBase;

_wb_parse(pp, wbm)
register struct Process *pp;
struct WBStartup *wbm;
{
	register char *cp;
	register struct DiskObject *dop;
	register struct FileHandle *fhp;
	register long wind;
	void *_OpenLibrary();
	long _Open();

	if ((IconBase = _OpenLibrary("icon.library", 0L)) == 0)
		return;
	if ((dop = GetDiskObject(wbm->sm_ArgList->wa_Name)) == 0)
		goto closeit;
	if (cp = FindToolType(dop->do_ToolTypes, "WINDOW")) {
		if (wind = _Open(cp, MODE_OLDFILE)) {
			fhp = (struct FileHandle *) (wind << 2);
			pp->pr_ConsoleTask = (APTR) fhp->fh_Type;
			pp->pr_CIS = (BPTR)wind;
			pp->pr_COS = (BPTR)_Open("*", MODE_OLDFILE);
		}
	}
	FreeDiskObject(dop);
closeit:
	CloseLibrary(IconBase);
	IconBase = 0;
}

write.c
/* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */

#include	<errno.h>
#include	<fcntl.h>

long _IoErr(), _Write();

write(fd, buf, len)
char *buf;
register int fd;
unsigned int len;
{
	register struct _dev *refp;
	register long err;

	Chk_Abort();
	refp = _devtab + fd;
	if (fd < 0 || fd >= _numdev || refp->fd == 0) {
		errno = EBADF;
		return(-1);
	}
	if ((refp->mode & 3) == O_RDONLY) {
		errno = EINVAL;
		return(-1);
	}
	if ((err = _Write(refp->fd, buf, (long)len)) == -1) {
		errno = _IoErr();
		return(-1);
	}
	return((int)err);
}

