		*********************************
		*                               *
		*   Visual Shell v1.17  10/92   *
		*                               *
		*     by Torsten Jürgeleit      *
		*                               *
		*   assembly support routines   *
		*            part II            *
		*                               *
		*********************************

	NOLIST
	INCLUDE "exec/types.i"
	INCLUDE "exec/ports.i"
	INCLUDE "exec/nodes.i"
	INCLUDE "exec/lists.i"
	INCLUDE "exec/memory.i"
	INCLUDE "libraries/arpbase.i"
	INCLUDE "intuition/intuition.i"
	INCLUDE "equates.i"
	LIST

;---------------------------------------------------------------------------
; External definitions
;---------------------------------------------------------------------------

	XDEF	_unpack_font
	XDEF	_display_text
	XDEF	write_text
	XDEF	_print_freq_lines
	XDEF	_hcomp_freq_cursor
	XDEF	_move_freq_cursor_down
	XDEF	_scroll_file_req
	XDEF	_print_vreq_lines
	XDEF	_build_vreq_line
	XDEF	build_text_line
	XDEF	_hcomp_vreq_line
	XDEF	_scroll_view_req
	XDEF	_print_quick_view_lines

;---------------------------------------------------------------------------
; External references
;---------------------------------------------------------------------------

	XREF	_IntuitionBase
	XREF	_GfxBase
	XREF	_gadget_buffer
	XREF	_con_device
	XREF	_con_unit
	XREF	_con_window
	XREF	_con_rport
	XREF	_main_task
	XREF	_vsh_port
	XREF	_auto_repeat
	XREF	_show_flag
	XREF	_scroll_flag
	XREF	_vsh_scroll_speed
	XREF	_vsh_dump_mode
	XREF	_qualifier
	XREF	_enable_abort
	XREF	_num_lock
	XREF	_key_table
	XREF	_action_table
	XREF	_scroll_flag_table
	XREF	_action
	XREF	_file_req
	XREF	_view_req
	XREF	_active_freq
	XREF	_line1_buffer
	XREF	_wb_line_len
	XREF	_max_line_len
	XREF	_print_dir_info
	XREF	_print_info_line
	XREF	_print_vreq_status
	XREF	_print_quick_view
	XREF	_SPrintf
	XREF	_protection_bits
	XREF	_protection_string
	XREF	_font_data
	XREF	_template_buffer

;---------------------------------------------------------------------------
; VOID unpack_font(font, font_data)
;		    a0      a1
; 	struct TextFont  *font
;	UBYTE *font_data
; Unpack specified text font into buffer
;---------------------------------------------------------------------------
_unpack_font:
	PUSH	d2-d4/a2-a3

	; --- init some regs
	move.w	tf_Modulo(a0),d1
	moveq	#0,d2
	move.b	tf_LoChar(a0),d2
	moveq	#0,d3
	move.b	tf_HiChar(a0),d3
	move.l	tf_CharData(a0),a2
	move.l	tf_CharLoc(a0),a3
	moveq	#0,d4			; reset char counter

up_low_loop:
	; --- copy 0 to tf_LoChar-1 dummy characters
	cmp.w	d2,d4
	bhs	up_mid_loop
	move.w	d3,d0
	sub.w	d2,d0
	addq.w	#1,d0
	bsr	copy_font_char
	addq.w	#1,d4
	bra	up_low_loop

up_mid_loop:
	; --- copy tf_LoChar to tf_HiChar-1 real characters
	cmp.w	d3,d4
	bhi	up_high_loop
	move.w	d4,d0
	sub.w	d2,d0
	bsr	copy_font_char
	addq.w	#1,d4
	bra	up_mid_loop

up_high_loop:
	; --- copy tf_HiChar to 255 dummy characters
	cmp.w	#255,d4
	bhi	up_exit
	move.w	d3,d0
	sub.w	d2,d0
	addq.w	#1,d0
	bsr	copy_font_char
	addq.w	#1,d4
	bra	up_high_loop

up_exit:
	PULL	d2-d4/a2-a3
	rts

;---------------------------------------------------------------------------
; Copy font character data of specified char to given buffer
;
; Input: d0.w = character num (0..255)
;	 d1.w = tf_Modulo
;	 a1   = buffer ptr
;	 a2   = tf_CharData
;	 a3   = tf_CharLoc
;---------------------------------------------------------------------------
copy_font_char:
	lsl.w	#2,d0
	move.w	(a3,d0.w),d0		; d0 := bit offset into tf_CharData
	lsr.w	#3,d0			; d0 := byte offset into tf_CharData
	lea	0(a2,d0.w),a0		; a0 := character bitmap ptr
	moveq	#8-1,d0

cfc_copy_loop:
	move.b	(a0),(a1)+
	add.w	d1,a0
	dbra	d0,cfc_copy_loop

	rts

;---------------------------------------------------------------------------
; VOID display_text(front_color, back_color, x, y, text)
;	USHORT front_color, back_color, x, y
;	UBYTE  *text
; Print text on console window at specified position
;---------------------------------------------------------------------------
_display_text:
	PUSH	a2/a6

	move.l	_con_rport,a2		; a2 := rast port
	move.l	_GfxBase,a6

	moveq	#RP_JAM2,d0		; draw mode
	move.l	a2,a1
	CALLSYS	SetDrMd

	move.w	4+2*4(sp),d0		; front color
	move.l	a2,a1
	CALLSYS	SetAPen

	move.w	6+2*4(sp),d0		; back color
	move.l	a2,a1
	CALLSYS	SetBPen

	move.w	8+2*4(sp),d0		; x
	move.w	10+2*4(sp),d1		; y
	move.l	12+2*4(sp),a0		; text
	bsr	write_text

	PULL	a2/a6
	rts

;---------------------------------------------------------------------------
; Input : a0   = text ptr
;	  d0.w = xpos
;	  d1.w = ypos
; Write text to given rastport at specified position
;---------------------------------------------------------------------------
write_text:
	PUSH	d2-d6/a2-a3/a6

	move.w	d0,d2				; d2 := x pos
	move.w	d1,d3				; d3 := y pos
 	move.l	_font_data,d5			; d5 := font data ptr
	move.l	_template_buffer,d6		; d6 := template buffer ptr
	move.w	_wb_line_len,d4			; d4 := template modulo
	moveq	#0,d1				; d1 := char counter

wt_loop:
	moveq	#0,d0
	move.b	(a0)+,d0			; get next char from text
	beq	wt_blit_line

	move.l	d5,a2				; a2 := font data
	lsl.w	#3,d0				; d0 := offset in font data
	add.w	d0,a2				; a2 := start of char matrix
	move.l	d6,a3				; a3 := offset in template buffer

	move.b	(a2)+,(a3)			; copy char matrix to template
	add.w	d4,a3
	move.b	(a2)+,(a3)
	add.w	d4,a3
	move.b	(a2)+,(a3)
	add.w	d4,a3
	move.b	(a2)+,(a3)
	add.w	d4,a3
	move.b	(a2)+,(a3)
	add.w	d4,a3
	move.b	(a2)+,(a3)
	add.w	d4,a3
	move.b	(a2)+,(a3)
	add.w	d4,a3
	move.b	(a2)+,(a3)

	addq.w	#1,d6				; inc template ptr
	addq.w	#1,d1				; inc char counter
	cmp.w	d4,d1				; text too long ?
	blo	wt_loop

