********************************************************************************
* cli_parse.asm - asm replacement for cli_parse - by Talin                     *
********************************************************************************
; function
;	Copy cmdline into argline, expanding and seperating all arguments, with
;	the pointer to each argument in an array.

; register usage:
;	d0 = process BPTR, Command Name BPTR, argument to/from AllocMem
;	d1 = current parse character, also arg to AllocMem
;	d2 = lengh of cmdline argument, also 'toupper' version of escape character
;	d3 = argc
;	d4 = max argument length
;	d5 = max slot number

;	a0 = process ptr, command name ptr, end of cmdline ptr
;	a1 = arglin buffer
;	a2 = cmdline buffer
;	a3 = temporary argv array

			INCLUDE	"exec/types.i"
			INCLUDE	"exec/alerts.i"
			INCLUDE	"exec/memory.i"
			INCLUDE	"libraries/dos.i"
			INCLUDE	"libraries/dosextens.i"
			INCLUDE	"workbench/startup.i"

			xdef	__xcli_parse

; slotsused = xcli_parse(process, cmdline, cmdlen, buffer, maxbuf, slotarray, maxslots)

; returns 0 if error
; note that too many args is not an error -- it simply ignores the extra args.

__xcli_parse:				; (process, cmdlen, cmdline);
			movem.l		a2/a3/d2-d5,-(sp)		; push 6 regs = 24 bytes

;------ get arguments from stack
			move.l		 4+24(sp),a0			; get process pointer
			move.l		 8+24(sp),a2			; get command buffer
			move.l		12+24(sp),d2			; get command length
			move.l		16+24(sp),a1			; get destination buffer
			move.l		20+24(sp),d4			; get size of dest buffer
			move.l		24+24(sp),a3			; get slot array
			move.l		28+24(sp),d5			; get max number of slots
			add.l		a1,d4					; d4 = last dest address
			subq.l		#1,d4					; don't count terminating NULL

;------ find command name
			move.l		pr_CLI(a0),d0			; get pr_CLI field
			lsl.l		#2,d0					; pr_CLI bcpl pointer conversion
			move.l		d0,a0					; a0 <-- process pointer
			move.l		cli_CommandName(a0),d0	; get command name
			lsl.l		#2,d0					; bcpl pointer conversion

;-- copy command name
			move.l		d0,a0					; a0 <-- commandname
			moveq.l		#0,d0					; BCPL string length = 0
			move.b		(a0)+,d0				; size of command name
			clr.b		0(a0,d0.l)				; terminate the command name
			move.l		a0,(a3)+				; argv[0] <-- command name address
			moveq		#1,d3					; start counting arguments

;------ null terminate the arguments, eat trailing control characters
			lea			0(a2,d2.l),a0			; start at end of command line
stripjunk:
			cmp.b		#' ',-(a0)				; if less than space
			dbhi		d2,stripjunk			; decrement

			clr.b		1(a0)					; null terminate command line.

;------ start gathering arguments into buffer
newarg:
;-- skip spaces
			move.b		(a2)+,d1				; get next char in command line
			beq.s		parmExit				; if zero, no more arguments.
			cmp.b		#' ',d1					; if space
			beq.s		newarg					;	then loop
			cmp.b		#9,d1					; if tab
			beq.s		newarg					;	then loop

;-- check for argument count overflow, if d3 >= d5
			cmp.w		d5,d3					; compare argc with ARGVSLOTS
			bhs.s		parmExit				; if overflow, then quit

;-- push address of the next parameter
			move.l		a1,(a3)+				; argv[argc] = next argbuf loc
			addq.w		#1,d3					; arc++

;-- process quotes
			cmp.b		#'"',d1					; if it's a quote
			beq.s		doquote					; then do special

;-- copy the parameter in
			cmp.l		d4,a1
			bhs.s		problem
			move.b		d1,(a1)+				; copy first character to argbuf

nextchar:
;------ null termination check
			move.b		(a2)+,d1				; get next arg char
			beq.s		parmExit				; if char == '\0' then done
			cmp.b		#' ',d1					; if char == ' ' then
			beq.s		endarg					; we're done with this arg.

			cmp.l		d4,a1
			bhs.s		problem
			move.b		d1,(a1)+				; else move cmdline to argbuf
			bra.s		nextchar				; and do next char.

endarg:
			cmp.l		d4,a1
			bhs.s		problem
			clr.b		(a1)+					; null terminate argument
			bra.s		newarg					; and get another argument

doquote:
;------ process quoted strings
			move.b		(a2)+,d1				; get next char in quoted string
			beq.s		parmExit				; if char == '\0' then all done
			cmp.b		#'"',d1					; if char == '"' then done
			beq.s		endarg					; do next argument

;-- '*' is the BCPL escape character
			cmp.b		#'*',d1					; if it's not a '*'
			bne.s		addquotechar			; then add it to the arg

			move.b		(a2)+,d1				; get character after '*'
			move.b		d1,d2					; convert to upper case
			and.b		#$df,d2					; d2 is temp toupper'd d1

			cmp.b		#'N',d2					; check for dos newline char
			bne.s		checkEscape

;--	got a *N -- turn into a newline
			moveq		#10,d1					; d1 <-- newline
			bra.s		addquotechar			; add to arg

checkEscape:
			cmp.b		#'E',d2					; check for escape
			bne.s		addquotechar			; if not, just add in char

;--	got a *E -- turn into a escape
			moveq		#27,d1					; else char <-- ESC

addquotechar:
			cmp.l		d4,a1
			bhs.s		problem
			move.b		d1,(a1)+				; add character to arg
			bra.s		doquote					; and continue

parmExit:
;------ all done -- null terminate the arguments
			clr.b		(a1)					; null terminate last arg
			clr.l		(a3)					; clear argv[argc]

			move.l		d3,d0					; return number of args in d0

* now, copy argbuf to argv, for argc+1 items

;			move.l		sp,a3					; address of temp argv array
;1$			move.l		(a3)+,(a1)+				; copy 1 argument
;2$			dbf			d3,1$					; and loop

			movem.l		(sp)+,a2/a3/d2-d5
			rts

problem:
			moveq		#0,d0
			movem.l		(sp)+,a2/a3/d2-d5
			rts

			end
