[comp.sources.amiga] v90i132: ls 3.1 - UNIX-like ls utility, Part02/03

Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (04/11/90)

Submitted-by: kim@uts.amdahl.com (Kim E. DeVaughn)
Posting-number: Volume 90, Issue 132
Archive-name: unix/ls-3.1/part02

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 3)."
# Contents:  src/lssup.a
# Wrapped by tadguy@xanth on Tue Apr 10 17:22:48 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/lssup.a' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/lssup.a'\"
else
echo shar: Extracting \"'src/lssup.a'\" \(33907 characters\)
sed "s/^X//" >'src/lssup.a' <<'END_OF_FILE'
X* --------------------------------------------------------------------- *
X* LSSUP.A - Assembly support routines for ls.c
X* Written by Justin V. McCormick 89-07-24
X* --------------------------------------------------------------------- *
X	IFD	CAPE
X	CSYMFMT
X	BASEREG	B
X	SMALLOBJ
X	ADDSYM
X	OPTIMON
X	IDNT	"lssup.a"
X	ENDC
X
X
XSYS	MACRO	*
X	IFGT	NARG-2
X	FAIL	!!!
X	ENDC
X	IFEQ	NARG-2
X	MOVE.L	\2,a6
X	ENDC
X	JSR	LVO\1(a6)
X	ENDM
X
XXLVO	MACRO	*
X	XREF	LVO\1
X	ENDM
X
X; Equates
Xfib_DirEntryType EQU	$4 
Xfib_FileName	EQU	$8
Xfib_Size	EQU	$7C
Xfib_NumBlocks	EQU	$80
Xfib_DateStamp	EQU	$84
Xfib_SIZEOF	EQU	$104 
X
Xds_Days		EQU	$0
Xds_Minute	EQU	$4
Xds_Tick		EQU	$8
X
XLH_HEAD		EQU	$0
XLN_PRED		EQU	$4
XLN_SUCC		EQU	$0
X
Xfe_Node	equ	0
Xfe_Fib	equ	8
Xpr_ConsoleTask		EQU	$A4
X
XMEMF_CLEAR		EQU	$10000
Xsp_Msg			EQU	$0
Xsp_Pkt			EQU	$14
Xsp_SIZEOF		EQU	$44
Xdp_Link			EQU	$0
Xdp_Port			EQU	$4
Xdp_Arg1			EQU	$14
Xdp_Type			EQU	$8
XACTION_SCREEN_MODE	EQU	$3E2
XLN_NAME			EQU	$A
XLN_PRI			EQU	$9
XLN_TYPE			EQU	$8
XMP_FLAGS		EQU	$E
XMP_MSGLIST		EQU	$14
XMP_SIGBIT		EQU	$F
XMP_SIGTASK		EQU	$10
XMP_SIZE			EQU	$22
XNT_MSGPORT		EQU	$4
XPA_SIGNAL		EQU	$0
X
X* Library offsets
X	XLVO	AddPort
X	XLVO	AddTail
X	XLVO	AllocMem
X	XLVO	AllocSignal
X	XLVO	CopyMem
X	XLVO	Debug
X	XLVO	Examine
X	XLVO	FindTask
X	XLVO	FreeMem
X	XLVO	FreeSignal
X	XLVO	GetMsg
X	XLVO	Input
X	XLVO	Insert
X	XLVO	IoErr
X	XLVO	IsInteractive
X	XLVO	Output
X	XLVO	ParentDir
X	XLVO	PutMsg
X	XLVO	RawDoFmt
X	XLVO	Read
X	XLVO	RemPort
X	XLVO	WaitForChar
X	XLVO	WaitPort
X	XLVO	Write
X	XLVO	UnLock
X
X* External constants
X	XREF	@AllocFib
X	XREF	@CleanUp
X	XREF	@stpcpy
X	XREF	@strcat
X	XREF	@strlen
X	XREF	baddatestr
X	XREF	badtimestr
X	XREF	ColonStr
X	XREF	datepat
X	XREF	dayspermonth
X	XREF	DOSBase
X	XREF	gwbrstr
X	XREF	LSFlags
X	XREF	NoFindFmtStr
X	XREF	NoRAMMsg
X	XREF	RamNameStr
X	XREF	SlashStr
X	XREF	sortkey
X	XREF	timepat
X
X	SECTION	CODE
X* --------------------------------------------------------------------- *
X* VOID *myalloc (LONG)
X*   d0            d0
X* --------------------------------------------------------------------- *
X	XDEF	@myalloc
X@myalloc:
X	movem.l	d2/a6,-(sp)
X	addq.l	#4,d0			;Include sizeof(LONG)
X	move.l	d0,d2			;Copy to survive AllocMem
X	moveq	#0,d1			;MEMF_ANYTHING
X	SYS	AllocMem,4		;AllocMem(size + 4, 0L)
X	tst.l	d0			;Got it?
X	 beq.s	1$
X	movea.l	d0,a6			;Copy pointer
X	move.l	d2,(a6)+		;Stash size in first 4 bytes
X	move.l	a6,d0			;return final pointer in d0
X1$
X	movem.l	(sp)+,d2/a6
X	rts
X
X* --------------------------------------------------------------------- *
X* VOID myfree (VOID *)
X*               a0
X* --------------------------------------------------------------------- *
X	XDEF	@myfree
X@myfree:
X	move.l	a6,-(sp)
X
X	lea	-4(a0),a1		;Put in sys reg
X	move.l	(a1),d0			;d0 = size to free
X	SYS	FreeMem,4
X
X	movea.l	(sp)+,a6
X	rts
X
X* --------------------------------------------------------------------- *
X* void asprintf(wstr, formatstring, args)
X*   char *wstr;
X*   char *formatstring;
X*   char **args;
X* 
X* Synopsis: Given formatstring and args to format, formats output to wstr.
X* Similar to sprintf(), except doesn't handle floats.
X* --------------------------------------------------------------------- *
X	XDEF	asprintf
Xasprintf:
X	link	a5,#0
X	movem.l	d0-d2/a0-a3/a6,-(sp)	;Save everything we might clobber
X
X* Call format function to convert fmtstring and args to buffer on the stack
X	movea.l	12(a5),a0		;Grab format string
X	lea	16(a5),a1		;Grab EA of arguments
X	lea	kput1,a2		;Grab EA of output subroutine
X	movea.l	8(a5),a3		;Grab EA of dest workspace
X	SYS	RawDoFmt,4		;Format it into workspace
X
X	movem.l	(sp)+,d0-d2/a0-a3/a6	;Restore registers
X	unlk	a5			;And stack frame
X	rts
X
X* --------------------------------------------------------------------- *
X* RawDoFmt() output routine for xprintf, called for each formatted char.
X* Takes byte in d0 and puts in buffer pointed to by a3, then increments a3.
X* --------------------------------------------------------------------- *
X	XDEF	kput1
Xkput1:
X	move.b	d0,(a3)+
X	rts
X
X* --------------------------------------------------------------------- *
X* void GetWinBounds(width, height)
X*   long *width, *height;
X*          a0       a1
X* Find current console window, determine width and height
X* in terms of current font, update width and height VPARMS passed.
X* --------------------------------------------------------------------- *
Xheight	EQU	-4
Xwidth	EQU	-8
Xconid	EQU	-12
Xpacket	EQU	-16
Xrpport	EQU	-20
Xrpstr	EQU	-40
X
X	XDEF	@GetWinBounds
X@GetWinBounds:
X	link	a5,#-44
X	movem.l	d2-d4/a2/a6,-(sp)
X
X	move.l	a0,width(a5)		;Save width/height pointers on stack
X	move.l	a1,height(a5)
X
X	SYS	Input,DOSBase(a4)	;Grab Input filehandle
X	move.l	d0,d1
X	SYS	IsInteractive		;IsInteractive(Input())?
X	tst.l	d0
X	 beq.s	gwbnowbrep		;Nope, can't get a bounds report
X	SYS	Output
X	move.l	d0,d1
X	SYS	IsInteractive		;IsInteractive(Output())?
X	tst.l	d0
X	 beq.s	gwbnowbrep		;Nope, don't clutter output stream
X
X	suba.l	a1,a1
X	SYS	FindTask,4		;d0 = FindTask(0L), our process
X	movea.l	d0,a0			;Transfer to address reg
X	move.l	pr_ConsoleTask(a0),conid(a5) ;Save proc->pr_ConsoleTask
X	tst.l	conid(a5)		;Is there really a console there?
X	 bne.s	gwbgotcon		;Yep
X
Xgwbnowbrep:
X* Else we cannot get a window bounds report from this source
X	moveq	#23,d1			;return H=23
X	moveq	#77,d2			;       W=77
X	bra	gwbupdate
X
Xgwbgotcon:
X	moveq	#0,d4			;Clear our success status register
X
X	moveq	#0,d0
X	movea.l	d0,a0
X	jsr	CreatePort
X	move.l	d0,rpport(a5)		;rpport = CreatePort(0L, 0L)
X	 beq	gwbdone			;Oops, no signals or ram available!
X	moveq	#sp_SIZEOF,d0
X	jsr	@myalloc
X	move.l	d0,packet(a5)		;packet = AllocBlock(sizeof(*packet))
X	 beq	gwbfreeport		;Oops, no ram, free up port
X
X* Okay, we got our process id, reply port, and packet
X* Now toggle the console into raw mode
X	movea.l	rpport(a5),a2
X	movea.l	d0,a1
X	movea.l	conid(a5),a0
X	moveq	#1,d0
X	jsr	SetConsoleType		;SetConsoleType(1L, conid, packet, rpport)
X
X* Request a window bounds report
X	SYS	Output,DOSBase(a4)
X	move.l	d0,d1
X	moveq	#4,d3
X	lea	gwbrstr(a4),a0
X	move.l	a0,d2
X	SYS	Write,DOSBase(a4)	;Write(Output(), "\2330 q", 4L);
X	cmpi.l	#$0004,d0		;Did the console choke on it?
X	 bne	gwbsetcook		;hmmm, see if we can back out gracefully
X
X* Read the report string into stack buffer, if there is one
X	move.l	#10000,d2
X	SYS	Input
X	move.l	d0,d1
X	SYS	WaitForChar		;WaitForChar(Input(), 10000L) (.01 secs)
X	tst.l	d0			;Did we get the report?
X	 beq	gwbsetcook		;Nope, must not be a report coming
X	
X	SYS	Input
X	move.l	d0,d1
X	moveq	#16,d3			;Don't let it get longer than 16 characters
X	lea	rpstr(a5),a0		;Point to input string area
X	move.l	a0,d2
X	SYS	Read			;Read(Input(), rpstr, 16L)
X	move.l	d0,d4			;Save read length while we close shop
X
X* Turn the console back to cooked mode pronto to avoid cursor blink
Xgwbsetcook:
X	movea.l	rpport(a5),a2
X	movea.l	packet(a5),a1
X	movea.l	conid(a5),a0
X	moveq	#0,d0
X	jsr	SetConsoleType		;SetConsoleType(0L, conid, packet, rpport)
X
X* Release resources we borrowed
Xgwbfreepack:
X	move.l	packet(a5),d0		;Did we allocate a packet?
X	 beq.s	gwbfreeport		;nay, check for port to free
X	movea.l	d0,a0
X	jsr	@myfree			;Else FreeBlock(packet)
X
Xgwbfreeport:
X	move.l	rpport(a5),d0		;if (rpport)...
X	 beq	gwbdone			;nope
X	jsr	DeletePort		;Else DeletePort(rpport)
X
X* Finally, sanity check window bounds report string
X* d4 = length of report string according to Read()
X	cmpi.l	#9,d4			;Less than 8 characters returned?
X	 ble	gwbdone			;hmmm, phonky bounds report from DOS?
X	lea	rpstr(a5),a2		;a2 = rpstr
X	cmpi.b	#';',4(a2)		;Matches a typical report template?
X	 bne	gwbdone			;nope, got some weird junk back?
X	cmpi.b	#'r',-1(a2,d4.w)	;Last byte is 'r' for report?
X	 bne	gwbdone			;Nope, message fubar!
X
X* Parse the height and width variables from the field now
X* Our report format looks like this in hex:
X* 	9b 31 3b 31 3b y2 y1 3b x2 x1 20 72
X* Or in ascii:
X*	<0x9b>1;1;20;77 r
X* Which would indicate a width of 77 cols and a height of 20 rows for
X* the current console device
X*
X* REGS:	a2 points to beginning of 'r' terminated string
X
X	addq.w	#5,a2			;Point to first char of Y size
X	moveq	#0,d1			;Clear out work reg
X
X* Convert ascii rows value to LONG, update host data
X	move.b	(a2)+,d1		;Grab a Y
X	subi.w	#'0',d1			;Less ascii offset
X	cmpi.b	#';',(a2)		;Any more Y digits?
X	 beq.s	1$			;Nope
X	mulu	#10,d1			;Else shift by 10
X	add.b	(a2)+,d1		;Add least significant Y digit
X	subi.b	#'0',d1			;Less ascii offset
X	cmpi.b	#';',(a2)		;Any more Y digits?
X	 beq.s	1$			;Nope
X	mulu	#$000a,d1		;Else shift by 10
X	add.b	(a2)+,d1		;Add least significant Y digit
X	subi.b	#'0',d1			;Less ascii offset
X					;We'll assume screen height < 999 rows	
X1$
X* Convert ascii columns value to LONG, update host data
X	addq.w	#1,a2			;Move past the ';' separator
X	moveq	#0,d2			;Zap work reg
X	move.b	(a2)+,d2		;Grab msd of X
X	cmpi.b	#' ',d2			;Premature end?
X	 beq	gwbdone			;Huh, must be garbage - don't update VPARMS
X	cmpi.b	#';',d2			;Also a possible error
X	 beq	gwbdone
X	cmpi.b	#'r',d2			;And what about this?
X	 beq	gwbdone
X
X	subi.b	#'0',d2			;Okay, adjust ascii offset
X	cmpi.b	#' ',(a2)		;Hit end of report?
X	 beq.s	2$			;Yep
X	mulu	#$000a,d2		;Else shift by 10
X	add.b	(a2)+,d2		;Add next digit
X	subi.b	#'0',d2			;Ascii adjust
X	cmpi.b	#' ',(a2)		;Hit end of report?
X	 beq.s	2$			;Yep
X	mulu	#$000a,d2		;Else shift by 10
X	add.b	(a2),d2			;Add next digit
X	subi.b	#'0',d2			;Ascii adjust
X
X2$
Xgwbupdate:
X* Finally, update parameters by reference
X	movea.l	height(a5),a0		;Grab height VPARM
X	move.l	d1,(a0)			;*height = d1
X	movea.l	width(a5),a0		;Grab width VPARM
X	move.l	d2,(a0)			;*width = d2
X
Xgwbdone:
X	movem.l	(sp)+,d2-d4/a2/a6
X	unlk	a5
X	rts
X
X* --------------------------------------------------------------------- *
X* void __asm SetConsoleType(flag, id, packet, port)
X*   register __d0 long flag;
X*   register __a0 struct Process *id;
X*   register __a1 struct StandardPacket *packet;
X*   register __a2 struct MsgPort *port;
X*
X* Flag = 1L -- Raw mode
X*      = 0L -- Cooked mode
X* --------------------------------------------------------------------- *
X	XDEF	SetConsoleType
XSetConsoleType:
X	movem.l	a2/a3/a5/a6,-(sp)
X
X	movea.l	a0,a3			;Copy process pointer
X	movea.l	a1,a5			;Copy packet pointer
X	lea	sp_Pkt(a5),a0		;a0 = &packet->sp_Pkt
X	move.l	a0,sp_Msg+LN_NAME(a5)	;p->sp_Msg.mn_Node.ln_Name = &p->sp_Pkt
X	lea	sp_Msg(a5),a0		;a0 = &packet->sp_Msg
X	move.l	a0,sp_Pkt+dp_Link(a5)	;p->sp_Pkt.dp_Link = &p->sp_Msg
X	move.l	a2,sp_Pkt+dp_Port(a5)	;p->sp_Pkt.dp_Port = replyport
X	move.l	#ACTION_SCREEN_MODE,sp_Pkt+dp_Type(a5)	;Set function
X
X	tst.w	d0			;On or Off?
X	 beq	1$
X	move.l	#-1,sp_Pkt+dp_Arg1(a5)	;RAW ON
X	bra.s	2$
X1$
X	clr.l	sp_Pkt+dp_Arg1(a5)	;RAW OFF
X2$
X	movea.l	a3,a0
X	movea.l	a5,a1
X	SYS	PutMsg,4		;PutMsg(proc, packet)
X
X	movea.l	a2,a0
X	SYS	WaitPort		;WaitPort(port)
X	movea.l	a2,a0
X	SYS	GetMsg			;(void)GetMsg(port)
X
X	movem.l	(sp)+,a2/a3/a5/a6
X	rts
X
X* ------------------------------------------------------------------------- *
X* struct MsgPort *CreatePort(name, pri) (a0/d0)
X* ------------------------------------------------------------------------- *
X	XDEF	CreatePort
XCreatePort:
X	movem.l	d5/d7/a2/a5/a6,-(sp)
X
X	move.l	a0,a5			;Save Name
X	move.l	d0,d5			;Save Pri
X
X* Allocate a free signal, crap out if we can't
X	moveq	#-1,d0
X	SYS	AllocSignal,4
X	cmp.l	#-1,d0			;Did we get a signal?
X	 bne.s	cpgotsig		;Yep
X	moveq	#0,d0			;Otherwise return NULL
X	bra	cpdone
X
Xcpgotsig:
X	move.l	d0,d7			;Save our signal
X
X* Allocate memory for MsgPort
X	moveq	#MP_SIZE,d0		;Size of MsgPort
X	jsr	@myalloc		;Allocate it
X	tst.l	d0			;Did we get it?
X	 bne.s	cpgotport		;Yep
X
X	move.l	d7,d0			;Otherwise crap out, free signal
X	SYS	FreeSignal
X	moveq	#0,d0			;Return NULL
X	bra	cpdone
X
Xcpgotport:
X	move.l	d0,a2			;This is our new port!
X	move.l	a5,LN_NAME(a2)		;port->mp_Node.ln_Name = name
X	move.b	d5,LN_PRI(a2)		;port->mp_Node.ln_Pri = priority
X	move.b	#NT_MSGPORT,LN_TYPE(a2) ;port->mp_Node.ln_Type = NT_MSGPORT
X	move.b	#PA_SIGNAL,MP_FLAGS(a2) ;port->mp_Flags = PA_SIGNAL
X	move.b	d7,MP_SIGBIT(a2)	;port->mp_SIGBIT = sigBit
X	suba.l	a1,a1
X	SYS	FindTask
X	move.l	d0,MP_SIGTASK(a2)	;port->mp_SIGTASK = FindTask(0L)
X	
X	cmpa.l	#0,a5			;Is this a new name?
X	beq.s	cpnoname		;Nope, add it to the msg list
X
X	movea.l	a2,a1
X	SYS	AddPort			;Otherwise add this port
X	move.l	a2,d0			;Return port pointer
X	bra.s	cpdone
X
Xcpnoname:
X* Initialized New List head
X	lea	MP_MSGLIST(a2),a0 	;a0 = &port->mp_MsgList
X	move.l	a0,(a0)			;list->lh_Head = list
X	addq.l	#4,(a0)			;list->lh_Head += 4L
X	clr.l	4(a0)			;list->lh_Tail = 0L
X	move.l	a0,8(a0)		;list->lh_TailPred = list
X	move.l	a2,d0			;Return port pointer
X
Xcpdone:
X	movem.l	(sp)+,d5/d7/a2/a5/a6
X	rts
X
X* ------------------------------------------------------------------------- *
X* DeletePort(port)(d0)
X* ------------------------------------------------------------------------- *
X	XDEF	DeletePort
XDeletePort:
X	movem.l	a5/a6,-(sp)
X
X	move.l	d0,a5
X	movea.l	$4,a6
X	tst.l	LN_NAME(a5)		;Is there a name?
X	beq.s	dpnoname
X	
X	move.l	d0,a1
X	SYS	RemPort			;RemPort(port)
X	
Xdpnoname:
X	move.b	#$ff,LN_TYPE(a5) 	;port->mp_Node.ln_Type = 0xff
X	move.l	#-1,MP_MSGLIST(a5) 	;port->mp_MsgList.lh_Head = -1L
X
X	moveq	#0,d0
X	move.b	MP_SIGBIT(a5),d0	;d0 = port->mp_SigBit
X	SYS	FreeSignal		;FreeSignal(d0)
X
X	movea.l	a5,a0
X	jsr	@myfree			;FreeBlock(port)
X
X	movem.l	(sp)+,a5/a6
X	rts
X
X* ------------------------------------------------------------------------
X* FibFileDate(fib_date, datestr, timestr)
X*               a0	  a1	   8(a5)
X*   struct DateStamp *fib_date;
X*   char *datestr, *timestr;
X*   Calculate date based on DateStamp structure and return a pointer
X* to the formatted date string.
X* ------------------------------------------------------------------------
X	XDEF	@FibFileDate
X@FibFileDate:
X	link	a5,#0
X	movem.l	d3-d7/a2-a3/a6,-(sp)
X
X	movea.l	a1,a3			;a3 = datestr, 8(a5) = timestr
X	movea.l	a0,a1			;Grab datestamp pointer
X	moveq	#78,d7			;Initial year = 1978
X
X	move.l	(a1),d5			;days = fib_date->ds_Days
X	 blt	ffdbaddate		;Hey! you can't be negative! Invalid date...
X
X* Determine what year it is
X	divu	#1461,d5
X	move.l	d5,d0			;Stash it
X	ext.l	d5
X	lsl.l	#2,d5
X	add.l	d5,d7			;year += (days / 1461) * 4
X
X* Count how many months into that year
Xffdgetmo:
X	swap	d0			;days %= 1461
X	move.w	d0,d5
X
X1$	tst.w	d5			;Out of days yet?
X	 beq.s	3$			;Yep, done here
X
X	move.w	#365,d6			;Else month_days = 365
X	move.w	d7,d0			;Grab year
X	andi.w	#3,d0			;if (year & 3) == 0 Leap year?
X	 bne.s	2$			;Nope
X	addq.w	#1,d6			;Otherwise bump month_days
X
X2$	cmp.w	d6,d5			;is day < month_days?
X	 blt.s	3$			;yep, done here
X	sub.w	d6,d5			;otherwise day -= month_days
X
X	addq.l	#1,d7			; year++
X	bra	1$
X3$
X
X* Count how many days into that month of that year
Xffdgetday:
X;for (i = 0, day++; i < 12; i++)
X	moveq	#0,d4			;current month = 0
X	moveq	#0,d6			;Zap hinybs
X	addq.w	#1,d5
X	lea	dayspermonth(a4),a0
X
X1$
X	move.b	0(a0,d4.w),d6		;month_days = dayspermonth[i]
X
X	cmpi.w	#1,d4			;if (i == 1 && (year & 3) == 0)
X	 bne.s	2$
X	move.w	d7,d0
X	andi.w	#3,d0
X	 bne.s	2$
X	addq.w	#1,d6			;month_days++
X
X2$	cmp.w	d6,d5			;if (day <= month_days)
X	 ble.s	4$			;Break out, found the right month
X
X	sub.w	d6,d5			;Else, day -= month_days
X
X	addq.w	#1,d4			;i++
X3$	cmpi.w	#12,d4			;Done all months yet?
X	 blt	1$			;Nope
X
X4$
Xffdprint:
X1$	cmpi.l	#99,d7			;while (year >= 100)
X	 ble.s	2$
X	subi.l	#100,d7			;year -= 100
X	bra	1$
X2$
X;asprintf(datestr, "%02d-%02d-%02d %02d:%02d:%02d", i + 1, day, year, hour, min, sec)
X	move.l	8(a1),d0		;sec = fib_date->ds_Tick / 50;
X	divu	#50,d0
X	ext.l	d0
X	move.l	d0,-(sp)		;Push secs
X	move.l	4(a1),d0		;min = fib_date->ds_Minute
X	move.l	d0,d1			;Clone it
X	divu	#60,d0
X	moveq	#0,d3
X	move.w	d0,d3			;hour = min / 60
X	mulu	#60,d0
X	sub.w	d0,d1			;min -= hour * 60
X	move.l	d1,-(sp)		;Push mins
X	move.l	d3,-(sp)		;Push hours
X	pea	timepat(a4)		;Push the format pattern
X	move.l	8(a5),-(sp)		;Push destination buffer, datestr
X	jsr	asprintf
X	lea	20(sp),sp
X
X	move.l	d5,-(sp)		;Push day
X	addq.w	#1,d4			;Push month (offset by 1!)
X	move.l	d4,-(sp)
X	move.l	d7,-(sp)		;Push year
X	pea	datepat(a4)		;Push the format pattern
X	move.l	a3,-(sp)		;Push destination buffer
X	jsr	asprintf	
X	lea	20(sp),sp
X
Xffddone:
X	movem.l	(sp)+,d3-d7/a2-a3/a6
X	unlk	a5
X	rts
X
Xffdbaddate:
X	lea	badtimestr(a4),a1	;stpcpy (timestr, "00:00:00");
X	movea.l	8(a5),a0
X	jsr	@stpcpy
X	lea	baddatestr(a4),a1	;stpcpy (datestr, "00-00-00");
X	movea.l	a3,a0
X	jsr	@stpcpy
X	bra	ffddone
X
X*----------------------------------------------------------------------
X* LONG iswild(name)
X*   char *name;
X*          a0
X* Search a string for wild characters, return 1 if found
X*----------------------------------------------------------------------
X	XDEF	@iswild
X@iswild:
X	moveq	#0,d0			;Clear out our character register
Xischk1:
X	move.b	(a0)+,d0		;Grab a char
X	 beq.s	iwdone			;Might be end of string?
X	cmpi.b	#'*',d0			;Is it *?
X	 beq.s	iswdone			;yep, is wild
X	cmpi.b	#'?',d0			;Is it a qmark
X	 bne.s	ischk1			;Nope, check next character
X
Xiswdone:
X	moveq	#1,d0
Xiwdone:
X	rts
X
X* ------------------------------------------------------------------------
X; Compare a wild card name with a normal name
X; LONG wildmatch (name, wild)
X;   char *name, *wild;
X;          a0     a1
X* ------------------------------------------------------------------------
X	XDEF	@wildmatch
X@wildmatch:
X	link	a5,#-64
X	movem.l	d3/a2-a3,-(sp)
X
X	movea.l	a0,a2			;Grab name
X	movea.l	a1,a3			;Grab pattern
X	lea	-64(a5),a0		;back[0][0]
X	lea	-60(a5),a1		;back[0][1]
X
X	moveq	#0,d3			;bi = 0
X
Xwmloop1:
X	tst.b	(a2)			;End of name?
X	 bne.s	wmnoteon
X	tst.b	(a3)			;End of pattern?
X	 beq	wmmatched		;Yep, we matched
X
Xwmnoteon:
X	cmpi.b	#'*',(a3)		;Is it a splat?
X	 bne.s	wmnotstar		;Nope, maybe '?'
X
X	cmpi.w	#64,d3			;Have we hit max expression depth?
X	 beq	wmnomatch		;Yep, ran out of room in recursion table
X
X;back[bi][0] = w
X	move.l	a3,0(a0,d3.w)		;Stash pointer to this '*' in table
X
X;back[bi][1] = n
X	move.l	a2,0(a1,d3.w)
X
X	addq.w	#8,d3			;++bi
X	addq.w	#1,a3			;++w
X	bra.s	wmloop1			;Check next
X
Xwmgoback:
X	subq.w	#8,d3			;--bi
X	move.l	a0,d0
Xwmback1:
X	tst.w	d3			;while (bi >= 0 && *back[bi][1] == '\x0')
X	 blt.s	wmbacked
X	movea.l	0(a1,d3.l),a0
X	tst.b	(a0)
X	 bne.s	wmbacked
X
X	subq.w	#8,d3			;--bi
X	bra.s	wmback1
X
Xwmbacked:
X	tst.w	d3			;if (bi < 0)
X	 blt.s	wmnomatch		;return (0)
X
X	movea.l	d0,a0
X	movea.l	0(a0,d3.w),a3		;w = back[bi][0] + 1
X	addq.w	#1,a3	
X
X	addq.l	#1,0(a1,d3.w)
X	movea.l	0(a1,d3.l),a2		;n = ++back[bi][1]
X
X	addq.w	#8,d3			;++bi
X	bra.s	wmloop1
X
Xwmnotstar:
X	cmpi.b	#'?',(a3)		;Is it '?'
X	 bne.s	wmnotqmark
X
X	tst.b	(a2)			;Reached end of string?
X	 bne.s	wmincpoint		;Nope, move on to next char
X
X	tst.w	d3			;Are we at top level of expression?
X	 beq.s	wmnomatch		;Yep, expression didn't match
X	bra.s	wmgoback		;Otherwise pop a level and try to match
X
Xwmnotqmark:
X	move.b	(a2),d0			;Grab a char from bstr
X	cmpi.b	#$40,d0			;less than @ character?
X	 bls.s	1$			;Yep
X	cmpi.b	#$5a,d0			;Greater than Z?
X	 bhi.s	1$			;Yep
X	addi.b	#$20,d0
X1$
X	move.b	(a3),d1			;Grab a char from bstr
X	cmpi.b	#$40,d1			;less than @ character?
X	 bls.s	2$			;Yep
X	cmpi.b	#$5a,d1			;Greater than Z?
X	 bhi.s	2$			;Yep
X	addi.b	#$20,d1
X2$
X	cmp.b	d0,d1			;*n = *w?
X	 beq.s	wmincpoint		;Yep, move on past
X
X	tst.w	d3			;Are we at top expression level?
X	 beq.s	wmnomatch		;Yep, they didn't match
X	bra.s	wmgoback		;Nope, process next part
X
Xwmincpoint:
X	tst.b	(a2)			;Done with name?
X	 beq.s	wmnamend		;Yep
X	addq.w	#1,a2			;Otherwise increment name pointer
X
Xwmnamend:
X	tst.b	(a3)			;End of pattern?
X	 beq.s	wmmatched		;Yep, we matched
X	addq.w	#1,a3			;Otherwise inc wild pointer, match next char
X	bra	wmloop1
X
Xwmmatched:
X	moveq	#1,d0
X	bra.s	wmdone
X
Xwmnomatch:
X	moveq	#0,d0
X
Xwmdone:
X	movem.l	(sp)+,d3/a2-a3
X	unlk	a5
X	rts
X
X* --------------------------------------------------------------------- *
X* BOOL CompFibs (keytype, a,   b)
X*		    d0   a0   a1
X*   LONG keytype;
X*   struct FileInfoBlock *a, *b;
X*
X* Used by SortFibs to determine precedence of Fibs.
X* keytype is one of 0, 1, or 2:
X*   0=alpha, 1=size, 2=date
X* --------------------------------------------------------------------- *
X	XDEF	@CompFibs
X@CompFibs:
X	movem.l	d2-d3/a2,-(sp)
X
X	move.l	d0,d2			;Stash keytype
X
X* Prioritize Dirs/Files?
X	move.l	LSFlags(a4),d3		;Grab flags
X
X	btst.l	#17,d3			;LSFlags & MIXFILEDIRS?
X	 bne.s	cftstsort		;Yep, don't bother comparing EntryTypes
X
X	move.l	fib_DirEntryType(a0),d0
X	cmp.l	fib_DirEntryType(a1),d0
X	 blt.s	1$			;a0 is < a1, (dir < file)
X	 beq.s	cftstsort		;a0 is == a1, try next test
X
X	moveq	#0,d0			;a0 is > a1, (file > dir)
X	bra.s	2$
X1$
X	moveq	#1,d0			;greater than, (dir < file)
X
X2$	btst.l	#16,d3			;LSFlags & FILESFIRST?
X	 beq	cfexit0			;Nope, default Dirs first
X	bchg.l	#0,d0			;Else d0 ^= 1, reverse sense
X	bra	cfexit0
X	
X* Both entries are the same type, now see about sorting them
Xcftstsort:
X	btst.l	#6,d3			;LSFlags & NOSORTFLAG set?
X	 bne	cffalse			;Yep, always AddTail to list
X	
X* Switch keytype
X	tst.w	d2			;Alphabetize?
X	 bne.s	cfnalpha		;Nope
X
X* Compare lexigraphically, ignoring case differences
Xcfalpha:
X	lea	fib_FileName(a0),a0	;a = &Fipb->fib_FileName
X	lea	fib_FileName(a1),a1	;b = &Fipb->fib_FileName
X
X;  for(; *a && tolower(*a) == tolower(*b); a++, b++);
Xlccstart:
X	tst.b	(a0)			;Is there a char here at source?
X	 beq.s	lcceostr		;Nope, fell off the end
X
X	move.b	(a1)+,d1		;Grab a char from bstr
X	cmpi.b	#$40,d1			;less than @ character?
X	 bls.s	1$			;Yep
X	cmpi.b	#$5a,d1			;Greater than Z?
X	 bhi.s	1$			;Yep
X	addi.b	#$20,d1
X1$
X	move.b	(a0)+,d0		;Grab a char from astr
X	cmpi.b	#$40,d0			;less than @ character?
X	 bls.s	2$			;Yep
X	cmpi.b	#$5a,d0			;Greater than Z?
X	 bhi.s	2$			;Yep
X	addi.b	#$20,d0
X2$
X	cmp.b	d0,d1			;are they the same?
X	 beq	lccstart		;Yep, compare next pair of chars
X
Xlcceostr:
X	sub.b	d1,d0			;return(tolower(*astr) - tolower(*bstr))
X	 bgt.s	cftrue			; > 0?, return TRUE
X	bra.s	cffalse			;Else return FALSE
X
Xcfnalpha:
X	subq.w	#1,d2			;Size?
X	 bne.s	cfnsize			;Nope
X
X* Compare fib_Sizes
X	move.l	fib_Size(a0),d0		;d0 = afib->fib_Size
X	cmp.l	fib_Size(a1),d0		;b->fib_Size > a->fib_Size?
X	 bgt.s	cftrue			;Yep, return TRUE
X	 blt.s	cffalse			;<, return FALSE
X	 bra	cfalpha			;Else it's a tie, alphabetize
X
Xcfnsize:
X* Compare fib_DateStamps
X	lea	fib_DateStamp(a0),a0	;a = &afib->fib_DateStamp
X	lea	fib_DateStamp(a1),a1	;b = &bfib->fib_DateStamp
X	jsr	@CompareDateStamps
X	tst.l	d0
X	 beq	cfalpha			;its the same date?, alphabetize
X	 blt.s	cffalse
Xcftrue:
X	moveq	#1,d0
X	bra.s	cfexit
Xcffalse:
X	moveq	#0,d0
Xcfexit:
X	btst.l	#9,d3			;LSFlags & REVFLAG?
X	 beq.s	1$			;Nope
X	bchg.l	#0,d0			;Else invert boolean result
X1$
Xcfexit0:
X	movem.l	(sp)+,d2-d3/a2
X	rts
X
X* --------------------------------------------------------------------- *
X* LONG CompareDateStamps(adate, bdate)
X*  d0                     a0      a1
X*   struct DateStamp *adate, *bdate;
X* --------------------------------------------------------------------- *
X	XDEF	@CompareDateStamps
X@CompareDateStamps:
X	move.l	ds_Days(a0),d0		;d0 = adate->ds_Days
X	sub.l	ds_Days(a1),d0		;b->ds_Days > a->ds_Days?
X	 bne.s	1$			;Return b->day - a->day
X
X;They are the same day, check min/tick
X	move.l	ds_Minute(a0),d0
X	sub.l	ds_Minute(a1),d0	;d0 = amin - bmin
X	muls	#3000,d0		;     * 3000
X	add.l	ds_Tick(a0),d0
X	sub.l	ds_Tick(a1),d0		;     + atick - btick
X1$
X	rts
X
X* --------------------------------------------------------------------- *
X* VOID InsertFibNode(hfib, newfib)
X*                     a0     a1
X*   struct List *hfib;
X*   struct FibEntry *newfib;
X*
X* Compare data in newfib->Fib with nodes in the list until we
X* find the insertion point.
X* --------------------------------------------------------------------- *
X	XDEF	@InsertFibNode
X@InsertFibNode:
X	movem.l	d2/a2-a3/a5/a6,-(sp)
X
X	move.l	sortkey(a4),d2
X	movea.l	a0,a3			;a3 = hfib
X	movea.l	a1,a2			;a2 = newfib
X
X	movea.l	LH_HEAD(a3),a5		;afib = hfib->lh_Head
X
X1$	tst.l	fe_Node+LN_SUCC(a5)	;afib->fe_Node.mln_Succ != 0?
X	 beq.s	4$
X
X	movea.l	fe_Fib(a2),a1
X	movea.l	fe_Fib(a5),a0
X	move.l	d2,d0
X	jsr	@CompFibs		;CompFibs(sortkey, afib->Fib, newfib->Fib)
X	tst.w	d0
X	 bne.s	4$
X	movea.l	fe_Node+LN_SUCC(a5),a5	;afib = afib->fe_Node.mln_Succ
X	bra	1$
X
X4$	movea.l	a3,a0			;a0 = List *
X	movea.l	a2,a1			;a1 = Node *
X	movea.l	fe_Node+LN_PRED(a5),a2	;a2 = Pred *
X	SYS	Insert,4		;Insert(hfib, newfib, afib->fe_Node.mln_Succ)
X
X	movem.l	(sp)+,d2/a2-a3/a5/a6
X	rts
X
X* --------------------------------------------------------------------- *
X* LONG FillFibEntry (headfib, fibp)
X*		       a0      a1          
X*   struct List *headfib;
X*   struct FileInfoBlock *fibp;
X* --------------------------------------------------------------------- *
X	XDEF	@FillFibEntry
X@FillFibEntry:
X	movem.l	a2-a3/a5/a6,-(sp)
X	movea.l	a0,a2			;a2 = head of list
X	movea.l	a1,a3			;a3 = fileinfoblock
X
X	jsr	@AllocFib		;Allocate a new fib
X	tst.l	d0			;Got it?
X	 beq.s	3$			;Nope, return 0
X	movea.l	d0,a5			;a5 = tfibp = AllocFib()
X
X	move.l	#fib_SIZEOF,d0
X	movea.l	fe_Fib(a5),a1
X	movea.l	a3,a0
X	SYS	CopyMem,4		;CopyMem(fibp, tfibp->Fib, sizeof(struct fib))
X
X	movea.l	a5,a1
X	movea.l	a2,a0
X
X	jsr	@InsertFibNode		;InsertFibNode(headfib, tfibp)
X
X	moveq	#1,d0			;return(1)
X3$
X	movem.l	(sp)+,a2-a3/a5/a6
X	rts
X
X* --------------------------------------------------------------------- *
X	XDEF	@nullstub
X@nullstub:
X	moveq	#0,d0
X	rts
X
X* --------------------------------------------------------------------- *
X* LONG GetPathString (dest, src)
X*  d0                  a0    a1
X*   BYTE *dest, *src;
X* --------------------------------------------------------------------- *
X	XDEF	@GetPathString
X@GetPathString:
X	move.l	a2,-(sp)
X
X	moveq	#0,d0			;Zero return dest length
X
X* Find end of src string
X	movea.l	a1,a2			;Save src start address
X1$	tst.b	(a1)+			;while (*src++ != 0)
X	 bne	1$
X
X* Work backwards till we find a ':' or a '/'
X2$	move.b	-(a1),d1		;c = *(--src)
X	cmpi.b	#':',d1			;Hit a colon?
X	 beq.s	4$			;Yep, found our path end
X	cmpi.b	#'/',d1			;Hit a slash?
X	 bne.s	3$			;Nope, try next char
X	cmpa.l	a2,a1			;At first char?
X	 beq.s	4$			;Yep, leave the single slash
X	cmpi.b	#'/',-1(a1)		;Next char back is also a '/'?
X	 beq.s	4$			;Yep, allow multiple slashes
X	subq.w	#1,a1			;Else backup to previous char, eliminate '/'
X	bra.s	4$
X3$
X	cmpa.l	a2,a1			;Back at start of src?
X	 bhi	2$			;Nope, try previous src char
X	bra.s	gpsdone			;Else no dest, return
X4$
X* Copy path portion to dest
Xgpscpy:
X	cmpa.l	a2,a1			;Past end address?
X	 bcs.s	gpsdone			;Yep, terminate
X	move.b	(a2)+,(a0)+		;Copy a char from src to dest
X	addq.w	#1,d0			;Bump dest length count
X	bra	gpscpy			;Check end address
Xgpsdone:
X	clr.b	(a0)			;Null terminate dest
X
X	movea.l	(sp)+,a2
X	rts
X
X* --------------------------------------------------------------------- *
X* LONG GetFileString (dest, src)
X*  d0                  a0    a1
X*   BYTE *dest, *src;
X* --------------------------------------------------------------------- *
X	XDEF	@GetFileString
X@GetFileString:
X	move.l	a2,-(sp)
X
X	moveq	#0,d0			;Zero return dest length
X
X* Find end of src string
X	movea.l	a1,a2			;Save src start address
X1$	tst.b	(a1)+			;while (*src++ != 0)
X	 bne	1$
X
X* Work backwards till we find a ':' or a '/'
X2$	move.b	-(a1),d1		;c = *(--src)
X	cmpi.b	#':',d1			;Hit a colon?
X	 beq.s	4$			;Yep, found our path end
X	cmpi.b	#'/',d1			;Hit a slash?
X	 beq.s	4$			;Nope, try next char
X3$
X	cmpa.l	a2,a1			;Back at start of src?
X	 bhi	2$			;Nope, try previous src char
X	bra.s	gfscpy			;Else no path, entire src is filename
X4$
X	addq.w	#1,a1			;Move past ':' or '/'
X
X* Copy name portion to dest
Xgfscpy:
X	move.b	(a1)+,(a0)+		;Copy a char from src to dest
X	 beq.s	2$
X	addq.w	#1,d0			;Bump dest length count
X	bra	gfscpy			;Check end address
X2$
X	movea.l	(sp)+,a2
X	rts
X
X* ------------------------------------------------------------------------- *
X* BYTE *astrncpy(dst, src, len)
X* d0/a0          a0   a1    d0
X* Takes text in a1, copies d0 bytes to text in a0.
X* a0 returns pointing to null at end of final text.
X* Dest text is always null terminated.
X* ------------------------------------------------------------------------- *
X	XDEF	@astrncpy
X@astrncpy:
X1$	subq.l	#1,d0			;Dec count
X	 blt.s	2$			;Done!
X
X	move.b	(a1)+,(a0)+		;Copy a byte
X	 bne	1$			;Do until end of src or cnt < 0
X2$
X	clr.b	(a0)			;Null terminate dest
X	move.l	a0,d0			;Return in d0 also
X	rts
X
X* ------------------------------------------------------------------------- *
X* VOID amovmem(src, dst, len)
X*              a0    a1   d0
X* Takes text in a0, copies d0 bytes to text in a1. Correctly handles
X* overlapping memory.
X* ------------------------------------------------------------------------- *
X	XDEF	amovmem
Xamovmem:
X	cmpa.l	a0,a1			;Low to high or high to low?
X	 bcs.s	2$			;High to low, copy forward
X	adda.w	d0,a0			;Else start at end, copy backward
X	adda.w	d0,a1
X
X1$	move.b	-(a0),-(a1)
X	subq.w	#1,d0
X	 bgt	1$
X	bra.s	amdone
X
X2$	move.b	(a0)+,(a1)+
X	subq.w	#1,d0
X	 bgt	2$
Xamdone:
X	rts
X
X* --------------------------------------------------------------------- *
X* BYTE *aindex(BYTE *, BYTE);
X*  d0           a0      d0
X* --------------------------------------------------------------------- *
X	XDEF	@aindex
X@aindex:
X1$	cmp.b	(a0),d0
X	 beq.s	aifound
X	tst.b	(a0)+
X	 beq.s	ainomatch
X	bra	1$
X
Xainomatch:
X	moveq	#0,d0
X	rts
X
Xaifound:
X	move.l	a0,d0
X	rts
X
X* --------------------------------------------------------------------- *
X* LONG MakePathString(lock, dest)
X*                      a0     a1
X*   struct FileLock *lock;
X*   BYTE *dest;
X*
X* DESCRIPTION:
X*   Given text and a filelock, construct entire pathname and
X* return in dest.
X* --------------------------------------------------------------------- *
X	XDEF	@MakePathString
X@MakePathString:
X	movem.l	d2-d5/d7/a2-a3/a6,-(sp)
X
X* Grab pointer to lock and dest text to fill
X	move.l	a0,d3			;d3 = lock
X	movea.l	a1,a2			;a2 = dest
X	clr.b	(a2)			;NULL terminate dest
X	moveq	#0,d5			;LockFlag = 0
X
X* Allocate a FileInfoBlock for local use
X	move.l	#fib_SIZEOF,d0
X	jsr	@myalloc
X	move.l	d0,d7			;d7 = *fib
X	 beq	mpsfailed		;Whoops no mem? return!
X
X	movea.l	DOSBase(a4),a6		;DOSBase calls from here on
X
X* while (lock != 0)
X1$
X	tst.l	d3			;Got a lock?
X	 beq.s	mpsokay			;Nope, must be at root
X
X* Examine the current lock
X	move.l	d3,d1
X	move.l	d7,d2
X	SYS	Examine			;Examine(lock, fib)
X	tst.l	d0			;Okay?
X	 beq.s	mpsfailed		;Nope, some sort of dos failure?
X
X	movea.l	d7,a1
X	cmpi.b	#' ',fib_FileName(a1)	;if (fib->fib_FileName[0] >= ' ')
X	 bcs.s	3$			;Nope, don't bother inserting?
X
X	tst.b	(a2)			;if (dest[0] != 0)
X	 beq.s	2$
X	lea	SlashStr(a4),a1
X	movea.l	a2,a0
X	jsr	@InsertPathString	;InsertPathString(dest, "/");
X2$
X	movea.l	d7,a1
X	lea	fib_FileName(a1),a1
X	movea.l	a2,a0
X	jsr	@InsertPathString	;InsertPathString(dest, fib->fib_FileName)
X3$
X* Okay, move up one directory
X	move.l	d3,d4			;oldlock = lock
X
X	move.l	d3,d1
X	SYS	ParentDir
X	move.l	d0,d3			;lock = ParentDir(lock)
X
X	tst.w	d5			;LockFlag set?
X	 bne.s	4$			;Yep, unlock
X	moveq	#1,d5			;Else LockFlag = 1, unlock next time
X	 bra	1$			;Next directory up
X4$
X	move.l	d4,d1
X	SYS	UnLock			;UnLock(oldlock)
X	bra	1$			;Examine
X
Xmpsokay:
X* See if root was RAM:, special case
X	movea.l	d7,a1			;a1 = fib
X	cmpi.b	#' ',fib_FileName(a1)	;if (fib->fib_FileName[0] >= ' ')
X	 bcc.s	1$			;Yep, not 1.1/1.2 RAM:
X	lea	RamNameStr(a4),a1	;Else...
X	movea.l	a2,a0
X	jsr	@InsertPathString	;InsertPathString(dest, "RAM:")
X	bra.s	mpsdone
X1$
X* Find last slash we tacked on, change to a colon, or, add a colon
X	moveq	#'/',d0
X	movea.l	a2,a0
X	jsr	@aindex			;d0 = strchr(dest, '/')
X	tst.l	d0			;Do we have a slash?
X	 beq.s	2$			;Nope, at root....
X	movea.l	d0,a0
X	move.b	#':',(a0)		;Else change first '/' to a ':'
X	bra.s	mpsdone
X
X* No slash, must be locked at the root.  Append a colon to the dest.
X2$
X	lea	ColonStr(a4),a1	
X	movea.l	a2,a0
X	jsr	@strcat			;strcat (dest, ":")
X	bra.s	mpsdone
X
X* Come here if an error occured, return empty text to caller
Xmpsfailed:
X	clr.b	(a2)			;dest[0] = (BYTE)0
X	moveq	#0,d3			;return (0L)
X	bra.s	mpsdeall
X
X* Come here if everything is okay, deallocate FileInfoBlock
Xmpsdone:
X	moveq	#1,d3			;return (1L)
X
Xmpsdeall:
X	tst.l	d7			;Did we allocate a fib?
X	 beq.s	mpsfinis		;nope
X	movea.l	d7,a0			;Else free the memory
X	jsr	@myfree
X
Xmpsfinis:
X	move.l	d3,d0			;Put return value in d0
X	movem.l	(sp)+,d2-d5/d7/a2-a3/a6
X	rts
X
X* --------------------------------------------------------------------- *
X* VOID InsertPathString(dest, source)
X*                        a0     a1
X*   BYTE *dest, *source;
X*
X* DESCRIPTION:
X*   Insert source text into dest text.
X* Special case for source length == 0, source must be RAM.
X* --------------------------------------------------------------------- *
X	XDEF	@InsertPathString
X@InsertPathString:
X	movem.l	d7/a2-a3,-(sp)
X
X	movea.l	a1,a3			;a3 = source
X	move.l	a0,a2			;a2 = dest
X
X	movea.l	a3,a0
X	jsr	@strlen
X	move.l	d0,d7			;d7 = strlen(source)
X
X1$	movea.l	a2,a0
X	jsr	@strlen			;d0 = strlen(dest)
X
X	addq.w	#1,d0			;Bump the length to include zero byte at end
X	movea.l	a2,a1
X	adda.w	d7,a1			;Push dest + slen
X	movea.l	a2,a0			;Push dest
X	jsr	amovmem			;amovmem(dest, dest + slen, strlen(dest) + 1)
X
X	move.w	d7,d0
X	movea.l	a2,a1
X	movea.l	a3,a0
X	jsr	amovmem			;amovmem(source, dest, slen)
X
X	movem.l	(sp)+,d7/a2-a3
X	rts
X
X* --------------------------------------------------------------------- *
X* VOID NoMemExit(VOID)
X* --------------------------------------------------------------------- *
X	XDEF	@NoMemExit
X@NoMemExit:
X	moveq	#103,d1
X	moveq	#20,d0
X	lea	NoRAMMsg(a4),a0
X	jsr	@CleanUp
X	rts
X
X* --------------------------------------------------------------------- *
X* VOID NoFileExit(name)
X*                  a0
X* BYTE *name;
X* --------------------------------------------------------------------- *
X	XDEF	@NoFileExit
X@NoFileExit:
X	movem.l	d2-d4/a6,-(sp)
X
X	move.l	a0,d2			;Save name
X	SYS	IoErr,DOSBase(a4)	;Get IoError status
X	move.l	d0,d3			;Save it
X
X	move.l	#300,d0
X	jsr	@myalloc
X	move.l	d0,d4			;d3 = myalloc( 300 )
X	 bne.s	1$			;Got it!
X	jsr	@NoMemExit		;else exit with No Ram message
X	bra.s	2$
X1$
X	move.l	d2,-(sp)
X	pea	NoFindFmtStr(a4)
X	move.l	d4,-(sp)
X	jsr	asprintf		;asprintf(tstr, NoFindFmtStr, name)
X	lea	12(sp),sp
X
X	move.l	d3,d1
X	moveq	#20,d0
X	movea.l	d4,a0
X	jsr	@CleanUp		;CleanUp(tstr, 20L, IoErr())
X					;         a0   d0     d1
X	move.l	d4,a0
X	jsr	@myfree			;free (tstr)
X2$
X	movem.l	(sp)+,d2-d4/a6
X	rts
X
X* --------------------------------------------------------------------- *
X	END
X* --------------------------------------------------------------------- *
END_OF_FILE
if test 33907 -ne `wc -c <'src/lssup.a'`; then
    echo shar: \"'src/lssup.a'\" unpacked with wrong size!
fi
# end of 'src/lssup.a'
fi
echo shar: End of archive 2 \(of 3\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
Mail comments to the moderator at <amiga-request@cs.odu.edu>.
Post requests for sources, and general discussion to comp.sys.amiga.