wt_blit_line:
	move.l	_template_buffer,a0		; a0 := template ptr
	move.l	_con_rport,a1			; a1 := rast port
	moveq	#0,d0				; d0 := template x offset
	exg	d1,d4				; d1 := template modulo -> MUST BE EVEN!!!
	lsl.w	#3,d4				; d4 := template width
	add.w	d4,rp_cp_x(a1)			; inc cursor pos
	moveq	#8,d5				; d5 := template height
	move.l	_GfxBase,a6			; a6 := GfxBase
	CALLSYS	BltTemplate
	CALLSYS	WaitBlit

	PULL	d2-d6/a2-a3/a6
	rts

;---------------------------------------------------------------------------
; VOID print_freq_lines(freq, node, line, count)
;			 a0    a1    d0    d1
;	struct FileRequest  *freq
;	struct FileNode     *node
;	USHORT line, count
; Print specified part of filerequester
;---------------------------------------------------------------------------
_print_freq_lines:
	PUSH	d2-d4/a2-a3/a5-a6

	tst.b	_show_flag			; hidden display ?
	beq	pfl_exit
	move.l	a0,a2				; a2 := freq
	move.l	a1,a3				; a3 := node
	move.w	d0,d2				; d2 := line
	move.w	d1,d3				; d3 := count
	move.w	fr_Mode(a2),d0			; d0 := freq mode

pfl_info_mode:
	cmp.w	#FREQ_MODE_INFO,d0		; info mode ?
	bne	pfl_quick_view_mode
	move.l	a2,a0				; a0 := freq
	jsr	_print_dir_info
	bra	pfl_exit

pfl_quick_view_mode:
	cmp.w	#FREQ_MODE_QUICK_VIEW,d0	; quick view mode ?
	bne	pfl_normal_mode
	move.l	a2,a0				; a0 := freq
	jsr	_print_quick_view
	bra	pfl_exit

pfl_normal_mode:
	move.l	_con_rport,a5
	move.l	_GfxBase,a6
	lsl.w	#3,d2				; line *= 8
	add.w	fr_Display+d_TopEdge(a2),d2	; d2 := vertical position
	move.w	fr_Display+d_LeftEdge(a2),d4	; d4 := horizontal position
	subq.w	#1,d3				; dec count for dbra

	move.l	a3,d0				; node == NULL
	beq	pfl_clear

	moveq	#RP_JAM2,d0			; draw mode := JAM2
	move.l	a5,a1				; rport
	CALLSYS	SetDrMd

pfl_print_loop:
	tst.l	MLN_SUCC(a3)			; end of list ?
	beq	pfl_clear

pfl_check_type:
	moveq	#COLOR1,d0			; type = file | assign
	move.b	fn_Type(a3),d1
	cmp.b	#ENTRY_TYPE_FILE,d1
	beq	pfl_set_front_color
	cmp.b	#ENTRY_TYPE_DIR,d1
	bne	pfl_set_front_color
	moveq	#COLOR3,d0			; type = dir | dev

pfl_set_front_color:
	move.l	a5,a1				; rport
	CALLSYS	SetAPen

pfl_check_mark:
	moveq	#COLOR0,d0			; normal back color
	tst.b	fn_Marked(a3)			; entry marked ?
	beq	pfl_set_back_pen
	moveq	#COLOR2,d0			; marked back color

pfl_set_back_pen:
	move.l	a5,a1				; rport
	CALLSYS	SetBPen

	lea	fn_Text(a3),a0			; text
	move.w	d4,d0				; x
	move.w	d2,d1				; y
	bsr	write_text

	addq.l	#8,d2				; inc vertical position
	move.l	MLN_SUCC(a3),a3
	dbra	d3,pfl_print_loop
	bra	pfl_exit

pfl_clear:
	moveq	#COLOR0,d0			; fill color
	move.l	a5,a1				; rport
	CALLSYS	SetAPen

	move.w	d4,d0				; x1
	move.w	d2,d1				; y1
	move.w	d0,d2
	add.w	#MAX_FREQ_LINE_WIDTH,d2		; x2
	addq.w	#1,d3				; inc count because of dbra
	lsl.w	#3,d3				; d3 * 8
	add.w	d1,d3				; y2
	move.l	a5,a1				; rport
	CALLSYS	RectFill

pfl_exit:
	PULL	d2-d4/a2-a3/a5-a6
	rts

;---------------------------------------------------------------------------
; VOID hcomp_freq_cursor(freq)
;			  a0
;	struct FileRequest  *freq
; Highlight or de-highlight the cursor line in filerequester
;---------------------------------------------------------------------------
_hcomp_freq_cursor:
	PUSH	a2/a6

	tst.b	_show_flag			; hidden display ?
	beq	hfc_exit	
	move.l	a0,a2				; a2 := freq
	lea	_file_req,a1			; active freq ?
	tst.b	_active_freq
	beq	hfc_first_freq

hfc_second_freq:
	add.l	#FileRequest_Sizeof,a1

hfc_first_freq:
	cmp.l	a1,a2				; a2 == &file_req[active_freq] ?
	bne	hfc_exit
	move.w	fr_Mode(a2),d0			; d0 := freq mode
	cmp.w	#FREQ_MODE_INFO,fr_Mode(a2)	; info mode ?
	beq	hfc_exit
	cmp.w	#FREQ_MODE_QUICK_VIEW,d0	; quick view mode ?
	beq	hfc_exit

	move.l	_GfxBase,a6
	bsr	hcomp_freq_cursor

hfc_exit:
	PULL	a2/a6
	rts

;---------------------------------------------------------------------------
; Input : a2 = freq ptr
;	  a6 = GfxBase
; Highlight or de-highlight the cursor line in filerequester
;---------------------------------------------------------------------------
hcomp_freq_cursor:
	PUSH	d2-d3/a3

	move.w	fr_CursorLine(a2),d2		; d2 := cursor line
	cmp.w	#-1,d2				; no cursor line ?
	beq	hfc_return
	cmp.w	fr_Display+d_VisibleLines(a2),d2
	bhs	hfc_return

	move.l	_con_rport,a3			; a3 := rast port
	moveq	#RP_COMPLEMENT,d0		; draw mode
	move.l	a3,a1
	CALLSYS	SetDrMd

	moveq	#0,d0
	move.w	fr_Display+d_LeftEdge(a2),d0	; x1
	moveq	#0,d1
	move.w	fr_Display+d_TopEdge(a2),d1
	lsl.w	#3,d2				; d2 * 8
	add.w	d2,d1				; y1
	move.l	d0,d2
	add.w	#MAX_FREQ_LINE_WIDTH-1,d2	; x2
	move.l	d1,d3
	addq.w	#7,d3				; y2
	move.l	a3,a1
	CALLSYS	RectFill

	moveq	#RP_JAM2,d0			; draw mode
	move.l	a3,a1
	CALLSYS	SetDrMd

