;*** achslib.s
;
;    880103

;*** ASCII Code Equates

BS        ==        $08
HT        ==        $09
LF        ==        $0a
VT        ==        $0b
FF        ==        $0c
CR        ==        $0d
ZEOF      ==        $1a
ESC       ==        $1b
SPACE     ==        $20

;*** Atari ST Key Equates

;    Shift Bits
KRSHIFT   ==        $01
KLSHIFT   ==        $02
KCTRL     ==        $04
KALT      ==        $08
KCAPS     ==        $10
KRMOUSE   ==        $20
KLMOUSE   ==        $40

;    Function Keys
KF1       ==        $003b0000
KF2       ==        $003c0000
KF3       ==        $003d0000
KF4       ==        $003e0000
KF5       ==        $003f0000
KF6       ==        $00400000
KF7       ==        $00410000
KF8       ==        $00420000
KF9       ==        $00430000
KF10      ==        $00440000
 
KESC      ==        $0001001b
KRETURN   ==        $001c000d
KENTER    ==        $0072000d
KBS       ==        $000e0008
KDEL      ==        $0053007f

KCTLDEL   ==        $0053001f
KCTLLEFT  ==        $00730000
KCTLRIGHT ==        $00740000

KHOME     ==        $00470000
KUP       ==        $00480000          
KLEFT     ==        $004b0000
KRIGHT    ==        $004d0000
KDOWN     ==        $00500000
KTAB      ==        $000f0009
 
KINSERT   ==        $00520000
KUNDO     ==        $00610000
KHELP     ==        $00620000

;*** GEMDOS Equates

CCONIN    ==        1    ; standard console in       
CCONOUT   ==        2    ; standard console out
CAUXIN    ==        3    ; auxilary in
CAUXOUT   ==        4    ; auxilary out
CPRNOUT   ==        5    ; standard printer out
CRAWIO    ==        6    ; Raw I/O to standard I/O
CRAWIN    ==        7    ; Raw console in, no echo, no ctrl interpret
CNECIN    ==        8    ; Raw console in, no echo, ctrl interpreted
CCONWS    ==        9    ; write NULL terminated string to standard output 
CCONRS    ==        10   ; read edited string from standard input   
CCONIS    ==        11   ; check status of standard input


;*** Atari System Variables
;
;    NOTE: must be in Supervisor mode to modify.

_DEFRES   ==        $44a      ; default monitor resolution
_MONITOR  ==        $44c      ; monitor type
_CONTERM  ==        $484      ; attributes for the console system


;*** Terminal Definition Area

          .data
          .even
_TERM::
bell:     .dc.b     7,0            ; bell code string
          .dc.b     0,0,0,0,0,0

tset:     .dc.b     0,0,0,0,0,0,0,0     ; terminal init

trst:     .dc.b     0,0,0,0,0,0,0,0     ;terminal de-init
                     
curhome:  .dc.b     ESC,'H',0      ; cursor home
          .dc.b     0,0,0,0,0

clrscr:   .dc.b     ESC,'E',0      ; clear screen
          .dc.b     0,0,0,0,0

clreol:   .dc.b     ESC,'K',0      ; clear to EOL
          .dc.b     0,0,0,0,0

clreop:   .dc.b     ESC,'J',0      ; clear to EOP
          .dc.b     0,0,0,0,0

curon:    .dc.b     ESC,'e',0      ; cursor on
          .dc.b     0,0,0,0,0

curoff:   .dc.b     ESC,'f',0      ; cursor off
          .dc.b     0,0,0,0,0

hilite:   .dc.b     ESC,'p',0      ; inverse on
          .dc.b     0,0,0,0,0

lolite:   .dc.b     ESC,'q',0      ; inverse off
          .dc.b     0,0,0,0,0

insline:  .dc.b     ESC,'L',0      ; insert line
          .dc.b     0,0,0,0,0

delline:  .dc.b     ESC,'M',0      ; delete line
          .dc.b     0,0,0,0,0

curup:    .dc.b     ESC,'A',0      ; cursor up
          .dc.b     0,0,0,0,0

curdn:    .dc.b     ESC,'B',0      ; cursor down
          .dc.b     0,0,0,0,0

currt:    .dc.b     ESC,'C',0      ; cursor right
          .dc.b     0,0,0,0,0

curlt:    .dc.b     ESC,'D',0      ; cursor left
          .dc.b     0,0,0,0,0



;*** GotoXY for VT-52 terminal
;
; e  short X coord
;    short Y coord
;
; x  none
;
;    Position cursor at .text coords (X,Y).

          .data
          .even
     
curaddr:  .dc.b     ESC,'Y',0      ; cursor addressing lead in
          .dcb.b    5,0

cursep:   .dcb.b    8,0            ; cursor coord separator

curend:   .dcb.b    8,0            ; cursor addressing terminate

