;
; cmdLine.s
;
; Command line parsing (MDW)
;
;  1994-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's Sapphire library.
;
; Sapphire is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2, or (at your option)
; any later version.
;
; Sapphire is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with Sapphire.  If not, write to the Free Software Foundation,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

;----- Standard header ------------------------------------------------------

		GET	libs:header
		GET	libs:swis

;----- Main code ------------------------------------------------------------

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- cl_next ---
;
; On entry:	R0 == pointer to a command line string (ctrl terminated)
;		R1 == pointer to a buffer (may be equal to R0)
;
; On exit:	CS if another word found, and
;		  R0 == updated past next word
;		  R1 preserved, buffer filled with null terminated string
;		  R2 == pointer to terminating null character
;		else CC and
;		  R0 == pointer to terminating character
;		  R1 preserved, buffer preserved
;		  R2 corrupted
;
; Use:		Extracts the next word from a command line string.  If the
;		string is in a writable buffer, you can set R1 == R0 to
;		start with.  You can build up a C-like argv array like this:
;
;			; R0 == pointer to command line in writable buffer
;
;				MOV	R1,R0
;				ADR	R3,argv
;				MOV	R4,#0
;			loop	BL	cl_next
;				MOVCC	R1,#0
;				STR	R1,[R3],#4
;				ADDCS	R4,#0
;				BCS	loop
;
;			; R0-R3 corrupted
;			; R4 == argc
;
;		This routine will handle quoted strings, considering them
;		to be single arguments.  Either type of quote will do,
;		quote doubling is required to insert quotes in quoted
;		strings.

		EXPORT	cl_next
cl_next		ROUT

		STMFD	R13!,{R1,R3,R14}	;Save some registers
		MOV	R2,R1			;Set up buffer pointer
		MOV	R1,#0			;No quotes found yet
		MOV	R3,#0			;Various flags:
						;  b0 == written a character
						;  b1 == currently in quotes
						;  b2 == just closed quotes

		; --- Skip past leading spaces ---

00cl_next	LDRB	R14,[R0],#1		;Load a byte from the string
		CMP	R14,#' '		;Is it a space?
		CMPNE	R14,#9			;Or a tab will do too
		BEQ	%00cl_next		;Yes -- get another character

		; --- Main character reading loop ---

10cl_next	CMP	R14,#' '		;Is it the string end?
		SUBLO	R0,R0,#1		;Keep ptr at ctrl char
		TSTEQ	R3,#2			;Are we currently in quotes?
		BLS	%90cl_next		;No -- deal with it nicely

		CMP	R14,R1			;Is it the last quote char?
		BEQ	%30cl_next		;Yes -- deal with this

		BIC	R3,R3,#4		;Last one wasn't a quote

		CMP	R14,#'"'		;Is it a double quote?
		CMPNE	R14,#'''		;Or a single one?
		TSTEQ	R3,#2			;Make sure not in quoted
		BEQ	%20cl_next		;Yes -- deal with this then

		STRB	R14,[R2],#1		;Otherwise store the byte
		ORR	R3,R3,#1		;Remember we've done it
		LDRB	R14,[R0],#1		;Load a byte from the string
		B	%10cl_next		;And go round again

		; --- Handle a new quote character ---

20cl_next	MOV	R1,R14			;Remember the quote character
		ORR	R3,R3,#2		;We're now in quotes
		LDRB	R14,[R0],#1		;Load a byte from the string
		B	%10cl_next		;And go round again

		; --- Handle a matched quote character ---
		;
		; Now this may be a close quote, or it may be a double quote
		; to indicate a literal.  We handle this by the following:
		;
		; if lastWasCloseQuotes
		;   write literal quote char
		;   set inQuotes
		;   clear lastWasCloseQuotes
		; else if inQuotes
		;   clear inQuotes
		;   set lastWasCloseQuotes
		; end

30cl_next	TST	R3,#6			;Was last quote, or inQuotes?
		BEQ	%20cl_next		;No -- then it's an open
		TST	R3,#4			;Was last one a quote?
		STRNEB	R14,[R2],#1		;Yes -- then store quote
		ORRNE	R3,R3,#1		;Remember we store something
		EOR	R3,R3,#6		;And toggle the bits nicely
		LDRB	R14,[R0],#1		;Load a byte from the string
		B	%10cl_next		;Return to the loop

		; --- We reached the end of the string ---

90cl_next	TST	R3,#1			;Did we write any text?
		MOVNE	R14,#0			;A terminating null
		STRNEB	R14,[R2],#0		;If so, terminate the text
		LDMFD	R13!,{R1,R3,R14}	;Unstack the registers
		ORRNES	PC,R14,#C_flag		;If so, set C on exit
		BICEQS	PC,R14,#C_flag		;Otherwise clear C

		LTORG

; --- cl_buildArgv ---
;
; On entry:	R0 == command line string (writable)
;		R1 == address of argv buffer
;
; On exit:	R1 == next unused location in argv buffer
;
; Use:		Turns the given string into an argv array which will make
;		argument scanning easier.  This is pretty much the code
;		given in the description of cl_next.

		EXPORT	cl_buildArgv
cl_buildArgv	ROUT

		STMFD	R13!,{R0,R2,R3,R14}	;Save some registers
		MOV	R3,R1			;Move the argv address away
		MOV	R1,R0			;Point to output buffer

		; --- Copy the argument pointers over ---

00		BL	cl_next			;Fetch the next argument
		MOVCC	R1,#0			;If done, null terminate list
		STR	R1,[R3],#4		;Store the pointer away
		MOVCS	R1,R0			;More to come -- reset buffer
		BCS	%b00			;And loop around

		; --- Tidy up and leave ---

		SUB	R1,R3,#4		;Point at terminating zero
		LDMFD	R13!,{R0,R2,R3,PC}^	;And return to caller

		LTORG

; --- cl_getopt ---
;
; On entry:	R1 = pointer to
;
; On exit:


;----- That's all, folks ----------------------------------------------------

		END