hfc_return:
	PULL	d2-d3/a3
	rts

;---------------------------------------------------------------------------
; VOID move_freq_cursor_down(freq)
;			      a0
;	struct FileRequest  *freq
; Move cursor one entry down in given filerequester
;---------------------------------------------------------------------------
_move_freq_cursor_down:
	PUSH	d2-d7/a2-a3/a6			; save regs for scroll routine

	tst.b	_show_flag			; hidden display ?
	beq	mcd_exit
	move.l	a0,a2				; a2 := freq ptr
	move.w	fr_Mode(a2),d0			; d0 := freq mode
	cmp.w	#FREQ_MODE_INFO,d0		; info mode ?
	beq	mcd_exit
	cmp.w	#FREQ_MODE_QUICK_VIEW,d0	; quick view mode ?
	beq	mcd_exit
	tst.l	fr_Display+d_NumEntries(a2)	; empty file list ?
	beq	mcd_exit

	move.l	_GfxBase,a6
	bsr	hcomp_freq_cursor		; draw new cursor line
	moveq	#1,d7				; d7 := count
	bsr	scroll_freq_down
	moveq	#INFO_LINE_MODE_NORMAL,d0	; d0 := mode
	jsr	_print_info_line		; print new info line

mcd_exit:
	PULL	d2-d7/a2-a3/a6
	rts

;---------------------------------------------------------------------------
; VOID scroll_file_req(VOID)
; Scroll file list in active filerequester
;---------------------------------------------------------------------------
_scroll_file_req:
	PUSH	d2-d7/a2-a3/a6			; save regs for scroll routines

	tst.b	_scroll_flag			; check scroll flag
	beq	sfr_exit
	tst.b	_show_flag			; hidden display ?
	beq	sfr_exit
	lea	_file_req,a2			; a2 := &file_req[active_freq]
	tst.b	_active_freq
	beq	sfr_left_freq
	add.l	#FileRequest_Sizeof,a2

sfr_left_freq:
	move.w	fr_Mode(a2),d0			; d0 := freq mode
	cmp.w	#FREQ_MODE_INFO,d0		; info mode ?
	beq	sfr_exit
	cmp.w	#FREQ_MODE_QUICK_VIEW,d0	; quick view mode ?
	beq	sfr_exit
	cmp.l	#1,fr_Display+d_NumEntries(a2)	; more than one entries in file list ?
	bls	sfr_exit

sfr_auto_repeat_loop:
	move.l	_GfxBase,a6
	move.b	_scroll_flag,d1			; d1 := scroll flag
	bclr	#7,d1				; top or bottom ?
	bne	sfr_scroll_all
	moveq	#1,d7				; d7 := count
	bclr	#6,d1				; page up or down ?
	beq	sfr_scroll_part
	moveq	#0,d7
	move.w	fr_Display+d_VisibleLines(a2),d7	; d7 := count

sfr_scroll_part:
	bclr	#0,d1				; scroll up ?
	bne	sfr_scroll_part_up
	bclr	#1,d1				; scroll down ?
	beq	sfr_exit

sfr_scroll_part_down:
	bsr	scroll_freq_down
	bra	sfr_print_info

sfr_scroll_part_up:
	bsr	scroll_freq_up
	bra	sfr_print_info

sfr_scroll_all:
	bsr	hcomp_freq_cursor		; clear old cursor line
	move.l	fr_Display+d_List(a2),a0	; a0 := file list ptr
	move.b	_scroll_flag,d0			; d0 := scroll flag
	btst	#0,d0				; scroll up ?
	beq	sfr_scroll_all_down

sfr_scroll_all_up:
	move.l	MLH_HEAD(a0),a0
	clr.w	fr_CursorLine(a2)		; cursor at top
	bra	sfr_scroll_all_print

sfr_scroll_all_down:
	moveq	#0,d0
	move.w	fr_Display+d_VisibleLines(a2),d0
	cmp.l	fr_Display+d_NumEntries(a2),d0	; lesser entries than lines ?
	blo	sfr_search_last_entry
	move.l	fr_Display+d_NumEntries(a2),d0	; cursor to last entry
	subq.w	#1,d0
	move.w	d0,fr_CursorLine(a2)
	bra	sfr_draw_cursor

sfr_search_last_entry:
	move.l	MLH_TAILPRED(a0),a0
	move.w	fr_Display+d_VisibleLines(a2),d0
	subq.w	#2,d0				; dec for dbra

sfr_last_entry_loop:
	move.l	MLN_PRED(a0),a0
	dbra	d0,sfr_last_entry_loop
	move.w	fr_Display+d_VisibleLines(a2),d0	; cursor at bottom
	subq.w	#1,d0
	move.w	d0,fr_CursorLine(a2)

sfr_scroll_all_print:
	move.l	a0,fr_Display+d_FirstVisibleNode(a2)
	move.l	a0,a1					; a1 := node
	move.l	a2,a0					; a0 := freq
	moveq	#0,d0					; d0 := line
	move.w	fr_Display+d_VisibleLines(a2),d1	; d1 := count
	jsr	_print_freq_lines			; print whole page

sfr_draw_cursor:
	bsr	hcomp_freq_cursor		; draw new cursor line

sfr_print_info:
	moveq	#INFO_LINE_MODE_NORMAL,d0	; d0 := mode
	jsr	_print_info_line		; print new info line

sfr_check_auto_repeat:
	cmp.b	#SCROLL_SPEED_FAST,_vsh_scroll_speed	; fast scrolling ?
	bne	sfr_exit
	tst.b	_auto_repeat			; auto_repeat ?
	beq	sfr_exit
	tst.b	_scroll_flag			; check scroll flag
	bne	sfr_auto_repeat_loop

sfr_exit:
	PULL	d2-d7/a2-a3/a6
	rts

;---------------------------------------------------------------------------
; Input : a2   = filerequest ptr
;	  a6   = GfxBase
;	  d7.l = scroll count
; Scroll file list of active file requester count times up
;---------------------------------------------------------------------------
scroll_freq_up:
	moveq	#0,d2
	move.w	fr_Display+d_VisibleLines(a2),d2	; d2 := visible lines
	move.l	fr_Display+d_NumEntries(a2),d3		; d3 := number of entries
	move.l	fr_Display+d_FirstVisibleNode(a2),a3	; check cursor line - count
	moveq	#0,d4
	move.w	fr_CursorLine(a2),d4
	add.l	fn_Pos(a3),d4
	subq.l	#1,d4
	beq	sfu_exit			; already at top ?
	bsr	hcomp_freq_cursor		; clear old cursor line
	cmp.l	d7,d4
	bhi	sfu_move_cursor
	cmp.l	#1,fn_Pos(a3)			; already at top ?
	bhi	sfu_start_scroll
	clr.w	fr_CursorLine(a2)		; now cursor at top
	bra	sfu_draw_cursor

