OBJNAM FREESP.LIT ; Created 29-Oct-85, Last modified 3-Apr-86
; by Irv Bromberg, Medic/OS Consultants, Toronto, CANADA
RADIX 10
VEDIT=18
VMINOR=2
VMAJOR=2
VSUB=0

IF EQ,1

Assembled under AMOS/L 1.3 FREESP.LIT version 2.2(18) size=364 bytes,
hash=332-014-453-455.

Syntax: FREESP bytes{K}{/I} command

Reserves free space at the top of the user's partition prior to
execution of a the specified command.  This free space is made available
the next time the user's job executes a KBD monitor call with his
terminal in LINE INPUT MODE.  The Bytes count is specified as a base-10
number and can optionally be followed by a "K" for kilobytes.  The
command can be any monitor-level command at all.  The maximum is 32K.
The space reserved is in addition to any that would become free from
processing of any pending CMD file already at the top of the user's
partition (total limit 32K bytes).

The /I switch causes the command to be immediately executed using an
AMOS monitor call instead of the normal mode where an EXIT monitor
call is allowed to invoke the command indirectly.  The Immediate mode
is intended to be used only when debugging using SuperFIX -- it uses
slightly more partition space (occupied by FREESP.LIT module) and the
command being invoked MUST NOT be a CMD or DO file.

Here are some example of use with AlphaBASIC:

.freesp 8k basic       ; reserves 8K bytes, goes into Interactive BASIC,
AlphaBASIC Version 1.3(196)

READY          (Notice the exclamation from the FREESP memory cmd file
!                  displays immediately, 8K bytes immediately free)
xcall freesp,free      (AlphaBASIC always leaves 8 bytes free at the
print "Free=";free     top of the user's partition, this is in addition
Free= 8204             to the amount reserved by FREESP, therefore we
                       get 8K+8 =8*1024+8 =8192+8 =8204 bytes free here)

Also note that for efficiency FREESP always rounds up the Number specified
so that the number of bytes to be nulled is divisible by 4, allowing a
longword at a time to be cleared.

.freesp 8k run prog    ; reserves 8K bytes

To free up the space reserved by the above command the program can do any of
the following:

-- invoke a dummy string INPUT or INPUT LINE statement, this will return
  "!" as the input (will also echo !<cr><lf> on the user's screen) and
  will flush away the FREESP cmd file, freeing up the reserved space.
-- XCALL FREESP,Free    ! frees up the freespace and returns how much to
  the floating variable, Free.  Can be used anytime to return total free.
-- XCALL AMOS (the Medic/OS AMOS.SBR checks for the FREESP cmd file and
  automatically flushes it to free up the reserved freespace).
-- invoke any other XCALL subroutine which executes a KBD monitor call in
  line input mode.

Both the Medic/OS FREESP.SBR and AMOS.SBR prevent the !<cr><lf> from
echoing to the user's screen when flushing the FREESP cmd file.

Edit history:
2-Jan-86  2.0(16) Major rewrite: mark reserved space with "!" so FREESP.SBR
                 can check for it; Number adjusted for CRLF ! CRLF,
                 length of command and current CMD file size; Max total
                 CMD file size is 32K - check adjusted Number for this.
2-Jan-86  2.1(17) correct the longword Number rounding routine
3-Apr-86  2.2(18) add /I switch to use AMOS call to Immediately execute cmd
ENDC

SEARCH SYS
SEARCH SYSSYM

JCB=A0
SavBuf=A1
Buffer=A2
UEND=A3
UFRE=A4
TCB=A5
Atemp=A6

Number=D1
Free=D2
CMDSIZ=D3
Length=D4
Dtemp=D6

CR=13
LF=10

       PHDR    -1,0,PH$REE!PH$REU      ; re-entrant & re-usable

       JOBIDX  JCB

GetNUM: GTDEC                           ; get the number of bytes to reserve
       JMI     Syntax
       TST     Number
       JEQ     Syntax
       CMPB    (Buffer)+,#'K           ; kilobytes?
       BNE     ChkEND
       MUL     Number,#1024            ; yes, x1024

ChkEND: USRFRE  UFRE
       MOV     JOBBAS(JCB),UEND        ; calculate USREND addr
       ADD     JOBSIZ(JCB),UEND
       SUBW    JOBCMZ(JCB),UEND        ; pointing at next command file char
       CLR     CMDSIZ                  ; pre-clear
       MOV     UEND,Dtemp              ; test if odd address
       LSR     Dtemp
       BCC     ChkSW                   ; carry clear if already even
       CLRB    -(UEND)                 ; make it even
       INCW    CMDSIZ                  ; remember we did so

ChkSW:  BYP
       CMPB    @Buffer,#'/             ; switch present?
       BNE     ChkLEN
       INCW    Buffer
       CMPB    (Buffer)+,#'I           ; is it /I switch?
       BEQ     10$
       TYPECR  <?Illegal switch>       ; no, illegal
       EXIT
10$:    BYP                             ; and skip next whitespace
       ; when /I is specified we don't copy command line to FREESP cmd file
       CLR     Length                  ; use 0 as flag that /I was specified
       BR      ChkLN2

ChkLEN: MOV     Buffer,SavBuf
10$:    LIN                             ; determine length of remaining
       BEQ     20$                     ; command line
       INC     Buffer
       BR      10$
20$:    MOV     Buffer,Length           ; make sure there will be room to also
       SUB     SavBuf,Length           ; put the cmd line at beginning
       ADD     Length,CMDSIZ           ; add length of command line
       ADD     #2,CMDSIZ               ; +2 for CRLF after cmd
ChkLN2: ADD     #3,CMDSIZ               ; +3 for ! CRLF
       SUB     #3,Number               ; adjust Number for ! CRLF only
Round:  INC     Number                  ; round up to even longword quantity
       LSR     Number
       INC     Number
       LSR     Number
       LSL     Number,#2
       ADD     Number,CMDSIZ           ; now we can add Number into total
       CLR     Dtemp                   ; pre-clear for word move
       MOVW    JOBCMZ(JCB),Dtemp       ; get current command file size
       ADD     Dtemp,CMDSIZ
       CMP     CMDSIZ,#32768           ; must be less than 32K
       BLO     ChkFRE
       TYPECR  <?Memory command file size would exceed 32K bytes>
       EXIT

ChkFRE: MOV     UEND,Free
       SUB     UFRE,Free               ; calculated #bytes free
       SUB     #4,Free                 ; allow for 0 to end module chain
       MOV     Length,Dtemp            ; length of command to execute
       BEQ     10$                     ; 0=immediate execute mode
       ADD     #2,Dtemp                ; for CRLF
10$:    ADD     #3,Dtemp                ; for ! CRLF
       ADD     Number,Dtemp
       CMP     Dtemp,Free              ; are we asking for too much?
       BLO     Clear                   ; no, we can do it!
       TYPECR  <?Not enough free memory>
       EXIT

Clear:  LSR     Number,#2               ; /4 for longword clear
       BR      LpDBF                   ; enter at end of DBF loop
Loop:   CLR     -(UEND)
LpDBF:  DBF     Number,Loop
       TSTW    JOBCMZ(JCB)             ; command file already being processed?
       BNE     5$                      ; yes
       ANDW    #^C<C.TRC>,JOBCMS(JCB)  ; no, turn off trace mode
5$:     MOVW    CMDSIZ,JOBCMZ(JCB)      ; fool OS into thinking there is a
                                       ; NULL command file at the top
       MOVB    #LF,-(UEND)             ; First CRLF needed to terminate the
       MOVB    #CR,-(UEND)             ; command we're invoking.
       MOVB    #'!,-(UEND)             ; "!" is checked for by FREESP.SBR
       TST     Length                  ; =0 if immediate exec mode
       BEQ     Immed
       MOVB    #LF,-(UEND)             ; CRLF needed to hold the NULLs in the
       MOVB    #CR,-(UEND)             ; freespace until the command runs.
       BR      20$                     ; enter at end of DBF loop
10$:    MOVB    -(Buffer),-(UEND)       ; copy remainder of cmd line
20$:    DBF     Length,10$
       EXIT                            ; let the monitor execute it...

Immed:  AMOS                            ; immediately execute the command
       EXIT

Syntax: TYPECR  <?Syntax: FREESP bytes{K} command>
       EXIT

       END