_XMAX::   .dc.w     80             ; max number of columns
_YMAX::   .dc.w     25             ; max number of rows
xoff:     .dc.w     32             ; x offset for columns
yoff:     .dc.w     32             ; y offset for rows

_TABLEN:: .dc.w     4              ; tab length to use
rows:     .dc.b     1              ; true if rows sent first
binary:   .dc.b     1              ; true if .data sent in binary 
     
          .text
_GOTOXY:: 
          link      a6,#0
          movea.l   #curaddr,a0    ; pnt to cursor addressing string
          move.l    a0,-(sp)       ; put on stack
          move.w    #CCONWS,-(sp)  ; send string to terminal
          trap      #1             ;   do GEMDOS call
          addq.l    #6,sp          ; correct stack

          move.w    _YMAX,d1       ; point to ymax value
          move.w    10(a6),d0      ; get y argument
          bsr.s     GOTOXY1

          move.w    _XMAX,d1       ; point to xmax value
          move.w    8(a6),d0       ; get x argument
          bsr.s     GOTOXY1
          unlk      a6
          rts
GOTOXY1:
          ext.l     d0
          divu      d1,d0
          swap      d0             ; q = q mod max
          addi.w    #32,d0         ; q = q + offset

          move.w    d0,-(sp)
          move.w    #CCONOUT,-(sp)
          trap      #1
          addq.l    #4,sp
          rts



;*** Move Memory
;
; e  long source pointer to char
;    long target pointer to char
;    long length of source
;
; x  none
;
;    Move a block of Length from Source to Target.

          .text 
          .globl    _MOVEMEM
_MOVEMEM:
          movea.l   4(sp),a0       ; get source
          movea.l   8(sp),a1       ; get target
          move.l    12(sp),d0      ; get length
          beq.s     MOVEMX         ; exit if length is zero 
          cmpa.l    a1,a0          ; check  for s < t
          blt.s     MOVEMT         ; move tail first
MOVEMH:   
          move.b    (a0)+,(a1)+    ; move source byte to target
          subq.l    #1,d0          ; decrement length
          bne       MOVEMH         ; loop till zero
          bra.s     MOVEMX
MOVEMT:
          adda.l    d0,a0          ; do tail first
          adda.l    d0,a1
MOVEMTT:
          move.b    -(a0),-(a1)
          subq.l    #1,d0
          bne       MOVEMTT
MOVEMX:
          rts
          


;***String N Put
;
; e  long pointer to string
;    short n
;
; x  none 
;
;    Print n characters of a string

          .text
_STRNPUT::
          link      a6,#0
          movem.l   d3/a3, -(sp)
          movea.l   8(a6), a3
          adda.w    12(a6), a3
          cmpa.l    8(a6), a3
          beq.s     STRNPUT1
          move.b    (a3), d3
          clr.b     (a3)
STRNPUT1:
          move.l    8(a6), -(sp)
          move.w    #CCONWS, -(sp)
          trap      #1
          addq.l    #6, sp
          cmpa.l    8(a6), a3
          beq.s     STRNPUT2
          move.b    d3, (a3)
STRNPUT2:
          movem.l   (sp)+, d3/a3
          unlk      a6
          rts



;*** String N Copy
;
; e  long pointer source string
;    long pointer target string
;    short count
;
; x  none
;
;    Copy max n bytes of string 1 to string 2.
;    String 2 is NULL terminated.

          .text
_STRNCPY::      
          movea.l   4(sp),a0            ; get source
          movea.l   8(sp),a1            ; get target
          move.w    12(sp),d0           ; get count
          beq.s     .X                  ; count = 0?
.1:
          tst.b     (a0)                ; EOS on s1
          beq.s     .X
          move.b    (a0)+,(a1)+         ; copy char s1 to s2
          subq.w    #1,d0               ; --count
          bne       .1                  ; if count not zero
.X:
          clr.b     (a1)
          rts



;*** String Concatination
;
; e  long pointer to string 1
;    long pointer to string 2
; 
; x  none
;
;    Append string two to the end of one.

          .text
_STRCAT::
          move.l    4(sp),a0
.1:
          tst.b     (a0)+
          bne       .1
          subq.l    #1,a0
          movea.l   8(sp),a1
.2:
          move.b    (a1)+,(a0)+
          bne       .2
          rts


;*** Length of NULL terminated string
;
; e  long pointer to string
;
; x  D0.L = length of string up to NULL (but not including)

          .text
_STRLEN::
          moveq.l   #-1,d0
          movea.l   4(sp),a0
.1:
          addq.l    #1,d0
          tst.b     (a0)+
          bne       .1
          rts




;*** Find next token in string.
;
; e  long pointer to string / NULL to continue with last string
;    long pointer to delimeter string / NULL use default delimeters
;
; x  long pointer to start of token / NULL if no tokens left
;
;    Note: a) original string will be modified.
;          b) leading spaces are skipped.

          .data