sfu_move_cursor:
	move.w	fr_CursorLine(a2),d0		; dec cursor line
	sub.w	d7,d0
	bmi	sfu_scroll
	bne	sfu_set_cursor			; cursor at top ?
	cmp.l	#1,fn_Pos(a3)			; already at top ?
	bhi	sfu_start_scroll

sfu_set_cursor:
	move.w	d0,fr_CursorLine(a2)
	bra	sfu_draw_cursor

sfu_scroll:
	cmp.l	#1,fn_Pos(a3)			; already at top ?
	bls	sfu_draw_cursor

sfu_start_scroll:
	move.w	d7,d0				; d0 := scroll count
	subq.w	#1,d0				; dec count for dbra

sfu_loop:
	cmp.l	#1,fn_Pos(a3)			; top reached ?
	beq	sfu_check_count
	move.l	MLN_PRED(a3),a3			; get previous node
	dbra	d0,sfu_loop

sfu_check_count:
	cmp.w	#1,d7				; paging ?
	bhi	sfu_paging

sfu_init_scroll:
	move.l	_con_rport,a0			; source rport
	move.l	a0,a1				; dest rport
	move.w	fr_Display+d_LeftEdge(a2),d0	; x1
	move.w	fr_Display+d_TopEdge(a2),d1	; y1
	move.w	d1,d3				; y2
	move.w	d0,d2				; x2
	move.w	fr_Display+d_Width(a2),d4	; width
	move.w	fr_Display+d_VisibleLines(a2),d5
	lsl.w	#3,d5				; height
	move.w	#$0c0,d6			; minterm
	cmp.b	#SCROLL_SPEED_SLOW,_vsh_scroll_speed
	beq	sfu_scroll_slow

sfu_scroll_normal:
	addq.w	#8,d3				; y2
	subq.w	#8,d5				; height
	CALLSYS	ClipBlit			; scroll one entry up
	bra	sfu_paging

sfu_scroll_slow:
	PUSH	d7
	subq.w	#1,d1				; y1
	moveq	#8-1,d7				; d7 := count

1$:
	movem.w	d0-d6,-(sp)
	PUSH	a0-a1
	CALLSYS	ClipBlit			; scroll one scanline up
	PULL	a0-a1
	movem.w	(sp)+,d0-d6
	dbra	d7,1$
	PULL	d7

sfu_paging:
	move.l	a2,a0				; a0 := freq
	move.l	a3,a1				; a1 := node
	moveq	#0,d0				; d0 := line
	move.w	d7,d1				; d1 := count
	jsr	_print_freq_lines		; print new entry
	move.l	a3,fr_Display+d_FirstVisibleNode(a2)

sfu_draw_cursor:
	bsr	hcomp_freq_cursor		; draw new cursor line

sfu_exit:
	rts

;---------------------------------------------------------------------------
; Input : a2   = filerequest ptr
;	  a6   = GfxBase
;	  d7.l = scroll count
; Scroll file list of active file requester count times down
;---------------------------------------------------------------------------
scroll_freq_down:
	moveq	#0,d2
	move.w	fr_Display+d_VisibleLines(a2),d2	; d2 := visible lines
	move.l	fr_Display+d_NumEntries(a2),d3		; d3 := number of entries
	move.l	fr_Display+d_FirstVisibleNode(a2),a3	; check cursor line + count
	moveq	#0,d4
	move.w	fr_CursorLine(a2),d4
	add.l	fn_Pos(a3),d4
	cmp.l	d3,d4				; already at bottom ?
	beq	sfd_exit
	bsr	hcomp_freq_cursor		; clear old cursor line
	subq.l	#1,d4
	add.l	d7,d4
	cmp.l	d3,d4
	blo	sfd_move_cursor
	move.l	fn_Pos(a3),d1			; already at bottom ?
	add.l	d2,d1
	cmp.l	d3,d1
	bls	sfd_start_scroll
	cmp.l	d2,d3				; more than one page ?
	bhi	sfd_more_pages
	move.w	d3,d0				; now cursor at bottom
	subq.w	#1,d0
	move.w	d0,fr_CursorLine(a2)
	bra	sfd_draw_cursor

sfd_more_pages:
	move.w	d2,d0				; now cursor at bottom
	subq.w	#1,d0
	move.w	d0,fr_CursorLine(a2)
	bra	sfd_scroll

sfd_move_cursor:
	move.w	fr_CursorLine(a2),d0		; dec cursor line
	add.w	d7,d0
	move.w	d2,d1
	subq.w	#1,d1				; d1 := visible lines - 1
	cmp.w	d1,d0
	bhi	sfd_scroll
	bne	sfd_set_cursor			; cursor at bottom ?
	move.l	fn_Pos(a3),d1			; already at bottom ?
	add.l	d2,d1
	cmp.l	d3,d1
	bls	sfd_start_scroll

sfd_set_cursor:
	move.w	d0,fr_CursorLine(a2)
	bra	sfd_draw_cursor

sfd_scroll:
	move.l	fn_Pos(a3),d1			; already at bottom ?
	add.l	d2,d1
	cmp.l	d3,d1
	bhi	sfd_draw_cursor

sfd_start_scroll:
	move.w	d7,d0				; d0 := scroll count
	subq.w	#1,d0				; dec count for dbra

sfd_loop:
	move.l	fn_Pos(a3),d1			; bottom reached ?
	add.l	d2,d1
	cmp.l	d3,d1
	bhi	sfd_check_count
	move.l	MLN_SUCC(a3),a3			; get next node
	dbra	d0,sfd_loop

sfd_check_count:
	cmp.w	#1,d7				; paging ?
	bhi	sfd_paging

sfd_init_scroll:
	move.l	_con_rport,a0			; source rport
	move.l	a0,a1				; dest rport
	move.w	fr_Display+d_LeftEdge(a2),d0	; x1
	move.w	fr_Display+d_TopEdge(a2),d1	; y1
	move.w	d1,d3				; y2
	move.w	d0,d2				; x2
	move.w	fr_Display+d_Width(a2),d4	; width
	move.w	fr_Display+d_VisibleLines(a2),d5
	lsl.w	#3,d5				; height
	move.w	#$0c0,d6			; minterm
	cmp.b	#SCROLL_SPEED_SLOW,_vsh_scroll_speed
	beq	sfd_scroll_slow

sfd_scroll_normal:
	addq.w	#8,d1				; y1
	subq.w	#8,d5				; height
	CALLSYS	ClipBlit			; scroll one entry up
	bra	sfd_scroll_end

sfd_scroll_slow:
	PUSH	d7
	addq.w	#1,d1				; y1
	moveq	#8-1,d7				; d7 := count

1$:
	movem.w	d0-d6,-(sp)
	PUSH	a0-a1
	CALLSYS	ClipBlit			; scroll one scanline up
	PULL	a0-a1
	movem.w	(sp)+,d0-d6
	dbra	d7,1$
	PULL	d7

sfd_scroll_end:
	move.l	a3,a1				; a1 := node
	move.w	fr_Display+d_VisibleLines(a2),d0
	subq.w	#1,d0				; d0 := line
	move.w	d0,d1
	subq.w	#1,d1				; dec for dbra

