	section	Sort90,CODE
	IDNT	ALL

**	Sort90
**		for sorting lines on the first byte in the line
**
**		Copyright ©1990 DigiSoft
**
**	Permission is granted to purchasers of Macro68 to modify this source
**	file.  Permission is further granted to distribute the source code that
**	they have modified subject to the following conditions:
**	1.  That the original, unaltered, source is included with the
**	    distribution.
**	2.  That no charge is made for the distribution, other than the cost of
**	    media.                    (Distribution via Fred Fish is permitted)
**	3.  That my copyright notice remains as part of this and any other
**	    file adapted from this file.
**                                               Paul Coward
**                                                         DigiSoft
**
**	Tabstops : 8
**	Assemble with Macro68

**	18-06-90	** written


		OBJFILE		"ram:Sort90"
	;	ERRORFILE	"ram:Sort90.bugs"

	;	PALL
	;	HALL
		EXEOBJ
	;	LIST
	;	LISTSYMS
	;	ADDSYM
	;	LISTFILE	"ram:Sort90.lst"
	;	CREFFILE	"ram:Sort90.cref"
	;	DEBUG
	;	REALTIME
		STRICT


	ifnd	EXEC_TYPES_I
	if1
	PRINTX	Resident maclib not in use.
	endc
_AbsExecBase		equ	4
_LVOAlert		equ	-108	;exec
_LVOCloseLibrary	equ	-414	;exec
_LVOOpenLibrary		equ	-552	;exec
AT_Recovery		equ	$00000000
AG_OpenLib		equ	$00030000
MODE_OLDFILE		equ	1005
MODE_NEWFILE		equ	1006
	endc


_LVOdsAllocCPremember	equ	-30
_LVOdsAllocScratch	equ	-42
_LVOdsClearRemember	equ	-66
_LVOdsDosClose		equ	-414
_LVOdsDosOpen		equ	-408
_LVOdsDosRead		equ	-858
_LVOdsDosWrite		equ	-864
_LVOdsFileSize		equ	-162
_LVOdsFreeScratch	equ	-174
_LVOdsParse		equ	-216
_LVOdsPuts		equ	-648
_LVOdsStrLen		equ	-288


csd_RememberKey		equ	84	
csd_Args		equ	88		;8 bytes required
csd_FileStart		equ	96
csd_LineCount		equ	100		;.l
csd_SortedLineList	equ	104		;.l
csd_SIZEOF		equ	108


	ifnd	Tab
AO_DSSLib		equ	$00008099	;alert number id support library can't be opened
Tab			equ	$09
Lf			equ	$0a
CSI			equ	$9b
	endc

Release			equ	'1.0 '
VerNo			equ	'0.02'

*************************
*	COLD ENTRY	*
*************************


START:		moveq		#0,d3
		move.l		a0,d6
		move.l		d0,d7
		movea.l		(_AbsExecBase).w,a6	;establish exec for calls

	; --- open the support library

		moveq		#2,d0			;version #
		lea	 	(supportLibName,pc),a1	;point to liberary name
		jsr		(_LVOOpenLibrary,a6)	;exec
		tst.l		d0
		bne.b		1$
		move.l		#AT_Recovery!AG_OpenLib!AO_DSSLib,d7
		jsr		(_LVOAlert,a6)
		bra		Exit_To_DOS

	; --- initialize the scratch area

1$		movea.l		d0,a6
		moveq		#csd_SIZEOF,d0
		moveq		#33,d1
		moveq		#0,d2
		jsr		(_LVOdsAllocScratch,a6)
		bne		Exit_To_DOS

	; --- initialize the argument pointers

		movem.l		d6-d7,(csd_Args,a5)	;& a_Length(A0)

	; --- display banner

		lea		(Title,pc),a1
		jsr		(_LVOdsPuts,a6)

	; --- parse args

		lea		(csd_RememberKey,a5),a0
		move.l		#256,d0
		jsr		(_LVOdsAllocCPremember,a6)
		move.l		d0,(ArgPointers).l
		beq		InsufficientMemory

		lea		(csd_Args,a5),a0
		lea		(additionalHelp,pc),a1
		lea		(ArgPointers+4,pc),a2
		lea		(CmdTemplate,pc),a3
		jsr		(_LVOdsParse,a6)
		bpl.b		configure
		movea.l		(ArgPointers,pc),a1
		jsr		(_LVOdsPuts,a6)
		lea		(csd_RememberKey,a5),a0
		jsr		(_LVOdsClearRemember,a6)
		bra		exitWithError

	; --- any filename args ?

