[net.micro.amiga] Some assembler stuff

dewi@druca.UUCP (WilliamsD) (03/20/86)

After a few requests, here's the source to the ansiecho command that was
posted a week or so ago. It's been revised so that the V1.1 assembler and
linker believes in it, and has one bug fix -- the original wouldn't handle
ansiecho "" properly.

Also thrown in are cls.asm (clears the current window, what else...) and
ask.asm, which allows yes/no style dialog in CLI scripts by a rather gross
method.
		Dewi Williams

--------------- cut, do not fold spindle or mutilate ----------------------
echo "creating source files:"
echo "\tcls.asm"
cat <<"FUNKYSTUFF" >cls.asm
* CLI TOY #1
* CLS.ASM:     A command to clear the current (CLI) window. Works by
*              sending a HOME/CLEAR TO END OF SCREEN sequence to CON:
*
* Perpetrator: Dewi Williams  ..!ihnp4!druca!dewi
*              Unconditionally placed in the public domain.

* Included equate files.
* -----------------------------------------------------------------------
      NOLIST 
      INCLUDE  "exec/types.i"
      INCLUDE  "exec/libraries.i"
      INCLUDE  "libraries/dos.i"
      LIST

* Local Equates
* ------------------------------------------------------------------------
SysBase  EQU   4        ; The one known address in the system.

* External references
* -----------------------------------------------------------------------

	EXTERN_LIB	OpenLibrary
	EXTERN_LIB	Write
	EXTERN_LIB	Output
	EXTERN_LIB      IoErr

* macros
* ------------------------------------------------------------------------
* Calls to dos.library and exec library
callsys  MACRO
      CALLLIB      _LVO\1
      ENDM

* The code segment
* -------------------------------------------------------------------------

   RORG     0              ; Relocatable code.

   ;------ get Exec's library base pointer:
   move.l   SysBase,a6
   LEA.L    DOSName(PC),A1    ; name of dos library
   move.l   #LIBRARY_VERSION,d0

   callsys  OpenLibrary
   MOVE.L   D0,A6             ; Save library pointer (always in A6).
   BEQ.S    DOSFAIL           ; Give up!

* Obtaining the output handle (needed for write)
   callsys  Output            ; Always works -- copy from process structure.
   MOVE.L   D0,D1             ; Needed there by write

* Write the sequence to the driver
   LEA.L    CLS(PC),A0
   MOVE.L   A0,D2             ; Effective address of the buffer
   MOVEQ    #4,D3             ; Length of buffer to write
   callsys  Write             ; Do it
   TST.L    D0                ; Just set condition code
   BMI.S    IOFAIL            ; For disks & suchlike check == D3.