sfd_get_last_line:
	move.l	MLN_SUCC(a1),a1			; get next node
	dbra	d1,sfd_get_last_line
	move.w	d7,d1				; d1 := count
	bra	sfd_print

sfd_paging:
	move.l	a3,a1				; a1 := node
	moveq	#0,d0				; d0 := line
	move.w	d7,d1				; d1 := count

sfd_print:
	move.l	a2,a0				; a0 := freq
	jsr	_print_freq_lines		; print new entry
	move.l	a3,fr_Display+d_FirstVisibleNode(a2)

sfd_draw_cursor:
	bsr	hcomp_freq_cursor		; draw new cursor line

sfd_exit:
	rts

;---------------------------------------------------------------------------
; VOID print_vreq_lines(vreq, node, line, count)
;			 a0    a1    d0    d1
;	struct ViewRequest  *vreq
;	struct LineNode     *node
;	USHORT line, count
; Print specified lines of text as ASCII or hex dump
;---------------------------------------------------------------------------
_print_vreq_lines:
	PUSH	d2-d7/a2-a3/a5-a6

	; --- init some regs
	move.l	a0,a2				; a2 := vreq
	move.l	a1,a3				; a3 := node ptr
	move.w	d0,d5				; d5 := line
	move.w	d1,d6				; d6 := count
	move.l	_con_rport,a5			; a5 := rast port
	move.l	_GfxBase,a6

	; --- set draw mode and colors
	moveq	#RP_JAM2,d0			; draw mode
	move.l	a5,a1
	CALLSYS	SetDrMd

	moveq	#COLOR1,d0			; front color
	move.l	a5,a1
	CALLSYS	SetAPen

	moveq	#COLOR0,d0			; back color
	move.l	a5,a1
	CALLSYS	SetBPen

	; --- init line buffer
	subq.w	#1,d6				; dec count for dbra
	move.w	vr_Mode(a2),d7			; d7 := mode
	lea	_line1_buffer,a5
	move.w	_max_line_len,d4		; max num of chars per line
	subq.w	#1,d4				; dec num -> only valid for ASCII dump
	tst.w	d7				; check mode -> bytes per line
	beq	pvl_loop
	move.b	#':',8(a5)			; insert delimiters in line buffer for hex dump
	move.b	#' ',d0
	move.b	d0,9(a5)
	move.b	d0,9+1*9(a5)
	move.b	d0,9+2*9(a5)
	move.b	d0,9+3*9(a5)
	move.b	d0,9+4*9(a5)
	lea	9+MAX_HEX_LONG_WORDS*9+1(a5),a6	; a6 := ASCII chars for hex dump
	move.b	#'"',(a6)+

pvl_loop:
	tst.l	MLN_SUCC(a3)			; end of list ?
	beq	pvl_exit
	bsr	build_text_line			; build line of ASCII or hex dump

	move.l	a5,a0				; text
	move.w	vr_Display+d_LeftEdge(a2),d0	; x
	move.w	d5,d1
	lsl.w	#3,d1				; d1 * 8
	add.w	vr_Display+d_TopEdge(a2),d1	; y
	bsr	write_text

	move.l	MLN_SUCC(a3),a3			; next node
	addq.w	#1,d5				; inc line counter
	dbra	d6,pvl_loop

pvl_exit:
	PULL	d2-d7/a2-a3/a5-a6
	rts

;---------------------------------------------------------------------------
; UBYTE *build_vreq_line(vreq, lnode, max_line_len)
;			  a0    a1         d0
;	struct ViewRequest  *vreq
;	struct LineNode     *lnode
;	USHORT max_line_len
; Build specified line of text as ASCII or hex dump and returns pointer
;---------------------------------------------------------------------------
_build_vreq_line:
	PUSH	d2-d7/a2-a3/a5-a6

	move.l	a0,a2				; a2 := vreq
	move.l	a1,a3				; a3 := node ptr
	move.w	d0,d4				; d4 := max num of chars per line
	beq	_bvl_no_max_line_len
	subq.w	#1,d4				; dec num -> only valid for ASCII dump

_bvl_no_max_line_len:
	move.w	vr_Mode(a2),d7			; d7 := mode
	lea	_line1_buffer,a5
	tst.w	d7				; check mode -> bytes per line
	beq	_bvl_ascii
	move.b	#':',8(a5)			; insert delimiters in line buffer for hex dump
	move.b	#' ',d0
	move.b	d0,9(a5)
	move.b	d0,9+1*9(a5)
	move.b	d0,9+2*9(a5)
	move.b	d0,9+3*9(a5)
	move.b	d0,9+4*9(a5)
	lea	9+MAX_HEX_LONG_WORDS*9+1(a5),a6	; a6 := ASCII chars for hex dump
	move.b	#'"',(a6)+

_bvl_ascii:
	bsr	build_text_line
	move.l	a5,d0				; return pointer to line

	PULL	d2-d7/a2-a3/a5-a6
	rts

;---------------------------------------------------------------------------
; Input : a2 := req ptr (view or history req)
;	  a3 := line node ptr
;	  a5 := line buffer ptr
;	  a6 := ASCII chars ptr for hex dump
;	  d4 := max num of chars per line
;	  d7 := view mode
; Build specified line of text as ASCII or hex dump
;---------------------------------------------------------------------------
build_text_line:
	move.l	ln_Line(a3),a0			; a0 := source ptr
	move.l	a5,a1				; a1 := dest ptr
	moveq	#0,d3				; reset char counter
	move.w	ln_LineLen(a3),d2		; d2 := num of bytes in line
	beq	btl_ascii_fill_line		; empty line ?
	subq.w	#1,d2				; dec num for dbra
	tst.w	d7				; check mode
	beq	btl_ascii_loop

btl_hex:
	move.l	ln_Offset(a3),d0		; insert relative position
	moveq	#8,d1
	bsr	bin_to_hex
	add.l	#2,a1				; start of first long word
	moveq	#4,d4				; load byte counter for first long word

btl_hex_loop:
	move.b	(a0)+,d0			; get byte from buffer

btl_insert_hex_byte:
	moveq	#2,d1
	bsr	bin_to_hex			; convert to hex
	subq.w	#1,d4				; dec byte counter for long word
	bne	btl_hex_check_ctrl_chars
	moveq	#4,d4				; load byte counter for next long word
	add.l	#1,a1				; start of next long word -> space as delimiter

btl_hex_check_ctrl_chars:
	move.b	d0,d1				; check for ctrl chars
	bclr	#7,d1
	cmp.b	#' ',d1
	bhs	btl_hex_check_alternate_char

btl_hex_ctrl_char:
	move.b	#31,d0				; replace by ctrl char symbol
	cmp.b	#DUMP_MODE_ALL_CHARS,_vsh_dump_mode	; dump all chars ?
	beq	btl_hex_insert_ascii
	move.b	#'.',d0				; replace by '.' char
	bra	btl_hex_insert_ascii