configure:	move.l		(sourceFileName,pc),d1
		beq		exitWithError
		move.l		#MODE_OLDFILE,d2
		jsr		(_LVOdsDosOpen,a6)
		beq		exitWithError
		move.l		d0,d1
		jsr		(_LVOdsFileSize,a6)
		move.l		d0,d3			;save file size
		addq.l		#8,d0			;+ some for termination
		lea		(csd_RememberKey,a5),a0
		jsr		(_LVOdsAllocCPremember,a6)
		beq		InsufficientMemory
		move.l		d0,(csd_FileStart,a5)
		move.l		d0,d2
		jsr		(_LVOdsDosRead,a6)
		bne		exitWithFileError
		jsr		(_LVOdsDosClose,a6)

	; --- modify the file

		bsr		SortTheFile

	; --- and write it back out

		move.l		(targetFileName,pc),d1
		beq		exitWithError
		move.l		#MODE_NEWFILE,d2
		jsr		(_LVOdsDosOpen,a6)
		beq		exitWithError
		move.l		d0,d1

		move.l		(csd_LineCount,a5),d4
		movea.l		(csd_SortedLineList,a5),a2
.write:		move.l		(a2)+,d2
		movea.l		d2,a0
		jsr		(_LVOdsStrLen,a6)
		move.l		d0,d3
		jsr		(_LVOdsDosWrite,a6)
		bne		exitWithFileError
		move.l		#Lf_Msg,d2
		moveq		#1,d3
		jsr		(_LVOdsDosWrite,a6)
		subq.l		#1,d4
		bne.b		.write
		jsr		(_LVOdsDosClose,a6)

EXIT:		lea		(csd_RememberKey,a5),a0
		jsr		(_LVOdsClearRemember,a6)
Exit_To_DOS:	jsr		(_LVOdsFreeScratch,a6)
		movea.l		a6,a1
		movea.l		(4).w,a6
		jsr		(_LVOCloseLibrary,a6)
		moveq		#0,d0
		rts					;exit to DOS


	; --- error detected during start - exit gracefully

exitWithFileError:
		jsr		(_LVOdsDosClose,a6)
		lea		(IOError_Msg,pc),a1
		jsr		(_LVOdsPuts,a6)
		bra		EXIT


exitWithError:	lea		(InitError_Msg,pc),a1
		jsr		(_LVOdsPuts,a6)
		bra		EXIT


InsufficientMemory:
		lea		(InsufficientMemory_Msg,pc),a1
		jsr		(_LVOdsPuts,a6)
		bra		EXIT


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


SortTheFile:	lea		(sortingLinesMsg,pc),a1
		jsr		(_LVOdsPuts,a6)
		moveq		#0,d4
		movea.l		d2,a2			;file start
.nextLine:	move.b		(a2)+,d0
		beq.b		.linesCounted
		cmpi.b		#Lf,d0
		bne.b		.nextLine
		clr.b		(-1,a2)			;null term each line
		addq.l		#1,d4
		bra.b		.nextLine

.linesCounted:	move.l		d4,(csd_LineCount,a5)
		beq.b		exitWithFileError
		move.l		d4,d0
		lsl.l		#2,d0			;# of bytes need for sorting table
		addq.l		#8,d0			;+ some for table termination
		moveq		#0,d1			;any memory
		lea		(csd_RememberKey,a5),a0
		jsr		(_LVOdsAllocCPremember,a6)
		beq		InsufficientMemory
		move.l		d0,(csd_SortedLineList,a5)
		movea.l		d2,a2			;file start
		movea.l		d0,a3
		movea.l		d0,a4
		bra.b		.startTable

.findNextLine:	tst.b		(a2)+
		bne.b		.findNextLine
.startTable:	move.l		a2,(a4)+
		subq.l		#1,d4
		bne.b		.findNextLine

.linesInTable:	moveq		#0,d0
		move.l		a4,d1
		sub.l		a3,d1
		lsr.l		#2,d1
		subq.l		#1,d1

;Sort array in ascending order using quick sort
;Entry - a3 = pointer to the index buffer
;        d0 = lo
;        d1 = hi

quick_sort:	pushm.l		d0-d6/a1-a2	;save registers
		cmp.l		d1,d0		;lo<hi ?
		bge.b		quick_end
		move.l		d0,d2		;d2 = i
		move.l		d1,d3		;d3 = j
		exg		d0,d4		;lo in d4
		exg		d1,d5		;hi in d5
		move.l		d3,d6		;d6 = pivline
quick_lp1:	cmp.l		d3,d2		;i<j
		bge.b		quick_lp2
		move.l		d2,d0
		bsr.b		compare
		bgt.b		quick_lp2
		addq.l		#1,d2		;i+1
		bra.b		quick_lp1
quick_lp2:	cmp.l		d2,d3
		ble.b		quick_jmp2
		move.l		d3,d0
		bsr.b		compare
		blt.b		quick_jmp2
		subq.l		#1,d3		;j=j-1
		bra.b		quick_lp2
