;
;********************************************************
;*              Extended Submit for                     *
;*                      CP/M                            *
;********************************************************
;
; Revised 09/13/81 (RGF): added control character translation
;                         fixed bug in line number reporting
;
;               Version 1.1             by Ron Fowler
;               2/18/81 (first written)     Westland, MI
;
; Published in Lifelines, Volume II, Number 8- Jan 82
;
;
;       This program is intended as a replacement for the
; SUBMIT program provided with CP/M.  It provides several
; new facilities:
;       1) Nestable SUBMIT runs
;       2) Interactive entry of SUBMIT job (no need
;          to use an editor for simple SUBMIT runs)
;       3) Command line entry of small SUBMIT jobs
;       4) Ability to enter blank lines in an edited
;          SUBMIT file
;       5) User customization of number of parameters
;          and drive to send $$$.SUB to
;
;
;  Define Booleans
;
false   equ     0
true    equ     not false
;
;*************************************************************
;       --- User Customizable options ---
;
npar    equ     10      ; Number of Allowable Parameters
subdrv  equ     0       ; Make 0 for dflt - 1,2,3 for A,B,C
quiet   equ     false   ; Set to true to eliminate sign-on msg
cpbase  equ     0       ; Set to 4200h for Heath CP/M
;
;
;
;***************************************************************
;
;  CP/M Definitions
;
fpchar  equ     2       ; Print char function
printf  equ     9       ; Print string function
rdbuf   equ     10      ; Read console buffer
openf   equ     15      ; Open file function
closef  equ     16      ; Close file function
deletf  equ     19      ; Delete file function
readf   equ     20      ; Read record function
writef  equ     21      ; Write record function
makef   equ     22      ; Make (create) file function
;
bdos    equ     cpbase+5
;
fcb     equ     5ch     ; Default file control block
fcbrc   equ     15      ; FCB Offset to record  count
fcbnr   equ     32      ; FCB Offset to next record
fn      equ     1       ; FCB Offset to file name
ft      equ     9       ; FCB Offset to file type
tbuf    equ     cpbase+80h      ; Default buffer
tpa     equ     cpbase+100h     ; Transient program area
;
putcnt  equ     tbuf    ; Counter for output chars
;
;  Define Some Text Characters
;
cr      equ     13      ; Carriage return
lf      equ     10      ; Line feed
tab     equ     9       ; Tab Char
;
;  Start of Program Code
;
       org     tpa
;
;       Get the ball rolling
;
submit: lxi     h,0     ; Save stack in case
       dad     sp      ;  only help requested
       shld    spsave  ; (Not otherwise used)
       lxi     sp,stack
       call    start
;
;  Sign on Message
;
       if      not quiet
       db      'SuperSUB V1.1'
       endif
;
       db      cr,lf,'$'       ; Newline even if quiet
;
start:  pop     d       ; Retrieve string pointer
       mvi     c,printf
       lda     fcb+1   ; Anything on CMd line?
       cpi     ' '
       jz      help    ; No, Go print help
       call    bdos    ; Print the sign-on
       call    initvar ; Initialize the variable area
       call    getpar  ; Get command line parameters
       call    setup   ; Set up read of submit file
       call    rdfile  ; Read the submit file
       call    wrset   ; Set up write of "$$$.SUB"
       call    wrsub   ; Write "$$$.SUB"
       jmp     cpbase  ; Go start the SUBMIT
;
;
;  Setup sets up the file control block
;  for reading the the .SUB text file
;
setup:  lxi     h,fcb+ft  ; Look at 1st char of
       mov     a,m     ;    file type.  If it is
       cpi     ' '     ;    blank, then go move
       jz      putsub  ;    "SUB" into FT field
       lxi     d,subtyp; It's not blank to make
       mvi     b,3     ;   sure it's already
       call    compar  ;    "SUB"
       jnz     notfnd  ; If not, it's an error
       ret
;
;  Move "SUB" into the file type
;
putsub: xchg
       lxi     h,subtyp        ; By convention, move
       mvi     b,3             ;  @HL to @DE
       call    move
       ret
;
;  Move # bytes in B Register from @HL to @DE
;
move:   mov     a,m     ; Pick up
       stax    d       ; Put down
       inx     h       ; I'm sure
       inx     d       ;  you've seen this
       dcr     b       ;  before..
       jnz     move    ;
       ret