btl_hex_check_alternate_char:
	cmp.b	#'~',d0				; check if ASCII char
	bls	btl_hex_insert_ascii
	cmp.b	#DUMP_MODE_ASCII_CHARS,_vsh_dump_mode	; dump only ASCII chars ?
	bne	btl_hex_insert_ascii
	move.b	#'.',d0				; replace by '.' char

btl_hex_insert_ascii:
	move.b	d0,(a6,d3.w)			; write ASCII char
	addq.w	#1,d3
	dbra	d2,btl_hex_loop			; next hex byte
	cmp.w	#MAX_HEX_LONG_WORDS*4,d3	; line completely filled ?
	blo	btl_hex_fill_line
	lea	(a6,d3.w),a1			; get end of line
	move.b	#'"',(a1)+
	bra	btl_exit

btl_hex_fill_line:
	moveq	#' ',d0
	move.l	a6,d1				; calc num of spaces to fill
	sub.l	a1,d1
	subq.l	#2,d1

btl_hex_fill_loop1:				; fill with spaces
	move.b	d0,(a1)+
	dbra	d1,btl_hex_fill_loop1
	lea	(a6,d3.w),a1
	move.b	#'"',(a1)+

btl_hex_fill_loop2:				; fill with spaces
	move.b	d0,(a1)+
	addq.w	#1,d3
	cmp.w	#MAX_HEX_LONG_WORDS*4,d3
	blo	btl_hex_fill_loop2
	bra	btl_exit

****************************************************************************

btl_ascii_loop:
	move.b	(a0)+,d0			; get char from buffer
	beq	btl_ascii_ctrl_char

btl_ascii_tab:
	cmp.b	#9,d0				; tab ?
	bne	btl_ascii_check_ctrl_char
	move.b	#' ',d0				; default tabskip = 8
	move.w	d3,d1				; calc num of spaces to fill
	not.w	d1
	and.w	#7,d1

btl_ascii_tab_loop:
	move.b	d0,(a1)+			; expand tab to spaces
	addq.w	#1,d3
	tst.w	d4				; max line len given ?
	beq	btl_ascii_tab_no_max_line_len
	cmp.w	d4,d3				; end of line ?
	bhi	btl_exit

btl_ascii_tab_no_max_line_len:
	dbra	d1,btl_ascii_tab_loop
	bra	btl_ascii_next

btl_ascii_check_ctrl_char:
	move.b	d0,d1				; check for ctrl chars
	bclr	#7,d1
	cmp.b	#' ',d1
	bhs	btl_ascii_check_alternate_char

btl_ascii_ctrl_char:
	moveq	#31,d0				; replace by ctrl char symbol
	cmp.b	#DUMP_MODE_ALL_CHARS,_vsh_dump_mode	; dump all chars ?
	beq	btl_ascii_insert_ascii
	move.b	#'.',d0				; replace by '.' char
	bra	btl_ascii_insert_ascii

btl_ascii_check_alternate_char:
	cmp.b	#'~',d0				; check if ASCII char
	bls	btl_ascii_insert_ascii
	cmp.b	#DUMP_MODE_ASCII_CHARS,_vsh_dump_mode	; dump only ASCII chars ?
	bne	btl_ascii_insert_ascii
	move.b	#'.',d0				; replace by '.' char

btl_ascii_insert_ascii:
	move.b	d0,(a1)+			; copy normal char
	addq.w	#1,d3

btl_ascii_next:
	dbra	d2,btl_ascii_loop		; next ASCII byte

btl_ascii_fill_line:
	tst.w	d4				; max line len given ?
	beq	btl_exit
	cmp.w	d4,d3				; line completely filled ?
	bhi	btl_exit
	move.w	d4,d1				; calc num of spaces to fill
	sub.w	d3,d1
	moveq	#' ',d0

btl_ascii_fill_loop:
	move.b	d0,(a1)+			; fill rest of line with spaces
	dbra	d1,btl_ascii_fill_loop

btl_exit:
	clr.b	(a1)				; set end of string
	rts

;---------------------------------------------------------------------------
; Input: d0.l = binary number
;	 d1.w = num of hex digits
;	 a1   = buffer ptr
; Convert binary number to ASCII digits representing the hex value
;---------------------------------------------------------------------------
bin_to_hex:
	PUSH	d0/d2/d3
	move.w	d1,d3				; save num of hex digits
	subq.w	#1,d1				; dec digit counter for dbra

bth_loop:
	move.b	d0,d2
	and.b	#15,d2				; mask lower nibble
	cmp.b	#9,d2
	bhi	1$
	add.b	#'0',d2
	bra	bth_write_nibble

1$:
	add.b	#'A'-10,d2

bth_write_nibble:
	move.b	d2,(a1,d1.w)			; write size char to buffer
	asr.l	#4,d0				; next nibble
	dbra	d1,bth_loop
	add.w	d3,a1				; set new buffer ptr
	PULL	d0/d2/d3
	rts

;---------------------------------------------------------------------------
; VOID hcomp_vreq_line(vreq, line)
;			a0    d0
;	struct ViewRequest  *vreq
;	USHORT line
; Highlight or de-highlight selected line in viewrequester
;---------------------------------------------------------------------------
_hcomp_vreq_line:
	PUSH	d2-d3/a2-a3/a6

	tst.b	_show_flag			; hidden display ?
	beq	hvl_exit	
	move.l	a0,a2				; a2 := vreq
	move.w	d0,d2				; d2 := line

	; --- set draw mode
	move.l	_con_rport,a3			; rastport
	move.l	_GfxBase,a6
	moveq	#RP_COMPLEMENT,d0		; draw mode
	move.l	a3,a1
	CALLSYS	SetDrMd

	; --- init some regs
	moveq	#0,d0
	move.w	vr_Display+d_LeftEdge(a2),d0	; x1
	move.w	vr_Display+d_TopEdge(a2),d1
	lsl.w	#3,d2				; d2 * 8
	add.w	d2,d1				; y1
	cmp.w	#VIEW_MODE_HEX,vr_Mode(a2)	; hex dump ?
	beq	hvl_hex_dump

hvl_ascii_dump:
	move.w	vr_Display+d_Width(a2),d2
	bra	hvl_calc_width

hvl_hex_dump:
	move.w	#(9+MAX_HEX_LONG_WORDS*9+2+MAX_HEX_LONG_WORDS*4+1)*8,d2

hvl_calc_width:
	add.w	d0,d2				; x2
	subq.w	#1,d2
	move.w	d1,d3
	addq.w	#8-1,d3				; y2
	move.l	a3,a1
	CALLSYS	RectFill

	moveq	#RP_JAM2,d0			; draw mode
	move.l	a3,a1
	CALLSYS	SetDrMd

hvl_exit:
	PULL	d2-d3/a2-a3/a6
	rts

;---------------------------------------------------------------------------
; VOID scroll_view_req()
; Scroll line list of viewed text
;---------------------------------------------------------------------------
_scroll_view_req:
	PUSH	d2-d7/a2-a3/a6			; save regs for scrolling routines

	lea	_view_req,a2			; a2 := view req ptr
	tst.b	_scroll_flag			; check scroll flag
	beq	svr_exit
	moveq	#0,d0				; num of entries > visible lines ?
	move.w	vr_Display+d_VisibleLines(a2),d0
	cmp.l	vr_Display+d_NumEntries(a2),d0
	bhs	svr_exit