quick_jmp2:	cmp.l		d2,d3		;i>=j
		ble.b		quick_jmp3	;out of order pair
		move.l		d2,d0
		move.l		d3,d1
		bsr.b		exchange
quick_jmp3:	cmp.l		d2,d3
		bgt.b		quick_lp1
		move.l		d2,d0
		move.l		d5,d1
		bsr.b		exchange	;move pivot to i
		move.l		d5,d0		;hi
		sub.l		d2,d0		;hi-i
		add.l		d4,d0		;hi-i+lo
		sub.l		d2,d0		;(hi-i)-(i-lo)
		ble.b		quick_jmp4
		move.l		d4,d0		;lo
		move.l		d2,d1
		subq.l		#1,d1		;i-1
		bsr.b		quick_sort
		move.l		d2,d0
		addq.l		#1,d0		;i+1
		move.l		d5,d1		;hi
		bsr.b		quick_sort
		bra.b		quick_end
quick_jmp4:	move.l		d2,d0
		addq.l		#1,d0		;i+1
		move.l		d5,d1		;hi
		bsr.b		quick_sort
		move.l		d4,d0		;lo
		move.l		d2,d1
		subq.l		#1,d1		;i-1
		bsr.b		quick_sort
quick_end:	popm.l		d0-d6/a1-a2
		rts

;Compares two strings i and p (pivot).  Return flags only.
;Entry  - a1 = pointer to pivot
;         a3 = pointer to index buffer
;         d0 = ith element in the
;         d6 = pivot element
;Exit     Flags set according to i cmp p
;Used     a2, CCR

compare:	pushm.l		d0-d2/d6/a1
		lsl.l		#2,d6
		movea.l		(0,a3,d6.l),a1		;pointer to pivot
		lsl.l		#2,d0
		movea.l		(0,a3,d0.l),a2
compare_jp2:	move.b		(a1)+,d0
		beq.b		1$
		move.b		(a2)+,d1
		beq.b		2$
		cmp.b		d0,d1
		beq.b		compare_jp2
		bra.b		compare_exit
1$		tst.b		(a2)
		bra.b		compare_exit
2$		tst.b		(a1)
compare_exit:	popm.l		d0-d2/d6/a1
		rts


;Exchange i and j elements of array structure
;Entry - a3 = pointer to the index buffer
;        d0 = element i
;        d1 = element j
;Exit  - NONE
;Used  - a2

exchange:	pushm.l		d0/a3
		movea.l		a3,a2
		lsl.l		#2,d0
		lsl.l		#2,d1
		adda.l		d0,a3
		adda.l		d1,a2
		move.l		(a3),d0
		move.l		(a2),(a3)
		move.l		d0,(a2)
		popm.l		d0/a3
		rts


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


ArgPointers:	dl	0
sourceFileName:	dl	0		;pointer to filename
targetFileName:	dl	0		;pointer to filename


CmdTemplate:
	db	'SOURCEFILE/A,TARGETFILE/A',0


additionalHelp:
	db	'USAGE:',Lf
	db	'Sort90 SourceFile.asm TargetFile.asm',Lf,Lf,0


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


supportLibName:
	db	'digisoftSupport.library',0


	oddok
Title:	db	CSI,$35,';',$33,$33,'m'			;set graphic rendition
	db	'Sort90  '
	db	'Release '
	dl	Release
	db	' Vers '
	dl	VerNo
	db	' CopyRight © DIGISOFT',Lf
	db	CSI,$30,';',$33,$31,'m'			;reset graphic rendition
	db	'  12 Dinmore St.  Moorooka 4105  Brisbane, QLD  Australia',Lf
	db	'       Phone  ISD (617) 277-3255  STD (07) 277-3255'
	db	0
	odderror


sortingLinesMsg:
	db	Lf
	db	'Sorting - Please wait',Lf,0

InitError_Msg:
	db	Lf
	db	CSI,$35,';',$33,$33,'m'			;set graphic rendition
	db	'INITIALIZATION ERROR !!!',Lf
	db	Tab,Tab,'Bad command line OR Insufficient memory!'
	db	CSI,$30,';',$33,$31,'m'			;reset graphic rendition
Lf_Msg:	db	Lf


InsufficientMemory_Msg:
	db	Lf
	db	CSI,$35,';',$33,$33,'m'			;set graphic rendition
	db	'IO ERROR !!!',Lf
	db	Tab,Tab,'Insufficient memory!'
	db	CSI,$30,';',$33,$31,'m'			;reset graphic rendition
	db	Lf


IOError_Msg:
	db	Lf
	db	CSI,$35,';',$33,$33,'m'			;set graphic rendition
	db	'IO ERROR !!!',Lf
	db	Tab,Tab,'File read/write error!'
	db	CSI,$30,';',$33,$31,'m'			;reset graphic rendition
	db	Lf


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

	END