* Exit back to CLI (shouldn't close CLI handles).
   MOVEQ    #0,D0             ; Success exit code

FINISHED:
   rts

* All the error traps go here
* ---------------------------

   ; Get here if we can't write to CON: for some reason.
IOFAIL:
   callsys  IoErr          ; Returns real reason for failure.
   BRA.S    FINISHED       ; Quit

   ; Get here if we can't open dos.library. Give up! We should really
   ; alert...
DOSFAIL:
   MOVEQ    #RETURN_FAIL,D0
   RTS

* Data declarations
* ------------------------------------------------
DOSName		DOSNAME;
CLS		DC.B	$9B,'H',$9B,'J'	; HOME, CLEAR TO END OF SCREEN
	END
FUNKYSTUFF
echo "\techo.asm"
cat <<"FUNKYSTUFF" >echo.asm
* CLI TOY #2
* ANSIECHO.ASM:    Extended echo that handles backslash constructs such as \t
*                  etc. Unlike UNIX echo, it takes \3A hex constructs instead
*                  of octal. I'd rather grow 6 new fingers than lose 2!
*
*              The following backslash constructs are supported:
*                 \t    tab
*                 \n    newline
*                 \f    formfeed (clear screen)
*                 \e    escape character
*                 \c    on end of string, suppresses newline
*                 \b    backspace
*                 \\    single backslash
*                 \"    explicit string quote, otherwise eaten.
*                 \nn   hexadecimal characters (must be upper case).
*
*              As an example, try echo \e[37mhello world\e[0m
*
* Perpetrator: Dewi Williams  ..!ihnp4!druca!dewi
*              Unconditionally placed in the public domain.

* Included equate files.
* -----------------------------------------------------------------------
      	NOLIST 
      	INCLUDE  "exec/types.i"
      	INCLUDE  "exec/libraries.i"
      	INCLUDE  "libraries/dos.i"
      	LIST

* External references
* -----------------------------------------------------------------------

	EXTERN_LIB	OpenLibrary
	EXTERN_LIB	Write
	EXTERN_LIB	Output

* Local Equates
* ------------------------------------------------------------------------
SysBase  EQU   4        ; The one known address in the system.
TRUE     EQU   -1
FALSE    EQU   0
CMD_SIZE EQU   300      ; plenty big enough!

* Macros
* ------------------------------------------------------------------------

* Calls to dos.library and exec library
callsys  MACRO
      CALLLIB      _LVO\1
      ENDM

* The code segment
* -------------------------------------------------------------------------
   RORG     0                 ; Relocatable code.

   LINK     A2,#(-CMD_SIZE)   ; expand onto stack
   LEA.L    -CMD_SIZE(A2),A1  ; start of expansion buffer
   jsr      argtrim           ; clean up command line
   MOVEM.L  D0/A0-A2,-(SP)    ; Save command line (OpenLibrary trashes).

   ;------ get Exec's library base pointer:
   move.l   SysBase,a6
   LEA.L    DOSName(PC),A1    ; name of dos library
   move.l   #LIBRARY_VERSION,d0

   callsys  OpenLibrary
   MOVE.L   D0,A6             ; Save library pointer (always in A6).
   BNE.S    gotdos

   ; Should really issue an alert here...
   moveq    #RETURN_FAIL,D0   ; give up
   bra      FINISHED

*  Set up loop addressing: A0 goes through command line, A1 references
*  stack build area, A2 is the frame pointer, D4 is the nonl flag and
*  D3 is a counter. The command line is terminated by a newline character.

gotdos:

*  Obtain the output handle (needed for write)
   callsys   Output
   MOVE.L   D0,D5             ; Save for the write

   MOVEM.L  (SP)+,D0/A0-A2    ; restore command line etc.

   MOVEQ    #FALSE,D4         ; nonl assumed false as default
   CLR.L    D3                ; zero characters so far

mainloop:
   CMPI.B   #0,(A0)           ; Reached end of string yet?
   BEQ      eos               ; yes
   CMPI.B   #'\',(A0)         ; is it escaped?
   BNE      notesc            ; no
   CMPI.B   #0,1(A0)          ; at the end of the string?
   BEQ      notesc            ; not escaping anything, is itself

   ; Check out the \t \f etc. cases first
   ADDQ     #1,A0             ; move to next character
   CMPI.B   #'t',(A0)         ; a tab?
   BNE      next1             ; no
   MOVE.B   #9,(A1)+          ; yes
   bra      gotit
next1:
   cmpi.b   #'b',(A0)         ; a backspace?
   bne      next2             ; no
   move.b   #8,(A1)+          ; yes
   bra      gotit
next2:
   cmpi.b   #'n',(A0)         ; a newline?
   bne      next3             ; no
   move.b   #10,(A1)+         ; yes
   bra      gotit
next3:
   cmpi.b   #'e',(a0)         ; an escape char (not backslash!)
   bne      next4             ; no
   move.b   #27,(A1)+         ; yes
   bra      gotit
next4:
   cmpi.b   #'\',(a0)         ; an escaped backslash?
   bne      next5             ; no
   bra      notesc            ; yes
next5:
   cmpi.b   #'f',(a0)         ; formfeed
   bne      next6             ; no
   move.b   #12,(A1)+         ; yes
   bra      gotit
next6:
   cmpi.b   #'c',(a0)         ; no newline construct
   bne      next7             ; no
   cmpi.b   #0,1(A0)          ; A \c at the end of the string?
   bne      notesc            ; no
   moveq    #TRUE,D4          ; set up the nonl flag
   bra      eos               ; know we've finished
next7:
   cmpi.b   #'"',(A0)         ; a string quote?
   bne      maybehex          ; no
   move.b   #'"',(A1)+        ; yes
   bra      gotit

   ; get here -- maybe it's 2 hex digits. Call ishexdig to find out.
maybehex:
   move.b   (a0),D1
   jsr      ishexdig          ; Check the first character
   beq      notesc            ; failed the test
   move.b   1(a0),D1          ; Now check the second
   jsr      ishexdig
   beq      notesc            ; second one failed
   jsr      hexstr            ; translate it into a real character
   addq     #1,a0             ; lose both characters
   move.b   d0,(A1)+          ; and fall through to gotit.

gotit:
   addq     #1,a0             ; next input character
   addq     #1,d3             ; bump output count
   bra      mainloop          ; round again
notesc:

   ; A normal character
   move.b   (a0)+,(a1)+       ; copy it over
   addq     #1,d3             ; bump output count
   bra      mainloop          ; round again

   ; Left the loop.

eos:
   TST.L    D4                ; Check out the nonl flag
   BNE      skipnl            ; set
   move.b   #10,(a1)+         ; add the newline.
   addq     #1,d3

skipnl:

   ; All set up for printing out the gathered string. Start by recalculating
   ; the start address of the output buffer.
   lea.l    -CMD_SIZE(A2),A0
   move.l   a0,d2             ; start address
   move.l   d5,d1             ; restore handle

   callsys  Write
   MOVEQ    #0,D0             ; success
FINISHED:
   UNLK     A2
   RTS

* Subroutines
* ------------------------------------------------------------------------

* ishexdig: passed a character in D1, will report as a boolean in D0.
* Passes 0..9 and A..F (upper case).
ishexdig:
   cmpi.b   #'0',D1
   blt      hexlab
   cmpi.b   #'9',D1
   ble      yes
hexlab:
   cmpi.b   #'A',D1
   blt      no
   cmpi.b   #'F',D1
   bgt      no
yes:
   moveq    #TRUE,D0
   bra      endhex
no:
   moveq    #FALSE,D0
endhex:
   rts

* hexstr:   passed a hex string in A0, return its value in D0.
*           Stop either at length 2 or invalid hex character.
*           In this case, the string has already been validated.
* CREDITS:  Slightly hacked version of p430 of "Programming the 68000"
*           by Steve Williams. Sybex books. Recommended.

hexstr:
   movem.l  d1-d3/a0,-(sp)    ; save starting registers
   clr.l    d0                ; clear accumulator
   clr.l    d3                ; count of digits processed
loop:
   clr.l    d1                ; zero out D1
   cmpi.b   #'9',(a0)         ; upper bound
   bhi      notdec            ; not a decimal digit
   cmpi.b   #'0',(a0)         ; lower bound
   blt      nothex            ; not a hex digit
   move.b   #'0',d1           ; correction factor
   bra      gotdig            ; accumulate
notdec:
   cmpi.b   #'A',(a0)         ; check letters
   blt      nothex            ; not a hex digit
   cmpi.b   #'F',(a0)         ; upper case hex?
   bhi      nothex            ; no, and lower case is not allowed
   move.b   #'A'-10,d1        ; correction factor / fall through to gotdig
gotdig:
   clr.l    d2                ; zero high byte
   move.b   (a0)+,d2          ; get next digit
   sub.l    d1,d2             ; convert to binary
   lsl.l    #4,d0             ; multiply by 16
   add.l    d2,d0             ; add in digit
   cmpi.l   #1,d3             ; reached the end yet?
   beq      hexdone           ; yes
   addq.l   #1,d-d3/a0    ; unsave registers
   rts                        ; return to caller

* argtrim:  a routine to trim the end of a command line and null terminate
*           it. This is achieved in the following manner:
*           Start at the end and run back until a non-whitespace (nl/blank)
*           character is encountered. If this is a quote, toss it.
*           If the *first* character is a quote, bump the start address by
*           one. No pretense of quote matching here.
*                 Inputs:     address in A0, length in D0
*                 Outputs:    address in A0.

argtrim:
   movem.l  d1-d7/a1-a6,-(sp)       ; save registers

   cmpi.b   #'"',(a0)		   ; starts with a quote?
   bne.s    checkline		   ; no
   subq     #1,d0		   ; yes - decrement count
   addq     #1,a0		   ; and bump start address

checkline:
   cmpi.b   #1,D0                   ; length includes the newline
   bne.s    isline		    ; yes - there is something there
   move.b   #0,(a0)                 ; create null string
   bra.s    argfini		    ; done

isline:
;  strip off any run of blanks on the end...   
   move.l   a0,a1                   ; computing end address of line
   add.l    d0,a1		    ; 
   subq     #2,a1		    ;

toploop:
   cmp.l    a0,a1		
   beq.s    empty                   ; single char or run of blanks

   cmpi.b   #' ',(a1)
   bne.s    endloop                 ; finished the scan
   subq     #1,a1                   ; else back one more
   bra.s    toploop                 ; and try again

endloop:
   cmpi.b   #'"',(a1)
   beq.s    nullit
nullnext:
   addq     #1,a1
nullit:
   move.b   #0,(a1)
   bra.s    argfini
empty:                              ; could be blanks or a single char
   cmpi.b   #' ',(a1)
   bne.s    endloop		    ; or maybe a single quote!
   move.b   #0,(a0)

argfini:
   movem.l  (sp)+,d1-d7/a1-a6       ; restore registers
   rts

* Data declarations
* -------------------------------------------------------------------------
DOSName		DOSNAME
   END
FUNKYSTUFF
echo "\task.asm"
cat <<"FUNKYSTUFF" >ask.asm
; CLI TOY #3.
; ask.asm:	A routine to allow a single character answer to a question
;		posed by a ansiecho or echo question.
;		This character is then tested, and an ERROR issued if the
;		answer is not "y" or "Y".
;
;		The idea is based on H. Fischer's INFO-IBMPC submission of
;		12/83, called bat-ques. 
;
; Complaint:    IF should really allow IF ERROR=40... which would make this
;		a more general purpose hack. Probably better to just do a
;		more reasonable CLI.
; Perpetrator:  Dewi Williams  ..!ihnp4!druca!dewi
;               Unconditionally placed in the public domain.
; Restrictions: You'll probably need the V1.1 linker & assembler.
; Usage:
;		failat 20
;		ansiecho "do you want to load up the RAM disk? \c"
;		ask
;		if not error
;		ansiecho loading RAM...
;		else
;		ansiecho not loading RAM...
;		endif

* Included equate files.
* -----------------------------------------------------------------------
      	NOLIST 
      	INCLUDE  "exec/types.i"
      	INCLUDE  "exec/libraries.i"
      	INCLUDE  "libraries/dos.i"
      	LIST

* External references
* -----------------------------------------------------------------------

	EXTERN_LIB	OpenLibrary
	EXTERN_LIB	Read
	EXTERN_LIB	Input

* Local Equates
* ------------------------------------------------------------------------
SysBase  EQU   4        ; The one known address in the system.
TRUE     EQU   -1
FALSE    EQU   0
CMD_SIZE EQU   300      ; plenty big enough!

* Macros
* ------------------------------------------------------------------------

* Calls to dos.library and exec.library
callsys  MACRO
	CALLLIB      _LVO\1
      	ENDM

* The code segment
* -------------------------------------------------------------------------

	RORG     0                 ; Relocatable code.

	LINK     A2,#(-CMD_SIZE)   ; expand onto stack
	LEA.L    -CMD_SIZE(A2),A3  ; start of read buffer
	MOVEM.L  A0-A3,-(SP)	   ; Save command line (OpenLibrary trashes).

	;------ get Exec's library base pointer:
	move.l   SysBase,a6
	LEA.L    DOSName(PC),A1    ; name of dos library
	move.l   #LIBRARY_VERSION,d0

	callsys  OpenLibrary
	MOVE.L   D0,A6             ; Save library pointer (always in A6).
	BNE.S    gotdos

	; Should do a dos failure alert here. They'll find out soon enough!
	move.l	#1000,D0
	bra.s	fini
gotdos:
	MOVEM.L  (SP)+,A0-A3   ; restore stack addressing.

*  	Obtain the Input handle.
	callsys  Input         ; Always works -- copy from process structure.
	MOVE.L   D0,D1         ; Save for the read

*	Read the console
	move	#CMD_SIZE,d3	; Read >1 to swallow the CR
	move.l	a3,D2		; read onto the stack
	callsys Read            ; D1 = handle D2 = address D3 = length

*	Check out the read character
	cmpi.b  #'Y',(A3)
	beq.s	yes
	cmpi.b  #'y',(a3)
	beq.s	yes
	moveq	#RETURN_ERROR,D0	; anything else means no
	bra.s	fini
yes:
	moveq	#RETURN_OK,D0
fini:
	unlk	a2
	rts			; return with exit code in D0

* Data declarations
* -------------------------------------------------------------------------
DOSName		DOSNAME
   END
FUNKYSTUFF
echo "source file creation complete"
exit 0
------
-- 


----------------------------------------------------------------------
	Dewi Williams.
				uucp:	   ..!ihnp4!druca!dewi
				phone:     (303) 538 4884