DEFDELIM: .dc.b     SPACE, ',', 0

          .bss
_NEXTTOK::
          .ds.l     1

          .text
_STRTOK::
          move.l    4(sp), d0           ;get string
          bne.s     .1                  ;if NULL then
          move.l    _NEXTTOK, d0        ; continue with previous
          beq.s     .X                  ; string, return NULL if EOS
.1:
          movea.l   d0, a0
.2:
          cmpi.b    #SPACE, (a0)+       ;skip leading spaces
          beq       .2
          subq.l    #1, a0
          move.l    a0, d0              ;start of token to return
          move.l    8(sp), d1           ;get delimeter string
          bne.s     .3                  ;if NULL then use default
          move.l    #DEFDELIM, d1
.3:
          movea.l   d1, a1              ;reset delimeter string
          move.b    (a0)+, d2           ;get char in token
.4:
          cmp.b     (a1), d2            ;check against delims
          beq.s     .5
          tst.b     (a1)+   
          bne       .4                  ;end of delim string?
          bra       .3
.5:
          clr.b     -1(a0)              ;terminate token at delim
          tst.b     d2                  ;was it end of search string
          bne.s     .6
          suba.l    a0, a0              ;save NULL for next search
.6:
          move.l    a0, _NEXTTOK        ;remember current position
.X:
          rts


;*** Find index of character in string
;
; e  long pointer to string
;    word character value
;
; x  D0.L = index into string if character is found else -1

          .text
_FINDI::   
          move.l    4(sp),a0       ;pointer to string
          moveq.l   #-1, d0
          move.w    8(sp),d1       ;character
.1:
          tst.b     (a0)           ;EOS?
          beq.s     .X
          cmp.b     (a0)+, d1      ;check character
          bne       .1
          move.l    a0, d0
          sub.l     4(sp), d0      ;current - original
          subq.l    #1, d0         ;adjust overrun -1
.X:
          rts


;*** Find index of last occurence of character in string
;
; e  long pointer to string
;    word character value
;
; x  D0.L = index into string if character is found else -1

          .text
_LFINDI::
          movea.l   4(sp), a0
          moveq.l   #-1, d0
          move.w    8(sp), d1
          bra.s     .2
.1:
          cmp.b     (a0)+, d1
          bne.s     .2
          move.l    a0, d0
          sub.l     4(sp), d0
          subq.l    #1, d0
.2:
          tst.b     (a0)
          bne       .1
          rts


;*** Deque Rouitines

;*** Make Deque
;
; e  long      # of long words for deque
;
; x  D0.L =    ptr to deque structure / NULL unsuccessful

          .text
_MKDEQ::
          link      a6, #0
          movem.l   a3-a4, -(sp)
          move.l    8(a6), d1
          lsl.l     #2, d1
          addi.l    #16, d1
          move.l    d1, -(sp)
          move.w    #$48, -(sp)
          trap      #1
          addq.l    #6, sp
          tst.l     d0
          beq.s     .X
          movea.l   d0, a0
          movea.l   d0, a1
          adda.l    #16, a1             ;base of deque
          movea.l   a1, a2              ;left pointer
          movea.l   a1, a3              ;right pointer
          movea.l   a1, a4              
          adda.l    d1, a4              ;end of deque +1
          movem.l   a1-a4, (a0)         ;save deque structure
.X:
          movem.l   (sp), a3-a4
          unlk      a6
          rts     


;*** Remove Deque
;
; e  long      ptr to deque structure
;
; x  D0.W =    NULL for success / error code

          .text
_RMDEQ::
          move.l    4(sp), -(sp)
          move.w    #$49, -(sp)
          trap      #1
          addq.l    #6, sp
          rts


;*** Add an element to deque
;
; e  long      ptr to deque structure
;    word      0 left / 1 right 
;    long      value to store

          .text
_DEQADD::
          link      a6, #0
          movem.l   a3-a4, -(sp)
          movea.l   8(a6), a0           ;ptr to deque structure
          movem.l   (a0), a1-a4         ;fetch deque structure
          move.l    14(a6), d0          ;value
          move.w    12(a6), d1          ;if adding to the right
          bne.s     .2
          cmpa.l    a1, a2
          bhi.s     .1                  ;if begin < left then
          movea.l   a4, a2              ;wrap deque to end
.1:
          move.l    d0, -(a2)           ;save value
          bra.s     .X
.2:
          move.l    d0, (a3)+           ;save value
          cmpa.l    a3, a4              ;if right < end then
          bhi.s     .X
          movea.l   a1, a3              ;wrap deque to beginning
.X:
          movem.l   a1-a4, (a0)         ;update deque structure
          movem.l   (sp), a3-a4
          unlk      a6
          rts


