; head

; (C) Stuart Mitchell - November 1990

		section head,code

		opt o+

		incdir "include:"

		INCLUDE "include:exec/types.i"
		INCLUDE "include:exec/memory.i"
		INCLUDE "include:libraries/dos.i"
		include "libraries/arpbase.i"

NUM_LINES	equ	10
LF		equ	$0a

_LVOOpenLibrary 	equ	-$228
_LVOCloseLibrary	equ	-$19e

CALL	MACRO
	jsr	_LVO\1(a6)
	ENDM

r_current_char	equr	a2
r_buffer	equr	a3
r_arpbase	equr	a6			; must be a6

r_num_arg	equr	d7
r_fh		equr	d6
r_lines 	equr	d5
r_cli_fh	equr	d4
r_num_read	equr	d3			; don't move this one
r_count 	equr	d2


start:		move.l	4.w,a6			;transfer ExecBase

; save command line - d4/a4 won't be trashed by OpenLibrary call...

		move.l	a0,a4			;address of startup line
		move.l	d0,d4			;length

; Open arp.library

		lea	arpname(pc),a1          ;get address of arpname
		moveq.l #39,d0			;version 1.3+
		CALL	OpenLibrary
		move.l	d0,r_arpbase
		beq	close			;if NULL exit

; parse filename

		move.l	a4,a0			; string
		move.l	d4,d0			; length

		lea	help(pc),a1
		lea	arg0(pc),a2             ; pointer to arg array
		lea	tplate(pc),a3
		CALL	GADS
		tst.l	d0
		beq	pr_usage
		blt	pr_line_err

; find output

		CALL	Output
		move.l	d0,r_cli_fh

; allocate buffer of 512 bytes of memory (MEMF_PUBLIC|MEMF_CLEAR)

		move.l	#512,d0
		CALL	ArpAlloc
		tst.l	d0
		beq	pr_nomem		;error if returned NULL
		move.l	d0,r_buffer		;save address

; open file

open_file:	move.l	arg1,d1 		;pointer to filename
		move.l	#MODE_OLDFILE,d2
		CALL	ArpOpen
		beq.s	pr_nofile		;if fh==0 exit
		move.l	d0,r_fh 		;save file handle

; set up count of lines to print

		move.l	arg0,d0
		beq.s	ten			; if no arg then default
		move.l	d0,a0
		CALL	Atol
		beq	bad_num
		tst.l	d0
		ble.s	bad_num
		move.l	d0,r_lines
		bra.s	read512

ten		moveq.l #NUM_LINES,r_lines	;print 10 lines

; read in 512 bytes of file to buffer

read512 	move.l	#512,d3			;read 512 bytes
		move.l	r_buffer,d2		;into allocated mem
		move.l	r_fh,d1 		;from fh
		CALL	Read
		beq.s	close			;if no chars (EOF) then exit
		move.l	d0,r_num_read		;save num chars read
		move.l	r_buffer,r_current_char ;move to start buffer

		moveq.l #0,r_count		;clear count of chars

loop		addq.l	#1,r_count		;inc number chars read
		cmpi.b	#LF,(r_current_char)+   ;if not (char==LF)
		bne.s	cont
		subq	#1,r_lines		;decrement lines count
		beq.s	finished		;branch if finished
cont		cmp.l	r_count,r_num_read	;if not buffer empty
		bne.s	loop			;do next char

		move.l	r_cli_fh,d1
		move.l	r_buffer,d2		;print all (d3) num of chars
		CALL	Write,a5

		bra.s	read512 		;read next lot

finished	move.l	r_count,d3		;print out num required
		move.l	r_buffer,d2
		move.l	r_cli_fh,d1
		CALL	Write,a5		;of characters

; Arp frees memory & closes files automatically

close		move.l	r_arpbase,a1		;move pointer to arp
		move.l	4.w,a6
		CALL	CloseLibrary		;close arp.library

exit_dos:	moveq.l #0,d0
		rts

pr_nofile	lea	nofile(pc),a0
		lea	arg1(pc),a1
		CALL	Printf
		bra.s	close

pr_nomem	lea	mem(pc),a1
		CALL    Puts
		bra.s	close

pr_usage	lea	help(pc),a1
		CALL    Puts
		bra.s	close

pr_line_err	move.l	arg0,a1		; arg0 set to some string by ARP
		CALL    Puts
		bra.s	close

bad_num 	lea	num(pc),a1
my_puts:	CALL	Puts
		bra.s	close

		even
arpname 	dc.b	'arp.library',0
		even
help		dc.b	'usage : head [lines <num lines>] <file>',0
		even
tplate		dc.b	'l=lines/K,file/A',0
		even
arg0		dc.l	0
arg1		dc.l	0
		even
mem		dc.b	'No memory',0
		even
nofile		dc.b	'Cannot open file "%s"',$a,0
		even
num		dc.b	'Illegal lines count',0
		end

