;##############################################################################
;
; $VER: MASS_source 1.1.017 (13.4.1995) Rudla Kudla
;
;##############################################################################

;TestInput

ERROR_NODOSLIB	=20

		INCDIR	"INCLUDES:"
		INCLUDE	"exec/macros.i"
		INCLUDE	"exec/exec_lib.i"
		INCLUDE	"dos/dos_lib.i"
		INCLUDE	"dos/dos.i"	

LINE		equr	a2
BUFFER		equr	a3
ASSNAME		equr	d5
SPACE		equr	d6
TYPE		equr	d7

		IFD	TestInput
		;In real input, we will get $A ended string in a0 and it's
		;lenght (+1 for $A) in d0. This is simulated here for testing.

		lea	Test(pc),a0
		move.l	#EndTest-Test,d0
		ENDC

;======	Allocate local variables on stack, init input line and some registers

		move.l	a0,LINE
		clr.b	-1(a0,d0.w)		;zero end input string
		moveq	#' ',SPACE

;======	Open Dos library

		move.l	4.w,a6
		lea	dos_name(pc),a1
		moveq	#36,d0
		JSRLIB	OpenLibrary
		move.l	d0,a6
		tst.l	d0
		bne.b	.dos_ok
		moveq	#ERROR_NODOSLIB,d0
		rts

;------	This code is called from different places to exit (closes dos.library)

.end
		move.l	a6,a1
		move.l	4.w,a6
		JSRLIB	CloseLibrary
		moveq	#0,d0
		rts
.dos_ok

;======	Read string (it can be command, assign name or directory path)

.LIST		equr	a4
.RESULT		equr	d2

		moveq	#0,.RESULT
.command	move.l	.RESULT,TYPE
.lock
		bsr.w	GetString		;read first word
		beq.b	.end

;======	Test, if this is command (compare it with list of commands)

		lea	command_list(pc),.LIST
		moveq	#2,.RESULT
		bra.b	.test_list_end
		
.compare_list	move.l	BUFFER,a0
.compare_item	tst.b	(.LIST)
		beq.b	.command
		move.b	(a0)+,d0
		or.b	SPACE,d0
		cmp.b	(.LIST)+,d0
		beq.b	.compare_item

.next_item	tst.b	(.LIST)+
		bne.b	.next_item
		addq.w	#2,.RESULT

.test_list_end	tst.b	(.LIST)
		bne.b	.compare_list

;======	This is not an command, so it must be assign name or path
;	If it is ended with ":", it is assign name, otherwise it is directory
;	path.

.not_command
		moveq	#":",d0
		cmp.b	-2(LINE),d0		;assign name ends with ":"
		beq.b	.double
		moveq	#8,TYPE			;makedir type
		bra.b	.makedir
.double
		clr.b	-2(LINE)
		move.l	BUFFER,ASSNAME

;====== Read path to assign and prepare values

.LOCK		equr	d4

		bsr.b	GetString
		beq.b	.end
		move.l	BUFFER,.LOCK
		cmp.w	#4,TYPE
		bhs.b	.lock_not_needed
.makedir

;======	Lock directory (if it does not exist, create all needed subdirs)

.LIMITER	equr	d3
.DIREND		equr	a4

		moveq	#0,.LOCK
		move.l	BUFFER,.DIREND
		move.b	(.DIREND),.LIMITER

;------	Find end of next directory name (if 0 is first char, end assign)

.next_dir
		move.b	.LIMITER,(.DIREND)+
		beq.b	.lock_done
.first		move.b	(.DIREND)+,d0
		beq.b	.found_dir
		cmp.b	#'/',d0
		bne.b	.first
.found_dir	subq.w	#1,.DIREND

;------	Next dir name was found, so unlock previous lock and cut new path

		move.b	(.DIREND),.LIMITER
		clr.b	(.DIREND)

.unlock		move.l	.LOCK,d1
		beq.b	.skip_unlock
		JSRLIB	UnLock
.skip_unlock		

;------ Try to lock this directory (if sucesfull, try to nest into subdir)

		move.l	BUFFER,d1
		moveq	#ACCESS_READ,d2
		JSRLIB	Lock
		move.l	d0,.LOCK
		bne.b	.next_dir

;------ Dir can't be locked, so we will create it and try to lock it again

		move.l	BUFFER,d1
		JSRLIB	CreateDir
		move.l	d0,.LOCK	;returns exclusive lock if suceed
		bne.b	.unlock
.lock_done

.lock_not_needed

;======	Parameters are prepared, so go and assign according to type

		move.l	ASSNAME,d1
		move.l	.LOCK,d2
		beq.b	.lock_failed
		jsr	.Commands(PC,TYPE.w)
.lock_failed	bra.w	.lock
.Commands
		bra.b	.AssNormal
		bra.b	.AssAdd
		bra.b	.AssDefer
		bra.b	.AssPath
		bra.b	.free_lock

.AssNormal
		JSRLIB	AssignLock
.test_success	tst.l	d0
		bne.b	.success
.free_lock	move.l	d2,d1
		beq.b	.success
		JSRLIB	UnLock
.success	rts
.AssAdd
		JSRLIB	AssignAdd
		bra.b	.test_success
.AssDefer	JMPLIB	AssignLate
.AssPath	JMPLIB	AssignPath


GetString ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;IN:	LINE	input command line
;OUT:	LINE	point after last char of string
;	BUFFER	first character of string
;FUNC:	Finds string in source LINE and ends it with 0. String can be
;	enclosed in quotes or can't contain any spaces or tabs.
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

		PUSHM	d0-d2

		moveq	#' ',d1
		moveq	#9,d2

;======	Skip empty characters (spaces and tabs)

.skip		move.l	LINE,BUFFER
		move.b	(LINE)+,d0
		beq.b	.end
		cmp.b	d0,d1
		beq.b	.skip
		cmp.b	d0,d2
		beq.b	.skip

;======	Detect string begin and delimiters

		cmp.b	#34,-(LINE)	;we know, that there is some char>0
		bne.b	.find_end
		addq.w	#1,LINE
		moveq	#34,d1
		moveq	#34,d2
		
;======	Remember begin and find end of string

.find_end
		move.l	LINE,BUFFER
		bra.b	.test_end
		
..		cmp.b	d0,d1
		beq.b	.end
		cmp.b	d0,d2
		beq.b	.end
.test_end	move.b	(LINE)+,d0
		bne.b	..

;======	Change string delimiter to 0

		clr.b	-(LINE)
		bra.b	.tst
.end		clr.b	-1(LINE)

.tst		tst.b	(BUFFER)		;test, if string is empty
		POPM
		rts

version_string	DC.B	"$VER: MASS 1.1 (14.4.1995) Rudla Kudla",0
dos_name	DC.B	"dos.library",0
command_list	DC.B	"add",0,"defer",0,"path",0,0

	IFD	TestInput
Test
	DC.B	"ram:dir1 ram:dir2/dir21 ram:dir1/dir11 "
;	DC.B	"memory: ram:mem add memory: ram:mem2 memory: ram:mem3 "
;	DC.B	"PATH "
;	DC.B	"EPSON: ",34,"Workbench:devs/new printer/epson",34," "
;	DC.B	"DEFER "
;	DC.B	"CANON: ",34,"Workbench:devs/new printer/canon",34
	DC.B	$A
EndTest
		ENDC