;*** Delete value from deque
;
; e  long      ptr to deque structure
;    word      0 left / 1 right
;
; x  D0.L      value

          .text
_DEQDEL::
          link      a6, #0
          movem.l   a3-a4, -(sp)
          movea.l   8(a6), a0
          movem.l   (a0), a1-a4
          move.w    12(a6), d1
          bne.s     .1
          move.l    (a2)+, d0           ;get value
          cmpa.l    a2, a4              ;if left < end then
          bhi.s     .X
          movea.l   a1, a2              ;wrap deque to beginning
          bra.s     .X
.1:
          cmpa.l    a1, a3              ;if begin < right then
          bhi.s     .2
          movea.l   a4, a3              ;wrap deque to end
.2:
          move.l    -(a3), d0           ;get value
.X:
          movem.l   a1-a4, (a0)         ;update deque structure
          movem.l   (sp), a3-a4
          unlk      a6
          rts
          

          .globl    _PUTDEC
          .globl    PUTDEC

;*** Print Unsigned Decimal (0-65535)
;
; _PUTDEC      e    word value
; PUTDEC       e    D0.W value
;              x    none

          .text
_PUTDEC:
          move.w    4(sp),d0
PUTDEC:          
          ext.l     d0
          divu      #10,d0
          beq.s     PUTDEC1
          move.l    d0,-(sp)
          bsr       PUTDEC
          move.l    (sp)+,d0
PUTDEC1:
          swap      d0
          addi.w    #$30,d0
          move.w    d0,-(sp)
          move.w    #CCONOUT,-(sp)
          trap      #1
          addq.l    #4,sp
          rts

            
;*** Print Unsigned Decimal
;
; _PUTLONG     e    long value
; PUTLONG      e    D0.L value
;              x    none

          .text
_PUTLONG::
          move.l    4(sp),d0
PUTLONG::        
          move.l    #10, -(sp)
          move.l    d0, -(sp)
          bsr.s     _ULD
          addq.l    #8, sp
          tst.l     d0
          beq.s     .1
          movem.l   d0-d1,-(sp)
          bsr       PUTLONG
          movem.l   (sp)+, d0-d1
.1:
          addi.w    #$30, d1
          move.w    d1,-(sp)
          move.w    #CCONOUT,-(sp)
          trap      #1
          addq.l    #4,sp
          rts



;*** Unsigned Long to ASCII
;
; e  long value
;    long pointer to string buffer
;
; x  ASCIIZ string in buffer

          .text
_ULTOA::
          move.l    4(sp),d0
          movea.l   8(sp), a0
ULTOA::
          move.l    #10, -(sp)
          move.l    d0, -(sp)
          bsr.s     _ULD
          addq.l    #8, sp
          tst.l     d0
          beq.s     .1
          movem.l   d0-d1,-(sp)
          bsr       ULTOA
          movem.l   (sp)+, d0-d1
.1:
          addi.w    #$30, d1
          move.b    d1, (a0)+
          clr.b     (a0)   
          rts

            
;*** Unsigned long division
;
; e  long dividend
;    long divisor
;
; x  D0.L = quoitent
;    D1.L = remainder
          
          .text
_ULD::
          move.l    4(sp), d0           ;dividend
          move.l    8(sp), d2           ;divisor
          move.w    d3, -(sp)
          move.w    #31, d3             ;bit count
          clr.l     d1                  ;remainder
.1:
          add.l     d0, d0
          addx.l    d1, d1
          sub.l     d2, d1
          bcc.s     .2
          add.l     d2, d1
          bra.s     .3
.2:
          addq.l    #1, d0
.3:
          dbf       d3, .1
          move.w    (sp)+, d3
          rts


          .globl    _DOS
          .globl    ___BDOS

;*** DOS Function Call (CP/M-68k)
;
; e  word function number
;    long parameter
;
; x  D0.L = returned value
     
          .text
_DOS:
___BDOS:
          move.w    4(sp),d0       ; get function number
          move.l    8(sp),d1       ; get parameter
          trap      #2             ; call DOS
          rts      
     

          .globl    _gemdos

;*** GEM Dos Function Call
;
; e  word function number
;    word / long parameters
;
; x  D0 = return value if any
;
;    See GEM Dos notes
     
          .text
_gemdos:
          move.l    (sp)+, GEMRET
          trap      #1
          move.l    GEMRET, -(sp)
          rts

          .bss
GEMRET:   .ds.l     1



          .globl    _xbios

;*** XBIOS Function Call
;
; e  word function number
;    word / long parameters
;
; x  D0 = return value if any
;
;    See XBIOS notes
     
          .text
_xbios:
          move.l    (sp)+, XBRET
          trap      #14
          move.l    XBRET, -(sp)
          rts

          .bss
XBRET:    .ds.l     1