;
;  Getpar moves the substitution parameters specified
; in the command line into memory, and stores their
; addresses in the parameter table.  This allows
; substitution of $1, $2, etc., in the SUBMIT commands
; with their actual values specified in the command
; line.
;
getpar: lxi     h,tbuf+1        ; Where we find the command tail
       call    scanto  ; Skip submit file name
       sta     option  ; First char of cmd line is option
       rc              ; Line ended?
       cpi     '/'     ; No, check option
       jnz     glpo    ; Not keyboard input, read file
       inx     h       ; point past '/'
slscan: shld    clptr   ; Save cmd line ptr
       mov     a,m     ; Kbd is source, get EOL flag
       sta     clflag  ; Save as EOL flag
       cpi     ' '     ; Allow spaces after '/'
       rnz             ; Not non-blank - done
       inx     h       ; Else continue scan
       jmp     slscan
glpo:   mov     a,m     ; Input is from a .SUB file. This
       inx     h       ;   code skips over the name of
       ora     a       ;   the SUB file to get to the
       rz              ;   command line parameters
       cpi     ' '
       jz      glp
       cpi     tab
       jnz     glpo
glp:    call    scanto  ; Pass up the blanks
       rc              ; CY returned if end of cmd line
       call    putpar  ; Not put the parameter into Mem
       rc              ; CY returned if end of cmd line
       jmp     glp     ; Get them all.
;
;  SCANTO scans past blanks to the first non-blank.  If
; end of command line is found, returns carry set.
;
scanto: mov     a,m
       inx     h
       ora     a       ; Set flags on zero
       stc             ; In case zero found
       rz
       cpi     ' '
       jz      scanto  ; Scan past blanks
       cpi     tab     ; Do tabs to, just for
       jz      scanto  ;  good measure.
       dcx     h       ; Found char, point back to it
       ora     a       ; insure carry clear
       ret
;
;  PUTPAR puts the parameter pointed to by HL into
; memory pointed to by "TXTPTR".  Also stores the
; address of the parameter into the parameter table
; for easy access later, when we write $$$.SUB
;
putpar: push    h       ; Save pointer to parm
       lhld    txtptr  ; Next free memory
       xchg            ;   into DE
       lhld    tblptr  ; Next pree area of table
       mov     a,m     ; Non-zero in table
       ora     a       ;  indicates table
       jnz     parovf  ;  overflow
       mov     m,e     ; Store the parm adrs
       inx     h
       mov     m,d
       inx     h
       shld    tblptr  ; Save table pntr for next time
       pop     h       ; Get back parm pointer
       push    d       ; Save free mem pointer because
                       ;   we will have to have it back
                       ;   later to store the length
       inx     d       ; Point past length storage
       mvi     b,0     ; Initialize length of parm
pplp:   mov     a,m     ; Get next byte of parm
       inx     h
       ora     a       ; Test for end of cmd line
       jz      pp2     ; Jump if End
       cpi     ' '     ; Test for end of Command
       jz      pp2
       cpi     tab     ; Tab also ends command
       jz      pp2
       stax    d       ; Put parameter byte-by-byte
       inx     d       ;  into free memory
       inr     b       ; Bump length
       jmp     pplp
pp2:    xchg
       shld    txtptr  ; New free memory pointer
       pop     h       ; Remember our length pointer?
       mov     m,b     ; Store the length
       xchg            ; Have to retn HL > cmd line
       ora     a       ; Now return end of line flag
       stc
       rz              ; Return CY is zero (EOL Mark)
       cmc
       ret
;
;  RDFILE reads the .SUB file specified
; in the SUBMIT command into memory
;
rdfile: lxi     h,0     ; Init line number
       shld    linnum
       lda     option  ; Using a file?
       cpi     '/'     ; Option tells
       jz      line    ; Jump if not
       lxi     d,fcb   ; We are, open it.
       mvi     c,openf
       call    bdos
       inr     a       ; if 0FFh returned,
       jz      notfnd  ;   then file not found.
line:   lhld    linnum  ; Bump line number
       inx     h
       shld    linnum
       lhld    prev    ; Get prev line pointer
       xchg
       lhld    txtptr  ; Get current free mem pointer
       shld    prev    ; Make it the prev line (for next pass)
       mov     m,e     ; Store at begin of current line.
       inx     h       ;  a pointer to the previous
       mov     m,d
       inx     h
       push    h       ; Later we will put length here
       inx     h       ; Skip past length
       mvi     c,0     ; Initialize length to zero
