* QL WORLD DIY TOOLKIT - EDLINE$ function, by Simon N Goodwin.
*
start      lea.l      define,a1
           move.w     $110,a2       BP.INIT
           jmp        (a2)
*
define     dc.w       0,0           No procedures
           dc.w       1             One function
           dc.w       edline-*
           dc.b       7,'EDLINE$'
           dc.w       0             End of functions
*
edline     move.l     a5,d5         Save last parameter address
           lea.l      3*8(a3),a5    Check for three parameters
           cmp.l      a5,d5
           bne.s      bad_param     Not 3 unless A3+24 = A5
*
* Read the first two parameters: channel number and buffer size
*
           subq.l     #8,a5         Hide the last parameter
           move.w     $112,a2       CA.GTINT - get two ints
           jsr        (a2)
           bne.s      bad_exit
           addq.l     #4,$58(a6)    Tidy 2 ints off maths stack
           move.w     2(a1,a6.l),d7 Grab the buffer length
           move.l     a5,a3         Retrieve the last parameter
           move.l     d5,a5
           move.w     2(a1,a6.l),d7
*
* Convert stacked channel number to channel ID in D5
*
           move.w     0(a1,a6.l),d0 Grab the channel number
           mulu.w     #40,d0        Find offset in table
           add.l      $30(a6),d0    Add base offset
           cmp.l      $34(a6),d0    Check not beyond end
           bge.s      what_chan
           move.l     0(a6,d0.l),d5 Get channel ID
           bmi.s      what_chan     Channel must be open
*
* Get the default string and check it fits the buffer
*
           move.w     $116,a2    CA.GTSTR - get a string
           jsr        (a2)
           bne.s      bad_exit
           addq.w     #1,d7      Allow for terminator/cursor
           move.l     8(a6),d0   Get offset of end of buffer
           subq.l     #8,d0      Allow for 8 coordinate bytes
           sub.l      (a6),d0    D0 is now maximum buffer size
           cmp.w      d0,d7      See if the chosen size fits
           bcs.s      got_room
*
           moveq      #-5,d0     BUFFER FULL error
           rts
what_chan  moveq      #-6,d0     CHANNEL NOT OPEN error
           rts
bad_param  moveq      #-15,d0    BAD PARAMETER error
bad_exit   rts
*
call_QDOS  trap       #3         General-purpose ROM caller
           tst.l      d0
           beq.s      hunky_dory
           addq.l     #4,a7      Return to previous caller
hunky_dory rts
*
* Put the string in the buffer; save first 8 bytes for later
*
got_room   lea.l      2(a1),a0   Move FROM (offset)
           movea.l    (a6),a2    Move TO (offset)
           addq.l     #8,a2      Save first 8 bytes
           move.w     0(a1,a6.l),d2
           move.w     d2,d6      D6 is a copy of the length
           move.l     a2,a1      A1 will point at the string
           cmp.w      d7,d6      Check it'll fit!
           bcc.s      bad_param  Reject if D7>=D6
           bsr        move_str   Move D6 bytes to (A6,A2)
no_move    move.l     a0,d4      D4 is the empty stack offset
*
* Find out where we are on the screen
*
where      moveq      #-1,d3     Timeout
           move.l     d5,a0      Channel ID
           move.l     a1,d5      Save string pointer
           movea.l    (a6),a1    Put coords. at start of buffer
           trap       #4         Buffer is A6 relative
           moveq      #11,d0     SD.CHENQ
           bsr.s      call_QDOS
*
* Go to the initial cursor position and print the text
*
go_there   movea.l    (a6),a1       Find coordinate buffer 
           move.w     4(a6,a1.l),d1 Extract cursor X
           swap       d2            Save length
           move.w     6(a6,a1.l),d2 Extract cursor Y
           moveq      #16,d0        SD.POS
           bsr.s      call_QDOS
           swap       d2         Retrieve the length
           move.l     d5,a1      Restore the start pointer
           trap       #4         Pointer is A6 relative
           moveq      #7,d0      IO.SSTRG
           bsr.s      call_QDOS
           moveq      #32,d1     
           moveq      #5,d0      IO.SBYTE - blank end of line
           bsr.s      call_QDOS
           moveq      #19,d0     SD.PCOL - move cursor to blank
           bsr.s      call_QDOS
*
* Call up the editor
*
edit       move.w     d2,d1      Put cursor at end of text
           swap       d1
           move.w     d2,d1      Indicate length of text
           movea.l    (a6),a1    Find buffer
           lea.l      8(a1,d1.w),a1  Point to last character
           move.w     d7,d2      Maximum length
           trap       #4         Everything is relative!
           moveq      #4,d0      IO.EDLIN
           trap       #3
           tst.l      d0
           bpl.s      edited     No error: check terminator
           cmpi.w     #-1,d0     Did the user type BREAK?
           bne.s      whats_up
           moveq      #15,d0     SD.CURS for AH & JM ROMs
           bsr.s      call_QDOS  which leave the cursor on 
           moveq      #-1,d0     Error: not complete
begone     rts
*
whats_up   cmpi.w     #-5,d0     Buffer overflow?
           bne.s      begone     Give up if anything else!
           subq.w     #1,d1      Discard the last character
re_enter   move.w     d1,d2      Slide up to the end-stop
           bra.s      go_there   Try again
*
edited     subq.w     #1,d1      Don't count last character
           subq.l     #1,a1      Point at it
           cmpi.b     #10,0(a6,a1.l)
           bne.s      re_enter   Restart unless it was ENTER
*
enter      subq.l     #2,d4      Make room to stack length 
           move.l     d4,$58(a6) Reset maths stack pointer
           move.w     d1,d6      Keep length for move later
allocate   ext.l      d1
           move.w     $11A,a2    BV.CHRIX
           jsr        (a2)       Allocate space for text
           move.l     $58(a6),a1
           suba.w     d6,a1      Make room for text
           btst       #0,d6      Ensure A1 is even before
           beq.s      on_grid    ...stacking the length
           subq.l     #1,a1
on_grid    move.w     d6,0(a1,a6.l)
           move.l     a1,$58(a6)
           movea.l    (a6),a0
           addq.l     #8,a0      A0 is offset of text in buffer 
           lea.l      2(a1),a2   A2 is destination offset
           moveq      #1,d4      Return a string
           moveq      #0,d0      No error
*
* MOVE_STR: Moves D6 bytes, wordwise, from offset A0 to A2
*
move_str   subq.w     #1,d6      Count:=(D6-1) DIV 2
           bmi.s      null_move
           lsr.w      #1,d6      ...prepare to DBRA words
move_some  move.w     0(a6,a0.l),0(a6,a2.l)
           addq.l     #2,a2
           addq.l     #2,a0
           dbra       d6,move_some
null_move  rts       
           end
