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

#include <fcntl.h>
#include <functions.h>

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

void (*_cln)(void);

void
_exit(int 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
	movem.l	a5/a6,-(sp)
	move.l	4,a6				;get ExecBase
	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$
	move.l	(sp)+,a5/a6
#endasm
	}
	if (WBenchMsg == 0) {
		if (_arg_lin) {
			FreeMem(_arg_lin, (long)_arg_len);
			FreeMem(_argv, (long)(_argc+1)*sizeof(*_argv));
		}
	}
	else {
		Forbid();
		ReplyMsg((struct Message *)WBenchMsg);
	}
	CloseLibrary(DOSBase);
	{
#asm
		move.l	%%ret,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 <stdlib.h>
#include <string.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;

void _cli_parse(struct Process *pp, long alen, char *aptr);
void _wb_parse(struct Process *pp, struct WBStartup *WBenchMsg);
int main(int argc, char **argv);
#ifdef DETACH
static void do_detach(long *alen, char **aptr);
#endif

void
_main(long alen, char *aptr)
{
	register struct Process *pp;

#ifdef 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 = (struct Process *)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 = (struct WBStartup *)GetMsg(&pp->pr_MsgPort);
		if (WBenchMsg->sm_ArgList) {
			CurrentDir((struct FileLock *)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("*", (long)MODE_OLDFILE);
	exit(main(_argc, _argv));
}

#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(long *alen, char **aptr)
{
	register struct Process *pp;
	register unsigned short c;
	register char *cp;
	register struct CommandLineInterface *cli;
	register long l;
	long *lp, *sav;
	struct MemList *mm;
	struct Library *savlib;

	pp = (struct Process *)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 ((savlib = 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(savlib);
			lp = 0;
		}
		if (lp)
			*lp = 0;
		if (_stack == 0)
			_stack = cli->cli_DefaultStack * 4;
		if (_BackGroundIO)
			_Backstdout = (BPTR)Open("*", (long)MODE_OLDFILE);
		_alen = *alen;
		_aptr = AllocMem(_alen, 0L);
		memmove(_aptr, *aptr, (size_t)_alen);
		cp = (char *)((long)cli->cli_CommandName << 2);
		_detach_name = AllocMem((long)cp[0]+1, 0L);
		memmove(_detach_name, cp, (size_t)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(&pp->pr_Task.tc_MemEntry, &mm->ml_Node);

		CurrentDir(_detach_curdir);

		pp->pr_COS = _Backstdout;

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

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

#include <stdlib.h>
#include <functions.h>

void
_abort(void)
{
	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>
#include <functions.h>

#asm
	xdef __access
__access:
	jmp	_access
#endasm

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

	if ((l = Lock(filename, (long)ACCESS_READ)) == 0) {
		errno = ENOENT;
		return(-1);
	}
	switch(mode) {
	case 2:			/* write */
		UnLock(l);
		if ((l = Lock(filename, (long)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);
}

chdir.c
#include <libraries/dos.h>
#include <functions.h>

/*------------------------------------------------------------------*/
/*	chdir(path): make path the current directory. Return Ok/Not */
/*------------------------------------------------------------------*/

int
chdir(char *path)
{
	register struct FileLock *lock;
	struct FileLock *oldLock;

	if (*path == 0)
		return(0);
	if ((lock = Lock(path, (long)ACCESS_READ)) == 0)
		return((int)IoErr());
	if (oldLock = CurrentDir(lock))
		UnLock(oldLock);
	return(0);
}

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

#include <functions.h>

void _abort(void);

long
Chk_Abort(void)
{
	long x;
	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>
#include <string.h>
#include <functions.h>

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

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

	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, (size_t)c);
	strcpy(_arg_lin+c, " ");
	strncat(_arg_lin, aptr, (size_t)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>
#include <functions.h>

#asm
	xdef __close
__close:
	jmp	_close
#endasm

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

	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
	move.l  sp,a5			; set up frame ptr for sdb
	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$
	move.l  sp,a5			; set up frame ptr for sdb
	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>
#include <stdarg.h>
#include <functions.h>

long
dos_packet(struct MsgPort *port, long type, ...)
{
	register struct StandardPacket *sp;
	register struct MsgPort *rp;
	register va_list arg;
	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;
	va_start(arg, type);
	sp->sp_Pkt.dp_Arg1 = va_arg(arg, long);
	sp->sp_Pkt.dp_Arg2 = va_arg(arg, long);
	sp->sp_Pkt.dp_Arg3 = va_arg(arg, long);
	sp->sp_Pkt.dp_Arg4 = va_arg(arg, long);
	sp->sp_Pkt.dp_Arg5 = va_arg(arg, long);
	sp->sp_Pkt.dp_Arg6 = va_arg(arg, long);
	sp->sp_Pkt.dp_Arg7 = va_arg(arg, long);
	va_end(arg);
	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>
#include <functions.h>
#include <stdlib.h>
#include <string.h>

static int execit(char *arg, char **argv, int flg);
int execv(char *arg, char **argv);
int execvp(char *arg, char **argv);

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

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

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

int
execvp(char *arg, char **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 int
isfile(struct FileLock *l)
{
	struct FileInfoBlock *fp;
	int ret = 0;

	if ((fp = AllocMem((long)sizeof *fp, 0L)) == 0)
		return(-1);
	Examine(l, fp);
	if (fp->fib_DirEntryType < 0)
		ret = 1;
	FreeMem(fp, (long) sizeof *fp);
	return(ret);
}

static int
execit(char *arg, char **argv, int flg)
{
	register struct ex *ex;
	register struct CommandLineInterface *cli;
	struct Process *pp;
	register char **ap, *cp;
	size_t len;
	long *l, *k, *bcpl;
	struct FileLock *flck, *savdir;
	struct Library *savlib;
	union {
		long *lp;
		long ll;
		struct FileLock *fl;
		struct FileLock **flp;
	} dir;
	extern char _exec, _exectab;
	extern long DOSBase;
	extern long _savsp;

	for (len=0,ap=argv+1;*ap;ap++)
		len += strlen(*ap) + 1;
	pp = (struct Process *)FindTask(0);
	cli = (struct CommandLineInterface *)((long)pp->pr_CLI <<  2);
	if (cli == 0)
		return(-1);
	if ((savlib = 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(savlib);
		bcpl = 0;
	}
	len += &_exectab-&_exec + 1 + 8 + sizeof(struct ex);
	len = (len + 3) & ~3;
	if ((k = AllocMem((long)len, 0L)) == 0)
		return(-1);
	memmove(k, &_exec, len);
	*k = len;
	ex = (struct ex *)((char *)k + (long)(&_exectab-&_exec));

	dir.ll = 0;
	if ((flck = Lock(arg, (long)ACCESS_READ)) && isfile(flck))
		goto found;
	if (flg == 0)
		return(-1);
	dir.lp = (long *) cli->cli_CommandDir;
	while (dir.lp) {
		dir.ll <<= 2;
		savdir = CurrentDir(dir.flp[1]);
		flck = Lock(arg, (long)ACCESS_READ);
		CurrentDir(savdir);
		if (flck && isfile(flck)) {
			dir.fl = DupLock(dir.flp[1]);
			goto found;
		}
		dir.ll = *dir.lp;
	}
	dir.fl = Lock("c:", (long)ACCESS_READ);
	savdir = CurrentDir(dir.fl);
	flck = Lock(arg, (long)ACCESS_READ);
	CurrentDir(savdir);
	if (flck && isfile(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);
	return(0);
}

#asm
_LVOCurrentDir	equ	-126
_LVOUnLock		equ	-90
_LVOUnLoadSeg	equ	-156
_LVOLoadSeg		equ	-150
_LVOExit		equ	-144
_LVOPermit		equ	-138
_LVOForbid		equ	-132

	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	d0,-(sp)			;save our segment list
	move.l	4,a6				;get ExecBase
	jsr		_LVOForbid(a6)		;only one walker at a time
	move.l	(sp)+,d0
	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,-(sp)			;save
	jsr		_LVOPermit(a6)		;turn on multi-tasking again
	move.l	(sp)+,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

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

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

static long ret_val;
long _doexec(long len, ...);
int fexecv(char *cmd, char **argv);

int
wait(void)
{
	return(ret_val);
}

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

int
fexecv(char *cmd, char **argv)
{
	register struct CommandLineInterface *cli;
	struct Process *pp;
	struct FileHandle *fhp;
	APTR sav_ret;
	register char **ap, *cp, *arg;
	long len, seg, stksiz, sav;
	struct Library *savlib;
	struct FileLock *savdir;
	char buf[40];
	long *bcpl;
	union {
		long *lp;
		long ll;
		struct FileLock *fl;
		struct FileLock **flp;
	} l, stk;
	long oldcin, oldcout;
	extern long _savsp;

	pp = (struct Process *)FindTask(0);
	if ((cli = (struct CommandLineInterface *)((long)pp->pr_CLI << 2)) == 0) {
		return(-1);
	}
	if ((savlib = 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(savlib);
		bcpl = 0;
	}
	if (seg = LoadSeg(cmd))
		goto found;
	l.lp = (long *) cli->cli_CommandDir;
	while (l.ll) {
		l.ll <<= 2;
		savdir = CurrentDir(l.flp[1]);
		seg = LoadSeg(cmd);
		CurrentDir(savdir);
		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);
	memmove(buf, cp, (size_t)40);
	strcpy(cp+1, cmd);
	cp[0] = strlen(cmd);

	fhp = (struct FileHandle *) (pp->pr_CIS << 2);
	strncpy((char *)(fhp->fh_Buf<<2), arg, (size_t)(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);			now done in doexec jgII 6/17/88 */
	pp->pr_ReturnAddr = sav_ret;
	cli->cli_Module = sav;
	if (bcpl)
		*bcpl = sav;
	FreeMem(arg, len);
	memmove(cp, buf, (size_t)40);
	return(0);
}

long _mysp;

#asm
	xref	_geta4
	xdef	__doexec
__doexec:
	link	a5,#0
	movem.l	d1/a6,-(sp)
	movem.l	d3-d7/a2-a5,-(sp)		;save registers
	move.l	sp,__mysp				;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

	move.l	4,a6					;get ExecBase
	move.l	d0,d6					;save return value
	lea		dos_name,a1				;get DOS name
	jsr		-408(a6)				;call OpenLibrary
	move.l	d0,d7					;save DOSBase
	move.l	$114(a6),a0				;get task
	move.l	$ac(a0),a0				;get cli
	add.l	a0,a0
	add.l	a0,a0					;convert from BPTR
	move.l	$3c(a0),d1				;get cli->cli_module
	move.l	d7,a6					;get DOSBase
	jsr		-156(a6)				;UnLoadseg
	move.l	a6,a1					;copy DOSBase for closing
	move.l	$4,a6					;get ExecBase
	jsr		-414(a6)				;CloseLibrary

	movem.l	(sp)+,d2/d3				;get stk siz and old sp
	move.l	sp,a1					;save current sp
	jsr		(_geta4).l				;get a4
	move.l	__mysp,sp				;get back our sp
	move.l	d6,d0					;get back return code
	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
	movem.l	(sp)+,d2/a6
	unlk	a5
	rts

	cseg
dos_name:
	dc.b	'dos.library',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	d2/d3/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)+,d2/d3/a2/a3/a6	;restore regs
	rts				;and do the real call

getcwd.c
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <exec/memory.h>
#include <stdlib.h>
#include <string.h>
#include <functions.h>

/*--------------------------------------------------------------
 *	getcwd: return the path name of the current directory	
 *--------------------------------------------------------------
 */

char *
getcwd(char *path, int size)
{
	char s1[ 108 ];
	char *name;
	register struct FileLock *locka, *lockb;
	register struct FileInfoBlock *fib;

	if (path == 0)
		if ((path = malloc((size_t)108)) == 0)
			return(0);

	fib = malloc(sizeof(struct FileInfoBlock));
	if (fib == 0)
		return(0);
	
	locka = Lock("", (long)ACCESS_READ);
	*path = s1[0] = 0;

	while (locka) {
		Examine(locka, fib);
		name = fib->fib_FileName;
		if (*name == 0)
			strcpy(path, "RAM"); /* Patch for Ram disk bug */
		else
			strcpy(path, name);
		lockb = ParentDir(locka);
		UnLock(locka);

		if (lockb == 0)
			strcat(path, ":");
		else if (s1[0] != 0)
			strcat( path, "/");
		strcat( path, s1 );
		strcpy( s1, path );
		locka = lockb;
	}

	free(fib);
	return(path);
}

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
	move.l	a4,-(sp)
	move.l	a0,-(sp)
	jmp	_geta4

	public	_int_end
_int_end
	move.l	(sp)+,a0
	move.l	(sp)+,a4
	jmp	(a0)

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

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

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

	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 = (struct Process *)FindTask(0L);
		fhp = (struct FileHandle *)((long)refp->fd << 2);
		if (fhp->fh_Type == (struct MsgPort *)mp->pr_ConsoleTask) {
			for (refp=_devtab;refp<_devtab+_numdev;refp++) {
				fhp = (struct FileHandle *)((long)refp->fd << 2);
				if (fhp->fh_Type != (struct MsgPort *)mp->pr_ConsoleTask)
					continue;
				if (arg->sg_flags & RAW)
					refp->mode |= O_CONRAW;
				else
					refp->mode &= ~O_CONRAW;
			}
			dos_packet((struct MsgPort *)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>
#include <functions.h>

#asm
	xdef __isatty
__isatty:
	jmp	_isatty
#endasm

int
isatty(int fd)
{
	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>
#include <functions.h>

#asm
	xdef __lseek
__lseek:
	jmp	_lseek
#endasm

long
lseek(register int fd, long pos, int mode)
{
	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
CC=qcc
AS=as
CFLAGS=
AFLAGS=
O=oss

.c.$O:
	$(CC) -o $@ $(CFLAGS) $*.c
.a68.$O:
	$(AS) -o $@ $(AFLAGS) $*.a68

CLIB=\
	_main.$O abort.$O access.$O crt0.$O exec.$O\
	fexec.$O open.$O close.$O read.$O write.$O\
	lseek.$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\
	_exit.$O chkabort.$O intman.$O cliparse.$O\
	wbparse.$O vars.$O detach.$O scdir.$O chdir.$O \
	getcwd.$O mkdir.$O

clib:	$(CLIB)

detach.$O:	_main.c
	$(CC) -o $@ -DDETACH $(CFLAGS) _main.c

mkdir.c
#include <libraries/dos.h>
#include <functions.h>

/*--------------------------------------------------------------*/
/*	mkdir(name): make a directory with the given name.	*/
/*--------------------------------------------------------------*/

int
mkdir(char *name)
{
	register struct FileLock *lock;

	if (*name == 0)
		return(0);
	if ((lock = CreateDir(name)) == 0)
		return((int)IoErr());
	else 
		UnLock(lock);
	return(0);
}

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

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

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

#asm
	xdef __open
__open:
	jmp	_open
#endasm

int
open(register const char *name, int flag, ...)
{
	register struct _dev *refp;
	register int fd, err;
	register struct FileLock *flock;
	register struct FileHandle *file;
	register struct Library *lib;

	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 (flock = Lock(name, (long)ACCESS_WRITE)) {
			UnLock(flock);
			if (DeleteFile(name) == 0 && (err=IoErr()) != 205)
				goto xerr;
		}
	}
	file = Open(name, (long)MODE_OLDFILE);
	if (file == 0) {
		if ((flag&O_CREAT) == 0) {
			err = ENOENT;
			goto xerr;
		}
		if ((file = Open(name, (long)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, (long)OFFSET_END);
	return(fd);
}

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

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

#asm
	xdef __read
__read:
	jmp	_read
#endasm

size_t
read(register int fd, void *buf, size_t 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(err);
}

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

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

int
_rename(char *old, char *new)
{
	struct FileLock *l;

	if (l = Lock(new, (long)ACCESS_READ)) {
		UnLock(l);
		errno = EEXIST;
		return(-1);
	}
	if (Rename(old, new) == 0) {
		errno = IoErr();
		return(-1);
	}
	return(0);
}

scdir.c
/* Copyright 1986,1987,1988 by Manx Software Systems, Inc.	*/

#include <exec/exec.h>
#include <libraries/dosextens.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <functions.h>

static struct FileInfoBlock *getdir(char *path);
static struct FileInfoBlock *getnxt(void);
static int jive(char *nam, char *pat);

char *
scdir(char *pat)
{
	register struct FileInfoBlock *fp;
	register char *cp;
	static int time = 0;
	static char name[80];
	static char path[40];
	static char patn[40];

	for (;;) {
		Chk_Abort();
		if (time == 0) {
			if (strchr(pat, '*') == 0 && strchr(pat, '?') == 0) {
				time = 2;
				return(pat);
			}
			time = 1;
			strcpy(name, pat);
			if (cp=strrchr(name, '/')) {
				if ((cp > name && *(cp-1) == '/') || cp == name)
					goto colon;
				*cp = 0;
				fp = getdir(name);
				*cp++ = '/';
				strcpy(patn, cp);
				*cp = 0;
				strcpy(path, name);
			}
			else if (cp=strrchr(name, ':')) {
colon:
				strcpy(patn, ++cp);
				*cp = 0;
				strcpy(path, name);
				fp = getdir(path);
			}
			else {
				strcpy(patn, name);
				*path = 0;
				fp = getdir(path);
			}
		}
		else if (time == 2) {
			time = 0;
			return(0);
		}
		else
			fp = getnxt();
		if (fp == 0) {
			time = 0;
			return(0);
		}
		if (jive(fp->fib_FileName, patn) == 0) {
			strcpy(name, path);
			strcat(name, fp->fib_FileName);
			break;
		}
	}
	return(name);
}

static struct fibsav {
	struct fibsav *next;
	struct FileInfoBlock fib;
} *chain, *ptr;

static struct FileInfoBlock *
getdir(char *path)
{
	register struct fibsav *fsp;
	register struct FileInfoBlock *fibp, *ret = 0;
	register struct FileLock *lock;

	while (fsp=chain) {
		fsp = chain;
		chain = chain->next;
		free(fsp);
	}
	if ((fibp = malloc(sizeof(struct FileInfoBlock))) == 0)
		return(0);
	if (lock = Lock(path, (long)ACCESS_READ)) {
		Examine(lock, fibp);
		if (fibp->fib_DirEntryType > 0) {
			while (ExNext(lock, fibp)) {
				if (fibp->fib_DirEntryType > 0)
					continue;
				if ((fsp = malloc(sizeof(struct fibsav))) == 0)
					break;
				fsp->fib = *fibp;
				fsp->next = chain;
				chain = fsp;
			}
			ptr = chain;
			ret = getnxt();
		}
		UnLock(lock);
	}
	free(fibp);
	return(ret);
}

static struct FileInfoBlock *
getnxt(void)
{
	register struct FileInfoBlock *fibp;

	if (ptr) {
		fibp = &ptr->fib;
		ptr = ptr->next;
		return(fibp);
	}
	while (ptr=chain) {
		chain = chain->next;
		free(ptr);
	}
	return(0);
}

static int
jive(char *nam, char *pat)
{
	register char *p;

	for (;;) {
		if (tolower((int)*nam) == tolower((int)*pat)) {
			if(*nam++ == '\0')
				return(0);
			pat++;
		}
		else if (*pat == '?' && *nam != 0) {
			nam++;
			pat++;
		}
		else
			break;
	}
	if (*pat != '*')
		return(1);
	while (*pat == '*') {
		if (*++pat == '\0')
			return(0);
	}
	
	for (p=nam+strlen(nam)-1;p>=nam;p--) {
		if (*p == *pat)
			if (jive(p,pat) == 0)
				return(0);
	}
	return(1);
}

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>
#include <fcntl.h>
#include <functions.h>

void
set_raw(void)
{
	struct Process *mp;

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

void
set_con(void)
{
	struct Process *mp;

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

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

#include <exec/memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <functions.h>

static struct lib *make_env(void);

#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;
};

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

	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;
			memmove(cp, ep, (size_t)(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);
			}
			memmove(cp, arg, (size_t)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(void)
{
	register struct lib *lp;
	register struct envlib *elp;
	register char *p;

	elp = AllocMem((long)sizeof(struct envlib), (long)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);
	}
	memmove(elp, &envinit, sizeof(struct envlib));
	lp = &elp->lp;
	lp->name = elp->name;
	lp->env = p;
	AddLibrary((struct Library *)lp);
	return(lp);
}

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

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

int
stat(char *name, struct stat *buf)
{
	struct FileLock *l;
	struct FileInfoBlock *fp;

	if ((l=Lock(name, (long)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	#'MANX',(a0)
	bne	crunch
	add.w	#128,a0
	cmp.l	a7,a0
	bge	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.
 */

#include <functions.h>

void _exit(int);

void
_stkover(void)
{
#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>
#include <functions.h>

#asm
	xdef __unlink
__unlink:
	jmp	_unlink
#endasm

int
unlink(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>
#include <functions.h>

void *IconBase;

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

	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, (long)MODE_OLDFILE)) {
			fhp = (struct FileHandle *) ((long)wind << 2);
			pp->pr_ConsoleTask = (APTR) fhp->fh_Type;
			pp->pr_CIS = (BPTR)wind;
			pp->pr_COS = (BPTR)Open("*", (long)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>
#include <functions.h>
#include <libraries/dos.h>

#asm
	xdef __write
__write:
	jmp	_write
#endasm

size_t
write(register int fd, void *buf, size_t 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 (refp->mode & O_APPEND)
		Seek(refp->fd, 0L, (long)OFFSET_END);
	if ((err = Write(refp->fd, buf, (long)len)) == -1) {
		errno = IoErr();
		return(-1);
	}
	return(err);
}