llp:    call    gnb     ; Get next byte from input source
       jc      eof     ; CY set if end of file found
       call    ucase   ; Convert to upper case
       cpi     1ah     ;  See if CP/M End of File
       jz      eof
       cpi     lf      ; Ignore linefeeds
       jz      llp
       cpi     cr      ; If it's a carriage return,
       jz      eol     ;   then do end of line
       mov     m,a     ; Store all others into memory
       inx     h
       call    size    ; Make sure no memory overflow
       inr     c       ; Bump char count
       jm      lenerr  ; Max of 128 chars per line
       jmp     llp     ; Go to next char
;
;  Do End of Line Sequence
;
eol:    shld    txtptr  ; Save free memory pointer
       pop     h       ; Current line's length pointer
       mov     m,c     ; Store length away
       jmp     line    ; Go do next line
;
;  End of Text File
;
eof:    shld    txtptr  ; Save free memory pointer
       pop     h       ; Current line's length pointer
       mov     m,c     ; Store length away
       ret             ; All done reading SUB file
;
;  Get next byte from Input File
;
gnb:    push    h       ; Don't alter anybody
       push    d
       push    b
       lda     option  ; Input from .SUB file?
       cpi     '/'     ; Told by orig cmd line option
       jnz     nslash  ; Jump if we are
       call    gnbkbd  ; No, get a byte from kbd input
       jmp     gnbxit  ; Then leave
nslash: lda     ibp     ; Get buffer pointer
       ora     a       ; Past end?
       cm      fill    ; Wrapped around
       jnc     gnb1    ; No end of file
       mvi     1,1ah   ; Fake EOF
gnb1:   mov     e,a     ; put in DE
       mvi     d,0
       inr     a       ; Point to next
       sta     ibp     ; Put away
       lxi     h,tbuf  ; Now offset into buff
       dad     d
       mov     a,m     ; Get char there
gnbxit: pop     b       ; Restore everybody
       pop     d
       pop     h
       ora     a       ; Turn on carry
       ret
;
;  Fill input buffer
;
fill:   mvi     c,readf
       lxi     d,fcb
       call    bdos
       ora     a
       mvi     a,0
       stc
       rnz             ; Rtn CY=EOF
       cmc             ; No EOF, No CY
       ret
;
;  Come here to get a .SUB character when
;  we're not using a .SUB file ('/' option)
;
gnbkbd: lda     clflag  ; Use CP/M Cmd line?
       ora     a
       jnz     gnbcl   ; Then go do it
       lda     clcnt   ; Not, check local
       ora     a       ;   cmd line char count
       cm      clfill  ; Refill when it wraps back
       jc      gkend   ; Got carry (from CLFILL), return EOF
       dcr     a       ; Count down
       sta     clcnt
       jp      gnbcl   ; If plus, buffer not empty
       mvi     a,cr    ; Out of chars, return a CR
       ret
;
gkend:  mvi     a,1ah   ; Return EOF
       ret
;
;  Get next byte of input from cmd line @clptr
;
gnbcl:  lhld    clptr   ; Load the pointer
       mov     a,m     ; Get the char
       inx     h       ; Bump pointer for next time
       shld    clptr
       cpi     ';'     ; Logical end-of-line?
       jnz     nsemi   ; Jump if not
       mvi     a,cr    ; Yes, translate it
       ret
nsemi:  ora     a       ; Physical End-of-Line
       rnz             ;  This only needed when input
                       ;  Source is orig cpm cmd line
       mvi     a,1ah   ; Translate that to End of File
       ret
;
;  Subroutine to re-fill the local command line
;
clfill: lxi     d,prompt        ; Print a prompt
       mvi     c,printf        ; Use CP/M function 9
       call    bdos
       lxi     d,clbuf ; Now fill the buffer
       mvi     c,rdbuf
       call    bdos
       lda     clcnt   ; Return with count in A
       lxi     h,cltext        ; Reset the cmd line pointer
       shld    clptr
       ora     a       ; Set CY on len NZ
       stc
       rz
       cmc
       ret
;
;  Make sure no memory overflow
;
size:   lda     bdos+2  ; Highest page pointer
       dcr     a       ; Make it be under BDOS
       cmp     h       ; Check it against current page
       rnc             ; NC= all okay
       jmp     memerr  ; Otherwise Abort