svr_auto_repeat_loop:
	move.l	_GfxBase,a6
	move.b	_scroll_flag,d1
	bclr	#7,d1				; top or bottom ?
	bne	svr_scroll_all
	moveq	#1,d7				; scroll count = 1
	bclr	#6,d1				; page up or down ?
	beq	svr_scroll_part
	move.w	vr_Display+d_VisibleLines(a2),d7	; scroll count = lines

svr_scroll_part:
	bclr	#0,d1				; scroll up ?
	bne	svr_scroll_part_up
	bclr	#1,d1				; scroll down ?
	beq	svr_exit

svr_scroll_part_down:
	bsr	scroll_vreq_down
	bra	svr_print_vreq_status

svr_scroll_part_up:
	bsr	scroll_vreq_up
	bra	svr_print_vreq_status

svr_scroll_all:
	move.l	vr_Display+d_List(a2),a0	; a0 := line list ptr
	btst	#0,d1				; scroll up ?
	beq	svr_scroll_all_down

svr_scroll_all_up:
	move.l	MLH_HEAD(a0),a0
	bra	svr_scroll_all_print

svr_scroll_all_down:
	move.l	MLH_TAILPRED(a0),a0
	move.w	vr_Display+d_VisibleLines(a2),d0	; reload line count
	subq.w	#2,d0				; dec line count for dbra

1$:
	move.l	MLN_PRED(a0),a0
	dbra	d0,1$

svr_scroll_all_print:
	move.l	a0,vr_Display+d_FirstVisibleNode(a2)
	move.l	a0,a1					; a1 := node
	move.l	a2,a0					; a0 := vreq
	moveq	#0,d0					; d0 := line
	move.w	vr_Display+d_VisibleLines(a2),d1	; d1 := count
	jsr	_print_vreq_lines			; print whole page

svr_print_vreq_status:
	move.l	a2,a0				; a0 := vreq
	jsr	_print_vreq_status		; print new status

svr_check_auto_repeat:
	cmp.b	#SCROLL_SPEED_FAST,_vsh_scroll_speed	; fast scrolling ?
	bne	svr_exit
	tst.b	_auto_repeat			; auto_repeat ?
	beq	svr_exit
	tst.b	_scroll_flag			; check scroll flag
	bne	svr_auto_repeat_loop

svr_exit:
	PULL	d2-d7/a2-a3/a6
	rts

;---------------------------------------------------------------------------
; Input :  a2   = vreq ptr
;	   a6   = GfxBase
;	   d7.w = scroll count
; Scroll text of typed file count times up
;---------------------------------------------------------------------------
scroll_vreq_up:
	move.l	vr_Display+d_FirstVisibleNode(a2),a3
	cmp.l	#1,ln_Pos(a3)			; alreday at top ?
	beq	svu_exit
	move.w	d7,d0				; d0 := scroll count
	subq.w	#1,d0				; dec count for dbra

svu_loop:
	cmp.l	#1,ln_Pos(a3)			; top reached ?
	beq	svu_check_count
	move.l	MLN_PRED(a3),a3			; get previous node
	dbra	d0,svu_loop

svu_check_count:
	cmp.w	#1,d7				; paging ?
	bhi	svu_paging

svu_init_scroll:
	move.l	_con_rport,a0			; source rport
	move.l	a0,a1				; dest rport
	move.w	fr_Display+d_LeftEdge(a2),d0	; x1
	move.w	fr_Display+d_TopEdge(a2),d1	; y1
	move.w	d1,d3				; y2
	move.w	d0,d2				; x2
	move.w	fr_Display+d_Width(a2),d4	; width
	move.w	fr_Display+d_VisibleLines(a2),d5
	lsl.w	#3,d5				; height
	move.w	#$0c0,d6			; minterm
	cmp.b	#SCROLL_SPEED_SLOW,_vsh_scroll_speed
	beq	svu_scroll_slow

svu_scroll_normal:
	addq.w	#8,d3				; y2
	subq.w	#8,d5				; height
	CALLSYS	ClipBlit			; scroll one entry up
	bra	svu_paging

svu_scroll_slow:
	PUSH	d7
	subq.w	#1,d1				; y1
	moveq	#8-1,d7				; d7 := count

1$:
	movem.w	d0-d6,-(sp)
	PUSH	a0-a1
	CALLSYS	ClipBlit			; scroll one scanline up
	PULL	a0-a1
	movem.w	(sp)+,d0-d6
	dbra	d7,1$
	PULL	d7

svu_paging:
	move.l	a2,a0				; a0 := vreq
	move.l	a3,a1				; a1 := node
	moveq	#0,d0				; d0 := line
	move.w	d7,d1				; d1 := count
	jsr	_print_vreq_lines		; print first line
	move.l	a3,vr_Display+d_FirstVisibleNode(a2)

svu_exit:
	rts

;---------------------------------------------------------------------------
; Input :  a2   = vreq ptr
;	   a6   = GfxBase
;	   d7.w = scroll count
; Scroll text of typed file count times down
;---------------------------------------------------------------------------
scroll_vreq_down:
	moveq	#0,d2
	move.w	vr_Display+d_VisibleLines(a2),d2	; d2 := visible lines
	move.l	vr_Display+d_NumEntries(a2),d3		; d3 := number of entries
	move.l	vr_Display+d_FirstVisibleNode(a2),a3
	move.l	ln_Pos(a3),d1			; already at bottom ?
	add.l	d2,d1
	cmp.l	d3,d1
	bhi	svd_exit
	move.w	d7,d0				; d0 := scroll count
	subq.w	#1,d0				; dec count for dbra

svd_loop:
	move.l	ln_Pos(a3),d1			; bottom reached ?
	add.l	d2,d1
	cmp.l	d3,d1
	bhi	svd_check_count
	move.l	MLN_SUCC(a3),a3			; get next node
	dbra	d0,svd_loop

svd_check_count:
	cmp.w	#1,d7				; paging ?
	bhi	svd_paging

svd_init_scroll:
	move.l	_con_rport,a0			; source rport
	move.l	a0,a1				; dest rport
	move.w	fr_Display+d_LeftEdge(a2),d0	; x1
	move.w	fr_Display+d_TopEdge(a2),d1	; y1
	move.w	d1,d3				; y2
	move.w	d0,d2				; x2
	move.w	fr_Display+d_Width(a2),d4	; width
	move.w	fr_Display+d_VisibleLines(a2),d5
	lsl.w	#3,d5				; height
	move.w	#$0c0,d6			; minterm
	cmp.b	#SCROLL_SPEED_SLOW,_vsh_scroll_speed
	beq	svd_scroll_slow

svd_scroll_normal:
	addq.w	#8,d1				; y1
	subq.w	#8,d5				; height
	CALLSYS	ClipBlit			; scroll one entry up
	bra	svd_scroll_end

svd_scroll_slow:
	PUSH	d7
	addq.w	#1,d1				; y1
	moveq	#8-1,d7				; d7 := count

1$:
	movem.w	d0-d6,-(sp)
	PUSH	a0-a1
	CALLSYS	ClipBlit			; scroll one scanline up
	PULL	a0-a1
	movem.w	(sp)+,d0-d6
	dbra	d7,1$
	PULL	d7

svd_scroll_end:
	move.l	a3,a1				; a1 := node
	move.w	vr_Display+d_VisibleLines(a2),d0
	subq.w	#1,d0				; d0 := line
	move.w	d0,d1
	subq.w	#1,d1				; dec line num for dbra

svd_get_last_line:
	move.l	MLN_SUCC(a1),a1			; get next node
	dbra	d1,svd_get_last_line
	moveq	#1,d1				; d1 := count
	bra	svd_print

svd_paging:
	moveq	#0,d0				; d0 := line
	move.w	d7,d1				; d1 := count
	move.l	a3,a1				; a1 := node

svd_print:
	move.l	a2,a0				; a0 := vreq
	jsr	_print_vreq_lines		; print first line
	move.l	a3,vr_Display+d_FirstVisibleNode(a2)

svd_exit:
	rts

;---------------------------------------------------------------------------
; VOID print_quick_view_lines(freq, buffer, len)
;			       a0     a1    d0
;	struct FileRequest  *freq
;	BYTE   *buffer
;	USHORT len
; Print quick view lines from buffer to specified file requester
;---------------------------------------------------------------------------
_print_quick_view_lines:
	PUSH	d2-d6/a2-a3/a5-a6

	tst.b	_show_flag			; hidden display ?
	beq	pqvl_exit

	; --- init some regs
	move.l	a0,a2				; a2 := freq
	move.l	a1,a3				; a3 := buffer ptr
	move.w	d0,d3				; d3 := len
	move.l	_con_rport,a5			; a5 := rast port
	move.l	_GfxBase,a6

	; --- set draw mode and colors
	moveq	#RP_JAM2,d0			; draw mode
	move.l	a5,a1
	CALLSYS	SetDrMd

	moveq	#COLOR1,d0			; front color
	move.l	a5,a1
	CALLSYS	SetAPen

	moveq	#COLOR0,d0			; back color
	move.l	a5,a1
	CALLSYS	SetBPen

	; --- init line buffer
	moveq	#0,d2				; d2 := line counter
	tst.w	d3				; len == 0 ?
	beq	pqvl_clear
	lea	_line1_buffer,a5
	move.b	#' ',d0				; insert delimiters in line buffer for hex dump
	move.b	d0,8(a5)
	move.b	d0,8+1*9(a5)
	move.b	d0,8+2*9(a5)
	lea	MAX_QVIEW_LONG_WORDS*9(a5),a6	; a6 := ASCII chars for hex dump
	clr.b	MAX_QVIEW_LONG_WORDS*4(a6)	; mark end of string

pqvl_print_loop:
	move.l	a5,a1				; a1 := dest ptr
	moveq	#0,d4				; reset char counter
	moveq	#MAX_QVIEW_LONG_WORDS*4-1,d5	; d5 := num of bytes in line - 1
	moveq	#4,d6				; load byte counter for first long word

pqvl_line_loop:
	tst.w	d3				; end of text ?
	beq	pqvl_end_of_line
	move.b	(a3)+,d0			; get byte from buffer
	subq.w	#1,d3				; dec len

pqvl_insert_hex_byte:
	moveq	#2,d1
	bsr	bin_to_hex			; convert to hex
	subq.w	#1,d6				; dec byte counter for long word
	bne	pqvl_check_ctrl_char
	moveq	#4,d6				; load byte counter for next long word
	add.l	#1,a1				; start of next long word -> space as delimiter

pqvl_check_ctrl_char:
	move.b	d0,d1				; check for ctrl chars
	bclr	#7,d1
	cmp.b	#' ',d1
	bhs	pqvl_check_alternate_char

pqvl_ctrl_char:
	moveq	#31,d0				; replace by ctrl char symbol
	cmp.b	#DUMP_MODE_ALL_CHARS,_vsh_dump_mode	; dump all chars ?
	beq	pqvl_insert_ascii
	move.b	#'.',d0				; replace by '.' char
	bra	pqvl_insert_ascii

pqvl_check_alternate_char:
	cmp.b	#'~',d0				; check if ASCII char
	bls	pqvl_insert_ascii
	cmp.b	#DUMP_MODE_ASCII_CHARS,_vsh_dump_mode	; dump only ASCII chars ?
	bne	pqvl_insert_ascii
	move.b	#'.',d0				; replace by '.' char

pqvl_insert_ascii:
	move.b	d0,(a6,d4.w)			; write ASCII char
	addq.w	#1,d4
	dbra	d5,pqvl_line_loop		; next hex byte

pqvl_end_of_line:
	cmp.w	#MAX_QVIEW_LONG_WORDS*4,d4	; line completely filled ?
	bhs	pqvl_print_line

pqvl_fill_line:
	moveq	#' ',d0
	move.l	a6,d1				; calc num of spaces to fill
	sub.l	a1,d1
	subq.l	#2,d1

pqvl_fill_loop1:				; fill with spaces
	move.b	d0,(a1)+
	dbra	d1,pqvl_fill_loop1
	lea	(a6,d4.w),a1

pqvl_fill_loop2:				; fill with spaces
	move.b	d0,(a1)+
	addq.w	#1,d4
	cmp.w	#MAX_QVIEW_LONG_WORDS*4,d4
	blo	pqvl_fill_loop2

pqvl_print_line:
	move.l	a5,a0				; text
	move.w	fr_Display+d_LeftEdge(a2),d0	; x
	move.w	d2,d1
	lsl.w	#3,d1				; d0 * 8
	add.w	fr_Display+d_TopEdge(a2),d1	; y
	bsr	write_text

	addq.w	#1,d2				; inc line
	tst.w	d3				; end of text ?
	bne	pqvl_print_loop
	cmp.w	fr_Display+d_VisibleLines(a2),d2	; last line ?
	bhs	pqvl_exit

pqvl_clear:
	; --- clear empty area
	move.l	_con_rport,a5			; a5 := rast port
	move.l	_GfxBase,a6

	moveq	#COLOR0,d0			; fill color
	move.l	a5,a1
	CALLSYS	SetAPen

	move.w	fr_Display+d_LeftEdge(a2),d0	; x1
	move.w	d2,d1
	lsl.w	#3,d1				; d1 * 8
	add.w	fr_Display+d_TopEdge(a2),d1	; y1
	move.w	fr_Display+d_VisibleLines(a2),d3
	sub.w	d2,d3
	lsl.w	#3,d3				; d3 * 8
	add.w	d1,d3				; y2
	move.w	d0,d2
	add.w	#MAX_FREQ_LINE_WIDTH,d2		; x2
	move.l	a5,a1
	CALLSYS	RectFill

pqvl_exit:
	PULL	d2-d6/a2-a3/a5-a6
	rts