;
;  Set up the $$$.SUB file
;   For Writing
;
wrset:  lxi     d,subfcb
       mvi     c,openf
       call    bdos    ; Open the file
       inr     a       ; Check CPM return
       jz      none1   ; None exists already
;
;  $$$.SUB exists, so set
;  FCB to append to it
;
       lda     subfcb+fcbrc    ; Get record count
       sta     subfcb+fcbnr    ; Make that next rec
       ret
;
;  Come here when no $$$.SUB exists
;
none1:  lxi     d,subfcb
       mvi     c,makef
       call    bdos
       inr     a
       jz      nomake  ; 0FFh=Can't create file
       ret
;
;  Write the "$$$.SUB" file
;
wrsub:  lhld    prev    ; This code scans backward
       mov     a,h     ;  Thru the file stored in
       ora     l       ;  memory to the first non-
       jz      notext  ;  nul line.  If none is
       mov     e,m     ;  found, Aborts
       inx     h
       mov     d,m     ; Here, we pick up pntr to prev line
       inx     h       ; Now we point to length
       xchg            ; We need to store away
       shld    prev    ;  pointer to prev line
       xchg
       mov     a,m     ; Now pick up the length
       ora     a       ; Set Z flag on length
       jnz     wrntry  ; Got line w/length: go do it
       lhld    linnum  ; Nothing here, fix line number
       dcx     h       ; (working backward now)
       shld    linnum
       jmp     wrsub
wrlop:  lhld    prev    ; Get prev line pointer
       mov     a,h
       ora     l       ; If there is no prev line
       jz      close   ;  then we are done
       mov     e,m     ; Else set up prev for next
       inx     h       ;   pass thru here
       mov     d,m
       inx     h
       xchg            ; Now store it away
       shld    prev
       xchg
wrntry: call    putlin  ; Write the line to the file
       lhld    linnum  ; Bump the line number
       dcx     h       ; Down (working back now)
       shld    linnum
       jmp     wrlop
;
;  $$$.SUB is written, Close the file
;
close:  lxi     d,subfcb
       mvi     c,closef
       jmp     bdos
;
;  This subroutine writes a line
; to the $$$.SUB file buffer,
; and flushes the buffer after
; the line is written.
;
putlin: mov     a,m     ; Pick up length byte
       inx     h       ; Point past it
       sta     getcnt  ; Make a count for "GET"
       shld    getptr  ; Make a pointer for "get"
       lxi     h,tbuf+1        ; Text goes after length
       shld    putptr  ; Make pointer for "Put"
       xra     a       ; Initialize PUT count
       sta     putcnt
       mov     b,l     ; Count for clear loop
clr:    mov     m,a     ; Zero out buffer loc
       inx     h
       inr     b       ; Count
       jnz     clr
;
;  This loop collects characters
; from the line stored in memory
; and writes them to the file.
; If the "$" parameter specifier
; is encountered, parameter sub-
; stitution is done.
;
putlp:  call    getchr  ; Pick up a character
       jc      flush   ; CY = no more char in line
       cpi     '^'     ; Control char translate prefix?
       jnz     notcx
       call    getchr  ; Yes, get the next
       jc      ccerr   ; Error: Early end of input
       sui     '@'     ; Make it a control-char
       jc      ccerr   ; Error: Too small
       cpi     ' '
       jnc     ccerr   ; Error: Too large
notcx:  cpi     '$'     ; Parameter specifier?
       jnz     stobyt  ; If not, just write char
       lda     option  ; Check option: '$' doesn't
       cpi     '/'     ;  count in '/' mode
       mvi     a,'$'   ; (Restore the '$')
       jz      stobyt
       call    lkahed  ; Peek at next char
       jc      parerr  ; Line ending means param err
       cpi     '$'     ; Another "$"?
       jnz     subs    ; If not then go do substitution
       call    getchr  ; Get the 2nd "$" (We only looked
                       ;  ahead before)
stobyt: call    putchr  ; Write char to file
       jmp     putlp
;
;  Parameter substitution...Looks up the
; parameter # after the "$" and plugs it
; in if it exists.
;
subs:   call    numtst  ; It better be a number
       jc      parerr  ;  otherwise param error
       mvi     b,0     ; Initialize parm #
       jmp     lpntry  ; We join loop in progress...
sublp:  call    lkahed  ; Look at next char
       jc      dosubs  ; If line empty, then plug in parm
       call    numtst  ; Check for numric
       jc      dosubs  ; Done in not
lpntry: call    getchr  ; Now remove the char from input stream
       sui     '0'     ; Remove ASCII bias
       mov     c,a     ; Save it
       mov     a,b     ; Our accumulated count
       add     a       ; Multiply by ten
       add     a
       add     b
       add     a
       add     c       ; then add in new digit
       mov     b,a     ; restore count
       jmp     sublp
;
;  Perform the substitution
;
dosubs: mov     a,b     ; Get parm #
       dcr     a       ; Make zero relative
       jm      parerr  ; oops
       call    lookup  ; Look it up in parm table
       jc      parerr  ; It's not there
       mov     b,a     ; Length in B
sublp1: inr     b       ; Test B for zero
       dcr     b
       jz      putlp   ; Done
       mov     a,m     ; Get char of real parameter
       inx     h       ; Point past for next time
       push    h       ; Save real parm pointer
       call    putchr  ; Put it in the file
       pop     h       ; Get back real parm pointer
       dcr     b       ; Countdown
       jmp     sublp1
;
;  Come here when a line is finished,
; and we need to write the buffer to disk.
;
flush:  lxi     d,subfcb
       mvi     c,writef
       call    bdos
       ora     a
       jnz     wrerr   ; CPM returned a write error
       ret
;
;  GETCHR gets one char from
; line stored in memory
;
getchr: lxi     h,getcnt
       mov     a,m     ; Pick up count
       dcr     a       ; Remove this char
       stc             ; Preset error
       rm              ; Return CY if out of chars
       mov     m,a     ; Update count
       lhld    getptr  ; Current char pointer
       mov     a,m     ; Pick up char
       inx     h       ; Bump pointer
       shld    getptr  ; Put it back
       cmc             ; Turn carry off
       ret
;
;  PUTCHR puts one char to
; the output buffer
;
putchr: lxi     h,putcnt
       inr     m       ; Increment count
       jm      lenerr  ; Line went to > 128 chars
       lhld    putptr  ; Get buffer pointer
       mov     m,a     ; Put char there
       inx     h       ; Bump pointer
       shld    putptr  ; Put it back
       ret             ; All done
;
;  Look ahead one char in
; the input stream.  Set
; carry if none left.
;
lkahed: lda     getcnt
       ora     a       ; See if count is down to zero
       stc             ; Preset indicator
       rz
       mov     a,m     ; Pick up char
       cmc             ; Turn off carry flag
       ret
;
;  Look up parameter with number in
; a reg.  Return A=length of parm,
; and HL => parameter
;
lookup: cpi     npar
       jnc     parovf  ; Parm # too high
       mov     l,a
       mvi     h,0     ; Now have 16 bit number
       dad     h       ; Double for word offset
       lxi     d,table
       dad     d       ; Do the offset
       mov     e,m     ; Get the address of parm
       inx     h
       mov     d,m
       mov     a,d     ; Anything there?
       ora     e
       jnz     lkupok
       xra     a       ; No, zero length
       ret
lkupok: xchg            ; Now in DE
       mov     a,m     ; Pick up length
       inx     h       ; Point past length
       ret
;
;  Utility compare subroutine
;
compar: ldax    d
       cmp     m
       rnz
       inx     h
       inx     d
       dcr     b
       jnz     compar
       ret
;
;  Numeric Test Utility Subroutine
;
numtst: cpi     '0'
       rc
       cpi     '9'+1
       cmc
       ret
;
;  Decimal output routine
;
decout: push    b
       push    d
       push    h
       lxi     b,-10
       lxi     d,-1
;
decou2: dad     b
       inx     d
       jc      decou2
       lxi     b,10
       dad     b
       xchg
       mov     a,h
       ora     l
       cnz     decout
       mov     a,e
       adi     '0'
       call    type
       pop     h
       pop     d
       pop     b
       ret
;
;  Print CR,
LF on console
;
crlf:   mvi     a,cr
       call    type
       mvi     a,lf
;
;  Print char in A on console
;
type:   push    h
       push    d
       push    b
       mov     e,a     ; Put in E for CP/M
       mvi     c,fpchar
       call    bdos    ; Print it
       pop     b
       pop     d
       pop     h
       ret
;
;  Convert char in A to Upper Case
;
ucase:  cpi     'a'     ; Validate case
       rc
       cpi     'z'+1
       rnc
       ani     5fh     ; Got LC, conv to UC
       ret
;
;  Error Handlers
;
wrerr:  call    errxit
       db      'Disk full$'
nomake: call    errxit
       db      'Directory full$'
memerr: call    errxit
       db      'Memory full$'
notfnd: call    errxit
       db      'Submit file not found$'
parerr: call    errxit
       db      'Parameter$'
parovf: call    errxit
       db      'Too many parameters:$'
lenerr: call    errxit
       db      'Line too long:$'
notext: call    errxit
       db      'Submit file empty$'
ccerr:  call    errxit
       db      'Control character$'
errxit: pop     d
       mvi     c,printf
       call    bdos
       lxi     d,errmsg        ; Print the 2nd half msg
       mvi     c,printf
       call    bdos
       lhld    linnum          ; Tell line number
       call    decout
       call    crlf
       lxi     d,subfcb        ; Delete the $$$.SUB file
       mvi     c,deletf
       call    bdos
       jmp     cpbase
;
errmsg: db      ' error on line number: $'
;
; Prompt for command line input
prompt: db      cr,lf,'*$'
;
;  Initialize all variables
;
initvar:
       lxi     h,var
       lxi     b,endvar-var
initlp: mvi     m,0             ; Zero entire var area
       inx     h
       dcx     b
       mov     a,b
       ora     c
       jnz     initlp
       lxi     h,table ; Init parm table pointer
       shld    tblptr
       lxi     h,0ffffh; Mark end of table
       shld    endtbl
       lxi     h,fremem; Free memory starts txt area
       shld    txtptr
       mvi     a,80h   ; Force read
       sta     ibp
       sta     clcnt   ; Force console read
       ret
;
;  Print help with program options
;
help:   lxi     d,hlpmsg  ; Print the help stuff
       mvi     c,printf
       call    bdos
       lhld    spsave  ; Then return w/no warm boot
       sphl
       ret
;
hlpmsg: db      cr,lf,'How to use SUPERSUB:',cr,lf
       db      cr,lf,'SUPERSUB<CR>             :print this HELP message'
       db      cr,lf,'SUPERSUB /<CR>           :go into interactive mode'
       db      cr,lf,'SUPERSUB /<cmd lines>    :use SUMMARY mode'
       db      cr,lf,'SUPERSUB <FILE> <PARMS>  :as in standard SUBMIT.COM'
       db      cr,lf
       db      cr,lf,'IN "/" (interactive) mode, SUPERSUB will prompt you'
       db      cr,lf,'a line at a time for the SUBMIT job input...logical'
       db      cr,lf,'lines may be combined on the same input line by sep-'
       db      cr,lf,'erating them with semicolons.  Example:'
       db      cr,lf,'   A>SUPERSUB /STAT;DIR'
       db      cr,lf,'specifies two commands on the same input line.',cr,lf
       db      cr,lf,'Submitted jobs may be nested...SUPERSUB does not erase'
       db      cr,lf,'any existing submit job (appends to them instead).'
       db      cr,lf
       db      cr,lf,'To insert a control character into the output, pre-'
       db      cr,lf,'fix it with a "^" (works in any mode).'
       db      cr,lf,'$'
;
;  Variable Storage
;
var     equ     $
;
txtptr: dw      0       ; Free memory pointer
tblptr: dw      0       ; Pointer to Parm Table
linnum: dw      0       ; Current line number
prev:   dw      0       ; Pointer to previous line
getcnt: db      0       ; Counter for 'Get'
getptr: dw      0       ; Pointer for 'Get'
putptr: dw      0       ; Pointer for 'Put'
ibp:    db      0       ; Input Buffer Pointer
clptr:  dw      0       ; Command Line Pointer
clflag: db      0       ; Use CP/M cmd line flag
option: db      0       ; '/' option flag store
table:  ds      npar*3  ; Parameter table
endtbl: dw      0       ; End of Parameter table
;
endvar  equ     $
;
;  Command Line Buffer... Not Initialized
;
clbuf:  db      128     ; Buffer length
clcnt:  db      0       ; Character Counter
cltext: ds      128     ; The buffer itself
;
spsave: dw      0       ; Stack Pointer Save
;
;
;  FCB for $$$.SUB
;
subfcb: db      subdrv  ; Driver Specifier
       db      '$$$     '
subtyp: db      'SUB'
       dw      0,0,0,0 ; Initialize rest of FCB
       dw      0,0,0,0
       dw      0,0
;
;  Stack Area
;
       ds      200
stack   equ     $
fremem  equ     $
;
       end     submit