home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / jsage / znode3 / uploads / onpack.lbr / ONADD.AZM / ONADD.ASM
Encoding:
Assembly Source File  |  1993-06-07  |  40.5 KB  |  1,994 lines

  1.     title    'ONADD on-screen adding-machine program'
  2. ;
  3. ; Last revised: 07/19/87 (rgf)
  4. ;
  5. ;    *********************************************
  6. ;    *                        *
  7. ;    *  ONADD on-screen adding machine program   *
  8. ;    *                        *
  9. ;    *********************************************
  10. ;
  11. ;    Copyright (c) 1987 ON!;Systems, Inc.
  12. ;
  13. ; Written for ON!Systems, Inc. by Ronald G. Fowler
  14. ;                  Fort Atkinson, WI
  15. ;
  16.     name    ('ONADD')
  17. ;
  18.     extrn    fpinp,fpout    ;FLOAT routines
  19.     extrn    fpadd,fpsub,fpmul,fpdiv
  20.     extrn    facc        ;float accumulator
  21. ;
  22.     extrn    ffree
  23.     public    base,formot
  24. ;
  25. ; ONADD constants
  26. ;
  27. digitl    equ    10        ;digits to left of dp
  28. digitr    equ    2        ;digits to right of dp
  29. cmtlen    equ    31        ;length of comment
  30. scline    equ    6        ;line from which scrolls occur
  31. iline    equ    22        ;line for input
  32. numsiz    equ    digitr+digitl+1    ;number input field size: rt + lft + dp
  33. spc1    equ    2        ;spacing between num field and flags
  34. spc2    equ    10        ;spacing between flags and comment
  35. flgcol    equ    numsiz+spc1    ;flag column
  36. fls    equ    3        ;size of flag column
  37. cmtcol    equ    flgcol+spc2+fls    ;comment column
  38. ;
  39. ; PUTSW bits
  40. ;
  41. scrbit    equ    00000001b    ;1=write to screen
  42. filbit    equ    00000010b    ;1=write to file
  43. ;
  44. ;
  45. ; Float size definition ... must match definition in FLOATx.REL.
  46. ;
  47. digits    equ    16        ;# significant digits (internal): must be EVEN
  48. fpsize    equ    (digits/2)+1    ;float size (fixed, don't change this!)
  49. ;
  50. dirio    equ    6        ;direct I/O system call
  51. system    equ    5        ;system entrypoint
  52. tpa    equ    0100H        ;transient program area
  53. ;
  54. ;
  55. cr    equ    13        ;carriage return
  56. lf    equ    10        ;linefeed
  57. bs    equ    8        ;backspace
  58. tab    equ    9        ;horizontal tab
  59. bell    equ    7        ;
  60. escape    equ    01BH
  61. ;
  62. ; definition of keys
  63. ;
  64. togkey    equ    escape        ;keycode that toggles between num & comment
  65. cekey    equ    'X'-64        ;control-X=clear entry
  66. subkey    equ    '\'        ;subtotal key
  67. tabkey    equ    tab
  68. mskey    equ    'M'        ;memory-store key
  69. mrkey    equ    'R'        ;memory-recall key
  70. ;
  71. multi    macro    what,cnt
  72.     rept    cnt
  73.     db    what
  74.     endm
  75.     endm
  76. ;
  77. ;
  78. ;    ****************************
  79. ;    * Video interface routines *
  80. ;    ****************************
  81. ;
  82.     org    tpa
  83. ;
  84. base:    jmp    start        ;skip over video stuff
  85. ;
  86. ; ZCPR3 stuff
  87. ;
  88. envlit:    db    'Z3ENV'        ;Z3-compatible utility
  89.     db    1        ;external environment
  90. z3eadr:    dw    0        ;env address
  91. ;
  92. ;------------------------------------------------------------
  93. ;
  94. ;    *******************************
  95. ;    * Terminal Interface Routines *
  96. ;    *******************************
  97. ;
  98. ; Jump table
  99. ;
  100. curadr:    jmp    acur
  101. cls:    jmp    acls
  102. dellin:    jmp    adelln
  103. inslin:    jmp    ainsln
  104. ;
  105. ; The routines ...
  106. ;
  107. ; Address cursor, D=row, E=column
  108. ;
  109. acur:    xchg
  110.     shld    cursor
  111.     xchg
  112.     mvi    a,escape
  113.     call    outchr
  114.     mvi    a,'='
  115.     call    outchr
  116.     mov    a,d        ;send row
  117.     adi    ' '
  118.     call    outchr
  119.     mov    a,e        ;column
  120.     adi    ' '
  121.     jmp    outchr
  122. ;
  123. ; delete line at cursor position
  124. ;
  125. adelln:    mvi    a,escape
  126.     call    outchr
  127.     mvi    a,'R'
  128.     jmp    outchr
  129. ;
  130. ; insert line at cursor position
  131. ;
  132. ainsln:    mvi    a,escape
  133.     call    outchr
  134.     mvi    a,'E'
  135.     jmp    outchr
  136. ;
  137. acls:    mvi    a,01AH
  138.     jmp    outchr
  139. ;
  140. ; Character output for terminal routines
  141. ;
  142. outchr:    push    h
  143.     push    d
  144.     push    b
  145.     push    psw        ;save everybody
  146.     mov    e,a        ;output from E
  147.     mvi    c,dirio        ;direct console I/O
  148.     cpi    0FEH        ;validate character, so strange char-
  149.     cc    bdos        ;  acters don't become input requests
  150.     pop    psw
  151.     pop    b        ;unstack and return
  152.     pop    d
  153.     pop    h
  154.     ret
  155.  
  156. ;
  157. ; end of terminal interface
  158. ;
  159. ;------------------------------------------------------------
  160. ;
  161.     org    tpa+200h    ;locate beyond terminal interface
  162. ;
  163. ;
  164. ;    *************
  165. ;    * Data Area *
  166. ;    *************
  167. ;
  168. inkbuf:    ds    numsiz+2    ;field size + slop
  169. membuf:    ds    numsiz+2    ;MEM
  170. cmtbuf:    ds    cmtlen+2    ;comment buffer
  171. opfld:    db    '   ',0        ;operator flag field
  172. ;
  173. mdiv:    ds    1        ;M diversion flag
  174. mptr:    ds    2        ;pointer for M diversion
  175. msflag:    ds    1        ;M store flag
  176. ;
  177. obp:    ds    2        ;output buffer pointer
  178. outcnt:    ds    2        ;output char count
  179. memtop:    ds    2        ;top of memory
  180. ;
  181. padcnt:    ds    1        ;# padding blanks required
  182. padchr:    ds    1        ;character to pad with
  183. rollct:    ds    1        ;scroll-count
  184. opcode:    ds    1        ;operator code
  185. op1:    ds    1        ;opcode for num1
  186. temp:    ds    2        ;temp for context switch
  187. tempx:    ds    1        ;temp for CMNT
  188. ;
  189. spsave:    ds    2        ;system stackpointer save
  190.     ds    80        ;local stack
  191. stack:    db    0        ;take up space (for debugger)
  192. num1:    ds    fpsize        ;input buffer 1
  193. num2:    ds    fpsize        ;input buffer 2
  194. termch:    db    0        ;RDFLD terminator character
  195. cursor:    ds    2        ;current cursor address
  196. z3flag:    db    0
  197. ceflag:    db    0        ;double clear-entry flag
  198. hold:    ds    fpsize
  199. contxt:    ds    7        ;cmt context-save: flg, curad, ctrs, ptr
  200. putsw:    ds    1        ;bit 1=1 if write-file, 0=1 if write scrn
  201. outflg:    ds    1        ;gets reset if file buffer fills
  202. recalc:    ds    1        ;recalc flag
  203. pfield:    db    0,0        ;prompt column,row
  204. ;
  205. ; context switch stuff
  206. ;
  207. consp:    ds    2        ;consumer stacklevel
  208. prosp:    ds    2        ;producer stacklevel
  209. ;
  210. ; producer stack
  211. ;
  212.     ds    40        ;growth space
  213. prost:    dw    0,0,0        ;initial registers
  214. protop:    ds    2        ;top of the stack
  215. ;
  216. ;------------------------------------------------------------
  217. ;
  218. ;
  219. ; We begin ...
  220. ;
  221. start:    lxi    h,0        ;save stackpointer
  222.     dad    sp
  223.     shld    spsave
  224.     xra    a        ;no recalc yet
  225.     sta    recalc
  226.     lxi    sp,stack    ;load local stack
  227.     mvi    a,scrbit    ;reset PUT switch
  228.     sta    putsw
  229.     call    putscr        ;put up screen
  230.     call    nitfil        ;init file stuff
  231. ;
  232. ; loop here for each expression
  233. ;
  234. main:    call    linput        ;get a number
  235.     jc    main        ;double-CE here has nothing to clear
  236.     lxi    d,num1
  237.     lxi    h,inkbuf
  238.     call    fpinp        ;input float
  239.     lda    opcode        ;get opcode
  240.     sta    op1
  241.     call    scroll        ;roll up the screen
  242. ;
  243. ; loop here for each successive term
  244. ;
  245. main2:    call    linput        ;get another number
  246.     jnc    main3        ;jump if not double CE
  247.     call    scroll        ;give it up
  248.     jmp    main
  249. main3:    lxi    d,num2
  250.     lxi    h,inkbuf
  251.     call    fpinp
  252.     call    scroll        ;roll the screen up
  253.     lxi    h,num1
  254.     lxi    d,num2
  255.     lda    opcode        ;first, check for '-', (reverse Polish)
  256.     cpi    '-'        ;  which Richard J. says is how *real*
  257.     jnz    notpol        ;  calculators work their minus key
  258.     mvi    a,'+'        ;it's a minus, set up an add for next
  259.     sta    opcode        ;yes, really ...
  260.     jmp    subit        ;but this time, subtract
  261. notpol:    lda    op1        ;not minus, apparently not reverse Polish
  262.     cpi    '+'        ;so be algebraic
  263.     jz    addit
  264.     cpi    '-'
  265.     jz    subit
  266.     cpi    '*'
  267.     jz    multit
  268.     cpi    '/'
  269.     jz    divit
  270. addit:    call    fpadd
  271.     jmp    opjoin
  272. subit:    call    fpsub
  273.     jmp    opjoin
  274. multit:    call    fpmul
  275.     jmp    opjoin
  276. divit:    call    fpdiv
  277. opjoin:    call    movfac
  278.     lda    opcode        ;get most recent op
  279.     cpi    tabkey        ;total?
  280.     jz    total        ;jump if so
  281.     cpi    subkey        ;
  282.     jnz    nsub
  283.     mvi    a,'='
  284.     call    subtot        ;show subtotal
  285.     mvi    a,'+'        ;plus ADD
  286.     call    opshow
  287.     call    scroll
  288.     mvi    a,'+'        ;really an add
  289. nsub:    sta    op1        ;not yet
  290.     lxi    h,hold        ;move HOLD to NUM1
  291.     lxi    d,num1
  292.     call    fpmove
  293.     jmp    main2
  294. ;
  295. ; here at the end of a series
  296. ;
  297. total:    mvi    a,scrbit+filbit
  298.     sta    putsw        ;put this in file too
  299.     lxi    h,dash
  300.     call    prathl
  301.     mvi    a,scrbit    ;back to screen only
  302.     sta    putsw
  303.     call    scroll
  304.     mvi    a,'T'
  305.     call    subtot
  306.     call    scroll
  307.     call    scroll
  308.     jmp    main
  309. ;
  310. subtot:    push    psw
  311.     mvi    a,scrbit+filbit
  312.     sta    putsw        ;screen + file
  313.     lxi    h,hold
  314.     call    fpout        ;write to screen and file
  315.     mvi    a,' '
  316.     call    wrfbyt        ;space over in file
  317.     pop    psw        ;show opcode 'T'
  318.     call    opshow
  319.     mvi    a,scrbit    ;screen only
  320.     sta    putsw
  321.     ret
  322. ;
  323. linput:    xra    a        ;no comment context yet
  324.     sta    contxt
  325.     sta    mdiv        ;no M diversion yet
  326.     sta    msflag        ;no memory-store yet
  327.     mvi    e,0        ;E holds total buffer char count
  328.     lxi    h,inkbuf    ;HL addresses the buffer
  329.     lxi    b,(digitl*256)    ;B has positions-left, C is DP flag
  330. keylp:    mvi    m,0        ;keep terminator
  331.     call    shobuf        ;display the buffer
  332. rekey:    call    linchr        ;get a char
  333.     call    cvtuc        ;upshift
  334.     cpi    mrkey        ;memory recall?
  335.     jnz    notmr        ;jump if not
  336.     mov    a,e        ;buffer must be empty
  337.     ora    a
  338.     jnz    rekey
  339.     push    h        ;yes
  340.     mvi    a,'M'        ;flag it
  341.     call    opshow
  342.     mvi    a,'R'
  343.     call    opshow
  344.     lxi    h,membuf    ;set pointer
  345.     shld    mptr
  346.     mvi    a,1        ;set M divert flag
  347.     sta    mdiv
  348.     pop    h
  349.     jmp    rekey        ;onward
  350. notmr:    cpi    mskey        ;memory store?
  351.     jnz    notms        ;jump if not
  352.     lda    msflag        ;already done memory store?
  353.     ora    a
  354.     jnz    rekey        ;jump if so
  355.     mvi    a,1        ;well, we have now
  356.     sta    msflag
  357.     mvi    a,'M'        ;flag it
  358.     call    opshow
  359.     mvi    a,'S'
  360.     call    opshow
  361.     push    h        ;copy buffer to MEM
  362.     push    d
  363.     push    b
  364.     lxi    h,inkbuf
  365.     lxi    d,membuf
  366. mvmem:    mov    a,m
  367.     stax    d
  368.     inx    h
  369.     inx    d
  370.     ora    a
  371.     jnz    mvmem
  372.     call    shomem        ;display it
  373.     pop    b
  374.     pop    d
  375.     pop    h
  376.     jmp    rekey
  377. notms:    cpi    cekey        ;clear-entry?
  378.     jnz    notce
  379.     lxi    h,ceflag    ;check flag
  380.     mov    a,m        ;2 CE's in a row?
  381.     mvi    m,1        ;(set the flag)
  382.     ora    a
  383.     stc
  384.     rnz            ;exit CY=1 if so
  385.     lxi    d,(iline*256)+cmtcol+1
  386.     call    curadr        ;address comment
  387.     lxi    h,cblank
  388.     call    prathl        ;print blanks
  389.     jmp    linput        ;re-enter
  390. ;
  391. notce:    push    psw
  392.     xra    a        ;reset clear-entry flag
  393.     sta    ceflag
  394.     pop    psw
  395.     call    alpha        ;A-Z or a-z?
  396.     jnc    yestog        ;toggle to note field if so
  397.     cpi    togkey        ;escape key?
  398.     jnz    notesc        ;jump if not
  399. yestog:    push    h        ;yes, stack 'em all
  400.     push    d
  401.     push    b
  402.     call    cmnt        ;input the comment
  403.     pop    b
  404.     pop    d
  405.     pop    h
  406.     jc    keylp        ;jump if toggle
  407.     jmp    ndp        ;must be <cr>
  408. notesc:    call    digchk        ;is this a digit?
  409.     jc    notdig        ;jump if not
  410.     inr    b        ;yes.  Is there space for another?
  411.     dcr    b
  412.     jz    rekey        ;ignore it if not
  413.     mov    m,a        ;there is, stuff it
  414.     inx    h
  415.     dcr    b        ;one less position
  416.     inr    e        ;one more char
  417.     jmp    keylp        ;onward
  418. notdig:    cpi    bs        ;check for bs or rub
  419.     jz    isrub
  420.     cpi    07fh
  421.     jnz    notrub
  422. isrub:    mov    a,e        ;anything in buffer?
  423.     ora    a
  424.     jz    rekey        ;ignore if nothing
  425.     dcr    e        ;one less character
  426.     inr    b        ;one more position
  427.     dcx    h        ;point one backward
  428.     mov    a,m        ;get what's there
  429.     cpi    '.'        ;deleting the DP?
  430.     jnz    keylp        ;jump if not
  431.     mvi    c,0        ;yes, reset the DP flag
  432.     lda    padcnt        ;get positions free on left
  433.     mov    b,a
  434.     jmp    keylp        ;onward
  435. ;
  436. notrub:    cpi    '.'        ;decimal point?
  437.     jnz    ndp        ;\jump if not
  438.     mov    a,c        ;yes, test flag
  439.     ora    a
  440.     jnz    rekey        ;if already have dp, ignore it
  441.     inr    c        ;set dp flag
  442.     mov    a,b        ;set pad count for SHOBUF
  443.     sta    padcnt
  444.     mvi    m,'.'        ;put dp in buffer
  445.     inx    h
  446.     inr    e        ;add to length
  447.     mvi    b,digitr    ;get right-of-dp max
  448.     jmp    keylp
  449. ndp:    push    b
  450.     call    opchek        ;operator?
  451.     jnz    notop        ;jump if not
  452.     mov    a,b        ;save the code
  453.     sta    opcode
  454.     pop    b
  455.     lxi    h,inkbuf    ;normalize
  456.     call    normal
  457.     mvi    a,filbit+scrbit    ;write to screen and file
  458.     sta    putsw
  459.     mvi    c,1        ;decimal point there now
  460.     call    shobuf        ;re-display
  461.     mvi    a,' '        ;space over in file
  462.     call    wrfbyt
  463.     lda    opcode
  464.     call    opshow
  465.     lxi    h,cmtbuf    ;got a comment?
  466.     mov    a,m
  467.     ora    a
  468.     jz    endcmt        ;jump if not
  469.     mvi    a,' '        ;yes, space over
  470.     call    wrfbyt
  471. cmtwr:    mov    a,m
  472.     inx    h
  473.     ora    a
  474.     jz    endcmt
  475.     call    wrfbyt        ;write to file
  476.     jmp    cmtwr
  477. endcmt:    mvi    a,scrbit    ;back to screen only
  478.     sta    putsw
  479.     ora    a
  480.     ret
  481. notop:    pop    b
  482.     cpi    'C'-64        ;abort?
  483.     jnz    notcc        ;jump if not
  484.     push    d
  485.     push    h
  486.     lxi    d,xitmsg
  487.     call    ynprmt        ;get Y/N prompt
  488.     pop    h
  489.     pop    d
  490.     cpi    'Y'
  491.     jnz    keylp        ;if not Y, continue
  492. exit:    call    wrtfil        ;maybe write an output file
  493.     lxi    d,iline*256
  494.     call    curadr
  495.     lhld    spsave
  496.     sphl
  497.     ret
  498. ;
  499. ; print msg .DE in prompt field, get Y/N response
  500. ;
  501. ynprmt:    lhld    cursor
  502.     push    h        ;save cursor pos
  503.     call    prpmt        ;print prompt
  504.     call    getyn
  505.     pop    d
  506.     push    psw
  507.     call    clearp        ;clear prompt file
  508.     call    curadr        ;restore cursor
  509.     pop    psw
  510.     ret
  511. ;
  512. getyn:    call    charin
  513.     call    cvtuc
  514.     cpi    'Y'
  515.     rz
  516.     cpi    'N'
  517.     jnz    getyn        ;wait for Y/N
  518.     ret
  519. ;
  520. ; print msg .DE in prompt field
  521. ;
  522. prpmt:    lhld    pfield        ;prompt loc
  523.     xchg
  524.     call    curadr
  525.     call    prathl        ;print the message
  526.     ret
  527. ;
  528. ; LINPUT get char routine
  529. ;
  530. linchr:    lda    mdiv        ;M key diversion active?
  531.     ora    a
  532.     jz    charin        ;get from keyboard if not
  533.     push    h        ;yes, get from MEM
  534.     lhld    mptr
  535.     mov    a,m
  536.     inx    h        ;advance
  537.     shld    mptr
  538.     pop    h
  539.     ora    a        ;got something?
  540.     rnz            ;exit if so
  541.     sta    mdiv        ;nope, reset M diversion
  542.     jmp    charin        ;and get from keyboard
  543. ;
  544. ; normalize input buffer .HL (to 2 decimal places)
  545. ;
  546. normal:    mov    a,m        ;fetch
  547.     ora    a        ;end?
  548.     jz    nodot        ;jump, no DP found
  549.     inx    h        ;else advance
  550.     cpi    '.'        ;DP?
  551.     jnz    normal        ;loop if not
  552.     mov    a,m        ;first place present?
  553.     ora    a
  554.     jz    norm2        ;if not, go normalize 2
  555.     inx    h
  556.     mov    a,m        ;second?
  557.     ora    a
  558.     jz    norm1        ;if not, normalize 1
  559.     ret            ;both present, exit
  560. nodot:    mov    a,b        ;set pad count
  561.     sta    padcnt
  562.     mvi    m,'.'        ;add DP
  563.     inx    h
  564.     inr    e
  565. norm2:    mvi    m,'0'
  566.     inx    h
  567.     inr    e
  568. norm1:    mvi    m,'0'
  569.     inx    h
  570.     inr    e
  571.     mvi    m,0        ;terminator
  572.     lxi    b,1        ;B=0 (no free dig right), C=1 (DP flag)
  573.     ret
  574. ;
  575. notcc:    jmp    rekey        ;unknown key
  576. ;
  577. ; check for operator key
  578. ;
  579. opchek:    mvi    b,tabkey
  580.     cmp    b
  581.     rz
  582.     mvi    b,subkey
  583.     cmp    b
  584.     rz
  585.     mvi    b,'+'
  586.     cpi    cr
  587.     rz
  588.     cpi    '+'
  589.     rz
  590.     mvi    b,'-'
  591.     cmp    b
  592.     rz
  593.     mvi    b,'/'
  594.     cmp    b
  595.     rz
  596.     mvi    b,'*'
  597.     cpi    'x'
  598.     rz
  599.     cpi    'X'
  600.     rz
  601.     cmp    b
  602.     ret
  603. ;
  604. ; Input the comment field.  Now, we have to remember
  605. ; what character we came in with, because an alpha
  606. ; character must shift into comment mode.  Which is
  607. ; the way it originally worked, but they didn't like
  608. ; it that way. (A programmer's work is never done ...).
  609. ;
  610. cmnt:    sta    tempx        ;save the damned character
  611.     lxi    h,contxt    ;have we already started cmt field?
  612.     mov    a,m
  613.     ora    a
  614.     jz    newcmt        ;go start new if not
  615.     inx    h        ;yes, address saved context
  616.     mov    e,m        ;fetch cursor adrs
  617.     inx    h
  618.     mov    d,m
  619.     inx    h
  620.     call    curadr        ;go there
  621.     mov    c,m        ;load counters  and pointer
  622.     inx    h
  623.     mov    b,m
  624.     inx    h
  625.     mov    a,m
  626.     inx    h
  627.     mov    h,m
  628.     mov    l,a
  629.     jmp    cktemp        ;go examine key
  630. newcmt:    lxi    d,(iline*256)+cmtcol+1
  631.     push    d
  632.     call    curadr
  633.     mvi    a,' '
  634.     mvi    b,cmtlen    ;blank field
  635.     call    rchar
  636.     pop    d
  637.     call    curadr
  638.     mvi    b,cmtlen-1    ;max
  639.     mvi    c,0        ;length of comment
  640.     lxi    h,cmtbuf    ;comment buffer
  641. cktemp:    lda    tempx        ;get the char we entered with
  642.     call    alpha        ;is it printable? (might be ESC)
  643.     jnc    okalph        ;jump if so
  644. await:    mvi    m,0        ;maintain terminator
  645.     call    charin
  646.     cpi    togkey        ;got an escape?
  647.     jnz    noteky        ;jump if not
  648.     shld    contxt+5    ;yes, save the context
  649.     lhld    cursor        ;get cursor adrs
  650.     xchg            ;to DE
  651.     lxi    h,contxt
  652.     mvi    m,1        ;flag a context is saved
  653.     inx    h
  654.     mov    m,e        ;save cursor adrs
  655.     inx    h
  656.     mov    m,d
  657.     inx    h
  658.     mov    m,c        ;save counters
  659.     inx    h
  660.     mov    m,d
  661.     inx    h
  662.     stc            ;return toggle, not done
  663.     ret            ;all done, back to number field
  664. ;
  665. noteky:    cpi    'x'        ;these three codes ...
  666.     jz    okalph        ; ... have to be pre-checked
  667.     cpi    'X'        ; ... because OPCHEK will re-
  668.     jz    okalph        ; ... return a TRUE, and they
  669.     cpi    subkey        ; ... really aren't operators
  670.     jz    okalph        ; ... in the comment field.
  671. ;
  672.     push    b        ;opcode?
  673.     call    opchek
  674.     pop    b
  675.     rz            ;exit if so
  676.     cpi    07FH
  677.     jz    crub
  678.     cpi    bs
  679.     jnz    nrub
  680. crub:    mov    a,c        ;are we all the way back?
  681.     ora    a
  682.     jz    await        ;ignore this if so
  683.     dcx    h        ;back up
  684.     mvi    a,bs        ;remove char on screen
  685.     call    type
  686.     mvi    a,' '
  687.     call    type
  688.     mvi    a,bs
  689.     call    type
  690.     inr    b        ;add a position
  691.     dcr    c        ;deduct count
  692.     jmp    await        ;onward
  693. nrub:    cpi    ' '        ;control characters prohibited
  694.     jc    await
  695. okalph:    inr    b        ;have space?
  696.     dcr    b
  697.     jnz    gotsp        ;jump if so
  698.     mvi    a,bell        ;ring the bell
  699.     call    type
  700.     jmp    await        ;ignore it otherwise
  701. gotsp:    dcr    b        ;yes, deduct one
  702.     inr    c        ;lenght increment
  703.     mov    m,a        ;store it
  704.     inx    h
  705.     call    type        ;display it
  706.     jmp    await        ;onward
  707. ;
  708. ; Display the input buffer
  709. ;
  710. shobuf:    push    h        ;save 'em
  711.     push    d
  712.     push    b
  713.     mvi    a,cr        ;back to start of line
  714.     call    wrsbyt        ;screen only
  715.     lxi    h,inkbuf
  716.     call    displa        ;display the buffer
  717.     pop    b
  718.     pop    d
  719.     pop    h
  720.     ret
  721. ;
  722. ; formatted output
  723. ;
  724. formot:    lxi    b,digitl*256    ;B=digit-left count, C=dp flag
  725.     mvi    e,0        ;total bufr size
  726.     dcx    h        ;pre-decrement
  727. sblank:    inx    h
  728.     mov    a,m        ;skip blanks
  729.     cpi    ' '
  730.     jz    sblank
  731.     push    h        ;save pointer
  732. scanlp:    mov    a,m        ;got end?
  733.     inx    h
  734.     ora    a
  735.     jz    formnd        ;jump if so
  736.     cpi    '.'        ;dp?
  737.     jnz    fndp        ;jump if not
  738.     mov    a,b        ;yes, set DISPLA pad count
  739.     sta    padcnt
  740.     mvi    b,digitr
  741.     inr    e
  742.     inr    c        ;set DP flag
  743.     jmp    scanlp
  744. fndp:    inr    b        ;room remaining?
  745.     dcr    b
  746.     jz    fov        ;overflow if not
  747.     dcr    b        ;got room
  748.     inr    e
  749.     jmp    scanlp
  750. fov:    inr    c        ;is this the decimal portion?
  751.     dcr    c
  752.     jnz    fdec        ;jump if so
  753. ;
  754. ; integer portion overflow
  755. ;
  756.     pop    h        ;discard the number
  757.     mvi    b,digitl    ;print an overflowed number
  758.     mvi    a,'E'
  759.     call    rchar
  760.     mvi    a,'.'
  761.     call    type
  762.     mvi    b,digitr
  763.     mvi    a,'E'
  764.     call    rchar
  765.     ret
  766. ;
  767. fdec:    dcx    h
  768.     mvi    m,0        ;truncate
  769. formnd:    pop    h        ;get buffer pointer bak
  770.     push    h
  771.     call    normal        ;normalize
  772.     pop    h        ;fall into DISPLA
  773. ;
  774. ; Display buffer .HL formatted, with DP cursor backspacing.
  775. ; On entry, E=total field size, B=remaining space in buffer,
  776. ; C=DP flag, and PADCNT holds the amount of padding necessary
  777. ; on the left.
  778. ;
  779. displa:    push    b
  780.     mvi    e,numsiz    ;field pad count initially
  781.     mov    a,c        ;got a dp yet?
  782.     ora    a
  783.     jz    show1        ;\jump if no dp (b=pos left = pad cnt)
  784.     lda    padcnt        ;get positions before DP
  785.     mov    b,a
  786. show1:    call    rblank        ;pad
  787. sholp:    mov    a,m        ;fetch
  788.     inx    h
  789.     ora    a        ;terminator?
  790.     jz    show2        ;jump if so
  791.     call    type        ;no, display it
  792.     dcr    e        ;one less
  793.     jmp    sholp
  794. show2:    mov    b,e        ;remaining size of field
  795.     call    rblank
  796.     pop    b        ;get DP flag back (in c)
  797.     push    b
  798.     mov    a,c        ;check dp flag
  799.     ora    a
  800.     jnz    show3        ;if dp, use remaining in B as bs-count
  801.     mvi    b,digitr+1    ;if no dp, back up to left of dp
  802. show3:    mvi    a,bs
  803.     call    rchar
  804.     pop    b
  805.     ret
  806. ;
  807. ; print # blanks in A
  808. ;
  809. rblank:    mvi    a,' '
  810. rchar:    sta    padchr
  811.     mov    a,b        ;get count
  812.     ora    a        ;exit if none to print
  813.     rz
  814.     lda    padchr
  815. bllp:    call    type
  816.     dcr    e
  817.     dcr    b
  818.     jnz    bllp
  819.     ret
  820. ;
  821. ; display MEM variable
  822. ;
  823. shomem:    lhld    cursor        ;don't lose position
  824.     push    h
  825.     lxi    d,50        ;line 0, col 50
  826.     call    curadr
  827.     lxi    h,mname
  828.     call    prathl
  829.     lxi    h,membuf
  830.     call    prathl
  831.     pop    d        ;restore cursor
  832.     jmp    curadr
  833. ;
  834. ; shop opcode in A in opcode column in D
  835. ;
  836. opshow:    cpi    tab        ;convert tab to blank
  837.     jnz    opsh1
  838.     mvi    a,' '
  839. opsh1:    push    h
  840.     push    b
  841.     push    psw
  842.     lxi    h,opfld        ;where they go
  843.     mvi    b,3        ;max
  844. opscan:    mov    a,m        ;find empty position
  845.     cpi    ' '
  846.     jz    opfnd
  847.     inx    h
  848.     dcr    b
  849.     jnz    opscan
  850.     lxi    h,opfld        ;none found, overwrite oldest
  851. opfnd:    pop    psw
  852.     push    psw
  853.     mov    m,a
  854.     lxi    d,(iline*256)+flgcol
  855.     call    curadr        ;display on screen
  856.     lxi    h,opfld
  857.     call    prathl
  858.     pop    psw
  859.     pop    b
  860.     pop    h
  861.     ret
  862. ;
  863. opcler:    lxi    h,'  '
  864.     shld    opfld
  865.     shld    opfld+1
  866.     ret
  867. ;
  868. putscr:    mvi    a,(iline-scline)-1
  869.     sta    rollct        ;count before switch
  870.     call    cls
  871.     lxi    d,(1*256)+31
  872.     call    curadr
  873.     lxi    h,header
  874.     call    prathl
  875.     lxi    d,(scline-1)*256
  876.     call    curadr
  877.     mvi    b,78
  878.     mvi    a,'-'
  879.     call    rchar        ;put up line
  880.     lxi    d,(iline-1)*256
  881.     call    curadr
  882.     lxi    h,leader
  883.     call    prathl
  884.     lxi    d,iline*256
  885.     jmp    curadr
  886. ;
  887. ; scroll up
  888. ;
  889. scroll:    lxi    d,(scline+1)*256
  890.     lxi    h,rollct    ;switched yet?
  891.     mov    a,m
  892.     ora    a
  893.     jz    scrol1        ;\jump if so
  894.     dcr    m        ;no,downcount
  895.     dcr    d        ;and use previous line
  896. scrol1:    call    curadr
  897.     call    dellin
  898.     lxi    d,iline*256
  899.     call    curadr
  900. scnl:    mvi    a,cr        ;write newline to file
  901.     call    wrfbyt
  902.     mvi    a,lf
  903.     call    wrfbyt
  904. ;
  905. ; clear fields
  906. ;
  907.     call    opcler        ;clear OP field
  908.     xra    a
  909.     sta    inkbuf
  910.     sta    cmtbuf
  911.     ret
  912. ;
  913. ;
  914. ;------------------------------------------------------------
  915. ;
  916. ;    *****************************
  917. ;    * Miscellaneous Subroutines *
  918. ;    *****************************
  919. ;
  920. ; inline print, string .TOS
  921. ;
  922. ilprt:    xthl
  923.     call    prathl
  924.     xthl
  925.     ret
  926. ;
  927. ; print string .HL
  928. ;
  929. prathl:    mov    a,m        ;fetch
  930.     inx    h
  931.     ora    a        ;null terminates
  932.     rz
  933.     call    type        ;display
  934.     jmp    prathl
  935. ;
  936. ; output char in A to console, modify nothing
  937. ;
  938. type:    push    h        ;stack everybody
  939.     push    d
  940.     push    b
  941.     push    psw
  942.     lda    putsw        ;put to output file?
  943.     ani    filbit
  944.     jz    putnfl        ;jump if not
  945.     pop    psw        ;yes
  946.     push    psw
  947.     call    wrfbyt
  948. putnfl:    lda    putsw        ;write to screen?
  949.     ani    scrbit
  950.     jz    typxit        ;exit if not
  951.     pop    psw        ;yes
  952.     push    psw
  953.     call    wrsbyt        ;write to screen
  954. typxit:    pop    psw
  955.     pop    b
  956.     pop    d
  957.     pop    h
  958.     ret
  959. ;
  960. ; write char in A to screen
  961. ;
  962. wrsbyt:    push    psw
  963.     mov    e,a        ;align
  964.     mvi    c,dirio
  965.     call    bdos
  966.     pop    psw        ;recall character
  967.     lxi    h,cursor    ;update cursor column
  968.     cpi    lf        ;linefeed?
  969.     jnz    type0        ;jump if not
  970.     inx    h        ;yes, advance line only
  971.     inr    m
  972.     ret
  973. type0:    cpi    cr        ;end of line?
  974.     jnz    type1        ;jump if not
  975.     mvi    m,0        ;yes, reset column
  976.     ret
  977. type1:    cpi    bs        ;backspace?
  978.     jnz    type2        ;jump if not
  979.     dcr    m        ;one less
  980.     dcr    m        ;extra for next instruction
  981. type2:    inr    m        ;advance column
  982.     ret
  983. ;
  984. ; input character to A, modify only A
  985. ;
  986. charin:    lda    recalc        ;get recalc flag
  987.     ora    a
  988.     jz    char1        ;jump if not reading file
  989.     call    swpro        ;switch to producer context
  990.     ora    a        ;did we get a character?
  991.     rnz            ;done if so
  992.     sta    recalc        ;no, reset flag, fall into CHAR1
  993. char1:    push    h
  994.     push    d
  995.     push    b
  996. inlp:    mvi    e,0ffh        ;indicate input, not output
  997.     mvi    c,dirio
  998.     call    bdos        ;read character
  999.     ora    a        ;BDOS returns 0 ...
  1000.     jz    inlp        ; ... if no character waiting
  1001. charx:    pop    b
  1002.     pop    d
  1003.     pop    h
  1004.     ret
  1005. ;
  1006. ; convert char in A to upper case
  1007. ;
  1008. cvtuc:    cpi    'a'
  1009.     rc
  1010.     cpi    'z'+1
  1011.     rnc
  1012.     ani    5fh
  1013.     ret
  1014. ;
  1015. digchk:    cpi    '0'
  1016.     rc
  1017.     cpi    '9'+1
  1018.     cmc
  1019.     ret
  1020. ;
  1021. alphck:    cpi    'A'
  1022.     rc
  1023.     cpi    'Z'+1
  1024.     cmc
  1025.     rnc
  1026.     cpi    'a'
  1027.     rc
  1028.     cpi    'z'+1
  1029.     cmc
  1030.     ret
  1031. ;
  1032. ; copy the FACC to HOLD
  1033. ;
  1034. movfac:    lxi    d,hold        ;copy the FACC to local
  1035.     lxi    h,facc
  1036. fpmove:    lxi    b,fpsize    ;fall into block move
  1037. ldir:    mov    a,m
  1038.     stax    d
  1039.     inx    h
  1040.     inx    d
  1041.     dcx    b
  1042.     mov    a,b
  1043.     ora    c
  1044.     jnz    ldir
  1045.     ret
  1046. ;
  1047. ; clear prompt field
  1048. ;
  1049. clearp:    push    h
  1050.     push    d
  1051.     lhld    pfield
  1052.     xchg
  1053.     call    curadr
  1054.     lxi    h,mblank
  1055.     call    prathl
  1056.     pop    d
  1057.     pop    h
  1058.     ret
  1059. ;
  1060. ; FENV - find Z3 environment ... if found, sets named
  1061. ; directory address; if not found, leaves named dir-
  1062. ; ectory address 0.
  1063. ;
  1064. ; FENV routine Copyright 1986 by Zivio, Inc.
  1065. ; All Rights Reserved
  1066. ;
  1067. fenv:    xra    a        ;no Z3 yet
  1068.     sta    z3flag
  1069.     lhld    z3eadr        ;already have Z3 env from Z3ins?
  1070.     mov    a,h
  1071.     ora    l
  1072.     jnz    sdir        ;if so, get set ndir adrs
  1073.     lxi    h,0ffffh    ;Beginning of search, top of memory
  1074. srch:    lxi    d,envlit+4    ;Search target end.
  1075. evscan:    lda    2        ;Bios page
  1076.     cmp    h        ;Page being searched
  1077.     rz            ;give up, can't find it
  1078.     ldax    d        ;Get the 'v'
  1079.     cmp    m        ;Is hl pointing to it yet?
  1080.     jz    vm1        ;Yes.
  1081.     dcx    h        ;Next byte
  1082.     jmp    evscan        ;Again
  1083. vm1:    mvi    b,4        ;Check four more bytes
  1084. vm2:    dcx    d        ;Next byte in target
  1085.     dcx    h        ;Next byte in memory
  1086.     ldax    d        ;Get target byte
  1087.     cmp    m        ;Compare it with memory
  1088.     jnz    srch        ;Start over
  1089.     dcr    b
  1090.     jnz    vm2        ;Continue checking
  1091. ;
  1092. ;  may have found it ...
  1093. ;
  1094.     dcx    h
  1095.     dcx    h
  1096.     dcx    h        ;Back up to potential environment address
  1097.     push    h        ;Save it
  1098.     lxi    d,1bh        ;Offset to envptr in z3env
  1099.     dad    d        ;Point hl to it
  1100.     mov    e,m        ;Low byte to e
  1101.     inx    h
  1102.     mov    d,m        ;Move envptr to de
  1103.     pop    h        ;Retrieve potential environment address
  1104.     mov    a,h
  1105.     cmp    d        ;Compare high order
  1106.     jnz    evnext
  1107.     mov    a,l
  1108.     cmp    e        ;Compare low order
  1109.     jz    sdir        ;jump if found
  1110. evnext:    inx    h        ;else continue search
  1111.     inx    h
  1112.     inx    h
  1113.     jmp    srch
  1114. ;
  1115. ; have ENV
  1116. ;
  1117. sdir:    mvi    a,0ffh        ;set Z3 flag
  1118.     sta    z3flag
  1119.     ret
  1120. ;
  1121. ;
  1122. ;------------------------------------------------------------
  1123. ;
  1124. ;            *******************
  1125. ;            * FILE MANAGEMENT *
  1126. ;            *******************
  1127. ;
  1128. ;
  1129. ; File-I/O system calls and equates
  1130. ;
  1131. fcb    equ    05ch        ;file control block
  1132. tbuff    equ    80h        ;command tail buffer
  1133. ;
  1134. seldsk    equ    14        ;select disk
  1135. open    equ    15        ;open file
  1136. close    equ    16        ;close file
  1137. erase    equ    19        ;erase file
  1138. read    equ    20        ;read sequential record
  1139. write    equ    21        ;write sequential record
  1140. make    equ    22        ;create file
  1141. ;
  1142. curdsk    equ    25        ;return current drive
  1143. setdma    equ    26        ;set disk transfer adrs
  1144. user    equ    32        ;get/set user code
  1145. ;
  1146. ; Set up input file
  1147. ;
  1148. nitfil:    mvi    a,1        ;output-file write enable
  1149.     sta    outflg
  1150.     dcr    a        ;A=0
  1151.     sta    recalc        ;recalc=false
  1152.     lxi    h,ffree        ;init buffer
  1153.     shld    obp
  1154.     lhld    system+1    ;init memory
  1155.     dcr    h
  1156.     dcr    h        ;2 pages (leaving room for EOF's)
  1157.     mvi    l,0ffh
  1158.     shld    memtop
  1159. ;
  1160. ; query for input file
  1161. ;
  1162.     lhld    cursor        ;save cursor position
  1163.     push    h
  1164.     lxi    d,rdfmsg    ;query for recalc
  1165.     call    prpmt
  1166.     call    charin
  1167.     call    cvtuc
  1168.     cpi    'Y'
  1169.     jnz    nitxit        ;jump if refused
  1170. reask:    call    clearp
  1171.     lxi    d,ifnmsg    ;prompt for filename
  1172.     call    askfn
  1173.     jc    nitxit        ;exit if blank name
  1174.     lxi    d,outfcb    ;see if file exists
  1175.     mvi    c,open
  1176.     call    bdos
  1177.     inr    a        ;?
  1178.     jz    inf        ;jump if not found
  1179.     mvi    a,1        ;set recalc flag
  1180.     sta    recalc
  1181.     lxi    h,pstart    ;entry point of producer stack
  1182.     shld    protop
  1183.     lxi    h,prost        ;initial stackpointer
  1184.     shld    prosp        ;for producer
  1185.     jmp    nitxit
  1186. inf:    lxi    d,nfmsg        ;print not found
  1187.     call    prpmt
  1188.     call    charin
  1189.     jmp    reask
  1190. nitxit:    call    clearp
  1191.     pop    d        ;restore cursor
  1192.     call    curadr
  1193.     ret
  1194. ;
  1195. ; switch to producer context
  1196. ;
  1197. swpro:    push    h        ;stack everybody
  1198.     push    d
  1199.     push    b
  1200.     lxi    h,0
  1201.     dad    sp
  1202.     shld    consp        ;stack the consumer
  1203.     lhld    prosp        ;get producer stack level
  1204.     sphl
  1205.     pop    b        ;become a different process
  1206.     pop    d
  1207.     pop    h
  1208.     ret
  1209. ;
  1210. ; switch to consumer context, passing A reg
  1211. ;
  1212. swcon:    push    h        ;stack everybody
  1213.     push    d
  1214.     push    b
  1215.     lxi    h,0
  1216.     dad    sp
  1217.     shld    prosp        ;stack the producer
  1218.     lhld    consp        ;get consumer stack level
  1219.     sphl
  1220.     pop    b
  1221.     pop    d
  1222.     pop    h
  1223.     ret
  1224. ;
  1225. ; start of producer process
  1226. ;
  1227. linmax    equ    50        ;maximum line size
  1228. ;
  1229. pstart:    mvi    a,80h        ;set input buf ptr to force a read
  1230.     sta    ibp
  1231.     xra    a
  1232.     sta    eoflg        ;reset file-ended flag
  1233. pmain:    call    rdline        ;read a line
  1234.     jc    pend        ;jump if no more
  1235.     lda    linbuf        ;address buffer
  1236.     cpi    '-'        ;dashes?
  1237.     jz    pmain        ;ignore line if so
  1238.     lda    linflg        ;get FLAG field
  1239.     cpi    'T'        ;t-lines are not user-generated
  1240.     jz    pmain
  1241.     cpi    '='        ;subtotal lines too
  1242.     jz    pmain
  1243.     cpi    'M'        ;memory op?
  1244.     jnz    notmrk        ;jump if not
  1245.     lda    linflg+1    ;memory recall?
  1246.     cpi    'R'
  1247.     jnz    notmrk        ;jump if not
  1248. ;
  1249. ; memory recall operation
  1250. ;
  1251.     mvi    a,mrkey        ;send MR key
  1252.     call    swcon
  1253.     call    sndcmt        ;send comment
  1254.     lda    linflg+2
  1255.     cpi    ' '        ;convert blank to tab
  1256.     jnz    pmain1
  1257.     mvi    a,tabkey
  1258. pmain1:    call    swcon
  1259.     jmp    pmain        ;onward
  1260. ;    
  1261. notmrk:    lxi    h,linbuf-1    ;send number
  1262.     mvi    b,digitl+digitr+2    ;count+1
  1263. skipbk:    dcr    b
  1264.     inx    h
  1265.     mov    a,m        ;skip blanks
  1266.     cpi    ' '
  1267.     jz    skipbk
  1268. numlp:    mov    a,m        ;send number to consumer
  1269.     inx    h
  1270.     call    swcon
  1271.     dcr    b
  1272.     jnz    numlp
  1273.     call    sndcmt        ;send comment
  1274.     lxi    h,linflg    ;address flags
  1275.     mov    a,m
  1276.     inx    h
  1277.     cpi    'M'        ;memory store?
  1278.     jnz    notmsk        ;jump if not
  1279.     mov    a,m        ;get S
  1280.     inx    h
  1281.     cpi    'S'
  1282.     jnz    notmsk        ;jump
  1283.     mvi    a,mskey        ;send store key
  1284.     call    swcon
  1285.     mov    a,m        ;get operator
  1286. notmsk:    cpi    ' '        ;convert space to tab
  1287.     jnz    pmain2
  1288.     mvi    a,tabkey
  1289. pmain2:    call    swcon        ;send it
  1290.     jmp    pmain        ;onward
  1291. ;
  1292. pend:    xra    a        ;A=0 to SWCON terminates us
  1293.     call    swcon
  1294. ;
  1295. ; send comment
  1296. ;
  1297. sndcmt:    lxi    h,lincmt    ;address comment field
  1298.     mov    a,m        ;got one?
  1299.     ora    a
  1300.     rz
  1301.     cpi    ' '        ;exit if not
  1302.     rz
  1303.     call    sndtog        ;send toggle key
  1304. scmlp:    mov    a,m
  1305.     ora    a
  1306.     jz    sndtog        ;exit if end
  1307.     inx    h
  1308.     call    swcon
  1309.     jmp    scmlp
  1310. sndtog:    mvi    a,togkey    ;switch back
  1311.     jmp    swcon
  1312. ;
  1313. ; Read line from file
  1314. ;
  1315. rdline:    xra    a        ;no comment yet
  1316.     sta    lincmt
  1317.     lxi    h,linbuf    ;where it goes
  1318.     lxi    b,linmax    ;B=upcounter, C=max
  1319. rdllp:    mvi    m,0        ;insure terminator
  1320.     call    rdbyte        ;read a byte
  1321.     cpi    01AH
  1322.     jz    rdleof        ;jump if EOF
  1323.     cpi    lf
  1324.     jz    rdlend
  1325.     cpi    ' '        ;ignore all other control chars
  1326.     jc    rdllp
  1327.     inr    c        ;good char ... do we have room?
  1328.     dcr    c
  1329.     jz    rdllp        ;jump if not
  1330.     mov    m,a        ;store it
  1331.     inx    h        ;advance
  1332.     inr    b        ;up count
  1333.     dcr    c        ;downcount
  1334.     jmp    rdllp
  1335. rdlend:    mov    a,b        ;got anything?
  1336.     ora    a
  1337.     jz    rdline        ;if not, go get another
  1338.     ret
  1339. rdleof:    mvi    a,1        ;set EOF flag
  1340.     sta    eoflg
  1341.     mov    a,b        ;file ended ... got any chars?
  1342.     ora    a
  1343.     rnz            ;exit w/line if so
  1344.     stc            ;nope
  1345.     ret
  1346. ;
  1347. ; Read byte from file
  1348. ;
  1349. rdbyte:    lda    eoflg        ;got end of file?
  1350.     ora    a
  1351.     mvi    a,01AH
  1352.     rnz            ;exit EOF if so
  1353.     push    h
  1354.     push    d
  1355.     push    b
  1356.     lda    ibp        ;get pointer
  1357.     ora    a
  1358.     jp    rdb1        ;jump if not past end
  1359.     lxi    d,filbuf    ;set DMA
  1360.     mvi    c,setdma
  1361.     call    bdos
  1362.     lxi    d,outfcb    ;read
  1363.     mvi    c,read
  1364.     call    bdos
  1365.     ora    a        ;good read?
  1366.     jz    rdb1        ;jump if so
  1367.     sta    eoflg        ;no, set end-of-file flag
  1368.     mvi    a,01AH        ;return EOF
  1369.     jmp    rdbxit
  1370. rdb1:    mov    e,a        ;pointer to DE
  1371.     mvi    d,0
  1372.     inr    a        ;update pointer
  1373.     sta    ibp
  1374.     lxi    h,filbuf    ;offset into buffer
  1375.     dad    d
  1376.     mov    a,m        ;fetch
  1377.     ora    a
  1378. rdbxit:    pop    b
  1379.     pop    d
  1380.     pop    h
  1381.     ret
  1382. ;
  1383. linbuf:    ds    digitl        ;integer portion of #
  1384.     ds    1        ;DP
  1385.     ds    digitr        ;decimal portion
  1386.     ds    1        ;blank
  1387. linflg:    ds    3        ;flag field
  1388.     ds    1        ;blank
  1389. lincmt:    ds    cmtlen        ;comment
  1390. ;
  1391.     ds    20        ;cr etc.
  1392. ;
  1393. filbuf:    ds    128        ;input file buffer
  1394. ibp:    ds    1        ;input buffer pointer
  1395. eoflg:    ds    1        ;end-of-file flag
  1396. ;
  1397. ;------------------------------------------------------------
  1398. ;
  1399. ; write byte to output buffer
  1400. ;
  1401. wrfbyt:    push    h        ;save everyone
  1402.     push    d
  1403.     push    b
  1404.     push    psw
  1405.     mov    c,a        ;output character to C
  1406.     lda    outflg        ;filewrite enabled?
  1407.     ora    a
  1408.     jz    wrexit        ;just exit if not
  1409.     mov    a,c
  1410.     cpi    01AH        ;only EOF, CR and LF control chars in file
  1411.     jz    wrf1
  1412.     cpi    cr        ;
  1413.     jz    wrf1
  1414.     cpi    lf
  1415.     jz    wrf1
  1416.     cpi    ' '        ;suppress all others
  1417.     jc    wrexit
  1418. wrf1:    call    putbuf        ;put char in buffer
  1419.     jnc    wrexit        ;jump if it went
  1420. ;
  1421. ; out of memory
  1422. ;
  1423.     lhld    cursor        ;get current cursor adrs
  1424.     push    h        ;save it
  1425.     lhld    pfield        ;address prompt field
  1426.     xchg
  1427.     call    curadr
  1428.     lxi    h,memmsg    ;print msg
  1429.     call    prathl
  1430.     call    charin
  1431.     call    clearp        ;clear prompt field
  1432.     pop    d        ;restore old cursor adrs
  1433.     call    curadr
  1434.     xra    a        ;reset write
  1435.     sta    outflg
  1436. wrexit:    pop    psw        ;restore everyone
  1437.     pop    b
  1438.     pop    d
  1439.     pop    h
  1440.     ret    
  1441. ;
  1442. ; put char in C in buffer, return CY=1 if buf filled
  1443. ;
  1444. putbuf:    lhld    memtop
  1445.     xchg            ;DE=top
  1446.     lhld    obp        ;get output buffer pointer
  1447.     mov    m,c        ;store char
  1448.     mov    a,e        ;are we there?
  1449.     cmp    l
  1450.     jnz    wrfok        ;jump if not
  1451.     mov    a,d
  1452.     cmp    h
  1453.     jnz    wrfok
  1454.     stc
  1455.     ret
  1456. wrfok:    inx    h
  1457.     shld    obp
  1458.     lhld    outcnt        ;increment output count
  1459.     inx    h
  1460.     shld    outcnt
  1461.     ora    a
  1462.     ret
  1463. ;
  1464. mname:    db    'MEM: ',0
  1465. rdfmsg:    db    'Recalculate existing tape (Y/N)? ',0
  1466. nfmsg:    db    'File not found!        <any key> ',0
  1467. ifnmsg:    db    'Read tape from filename: ',0
  1468. xitmsg:    db    'Exit ON!ADD (y/n)?',0
  1469. wrtmsg:    db    'X,E: exit, F: write output tape: ',0
  1470. fulems:    db    'Disk full! Partial tape saved <any key>  :',0
  1471. ofnmsg:    db    'Save tape to filename: ',0
  1472. eramsg:    db    'File exists ... erase (Y/N) ?',0
  1473. makems:    db    'Error creating file <any key> :',0
  1474. header:    db    'O N ! A D D',cr,lf,cr,lf
  1475.     db    '^X  = Clear entry | TAB = total | \ = '
  1476.     db    'subtotal |^C = exit | M = Memory Store'
  1477.     db    cr,lf
  1478.     db    'ESC = note/number | +-*/ (add,subtract'
  1479.     db    ',multiply,divide)   | R = Memory recall'
  1480.     db    0
  1481. dash:    db    '---------------------',0
  1482. cblank:    multi    ' ',cmtlen    ;blanks
  1483.     db    0
  1484. leader:    multi    'x',digitl
  1485.     multi    '.',1
  1486.     multi    'x',digitr
  1487.     multi    ' ',spc1
  1488.     multi    'O',fls
  1489.     multi    ' ',spc2
  1490.     db    ' ----------- Note -------------',0
  1491. memmsg:    db    'Memory full! Output tape disabled <any key>  :',0
  1492. mblank:    db    '                                              ',0
  1493. ;
  1494. filnbf:    db    15,0
  1495.     ds    15+3
  1496. ;
  1497. ; write an output file
  1498. ;
  1499. wrtfil:    lhld    outcnt        ;got anything to write?
  1500.     mov    a,h
  1501.     ora    l
  1502.     rz            ;skip this if not
  1503.     lhld    cursor        ;save cursor position
  1504.     push    h
  1505.     lxi    d,wrtmsg    ;query for output file
  1506.     call    prpmt
  1507.     call    charin
  1508.     call    cvtuc
  1509.     cpi    'X'        ;exit
  1510.     jz    wrtxit
  1511.     cpi    'E'
  1512.     jz    wrtxit
  1513.     call    clearp        ;clear prompt field
  1514.     lxi    d,ofnmsg    ;prompt for filename
  1515.     call    askfn        ;get it
  1516.     jc    wrtxit        ;if blank name, exit
  1517.     lhld    memtop        ;take back that extra page
  1518.     inr    h        ; ... we stole when we set up MEMTOP
  1519.     shld    memtop        ; ... so there's room for EOF stuff
  1520.     lxi    d,outfcb    ;see if file already exists
  1521.     mvi    c,open
  1522.     call    bdos
  1523.     inr    a        ;?
  1524.     jz    makeit        ;if not, go make new
  1525.     mvi    c,close
  1526.     lxi    d,outfcb    ;close it
  1527.     call    bdos
  1528.     call    clearp
  1529.     lxi    d,eramsg
  1530.     call    prpmt        ;ask if we should erase
  1531.     call    getyn        ;get Y/N answer
  1532.     cpi    'Y'
  1533.     jnz    wrtxit        ;exit if NO
  1534.     call    type        ;echo
  1535.     mvi    a,cr
  1536.     call    type
  1537.     lxi    d,outfcb    ;erase
  1538.     mvi    c,erase
  1539.     call    bdos
  1540. makeit:    lxi    d,outfcb    ;create new
  1541.     mvi    c,make
  1542.     call    bdos
  1543.     cpi    0ffh        ;good make?
  1544.     lxi    d,makems    ;prep error msg
  1545.     jz    wtexit        ;if not, go error out
  1546. ;
  1547. ; pad output buffer with EOF markers
  1548. ;
  1549. padit:    mvi    a,01AH        ;pad last sector with EOF
  1550.     call    wrfbyt
  1551.     lhld    outcnt        ;last sector emptied?
  1552.     mov    a,l
  1553.     ani    07FH
  1554.     jnz    padit        ;loop until it is
  1555.     mvi    b,7        ;get log 128 for divide
  1556. rotrlp:    ora    a
  1557.     mov    a,h
  1558.     rar
  1559.     mov    h,a
  1560.     mov    a,l
  1561.     rar
  1562.     mov    l,a
  1563.     dcr    b
  1564.     jnz    rotrlp
  1565.     mov    b,h        ;BC=record count
  1566.     mov    c,l
  1567.     lxi    d,ffree        ;DE=start of buffer
  1568. wrlp:    lxi    h,128        ;calc next DMA
  1569.     dad    d
  1570.     push    h        ;save it
  1571.     push    b        ;save count
  1572.     mvi    c,setdma    ;set this one
  1573.     call    bdos
  1574.     lxi    d,outfcb    ;write
  1575.     mvi    c,write
  1576.     call    bdos
  1577.     pop    b        ;recall count
  1578.     pop    d        ;recall next DMA
  1579.     ora    a        ;good write?
  1580.     jz    wrtok        ;jump if so
  1581.     lxi    d,outfcb    ;no, close what we have
  1582.     mvi    c,close
  1583.     call    bdos
  1584.     jmp    dskful
  1585. wrtok:    dcx    b        ;write all
  1586.     mov    a,b
  1587.     ora    c
  1588.     jnz    wrlp
  1589.     lxi    d,outfcb    ;now close the file
  1590.     mvi    c,close
  1591.     call    bdos
  1592.     inr    a        ;did it go?
  1593.     jnz    wrtxit        ;exit if so
  1594. dskful:    lxi    d,fulems    ;print msg
  1595. wtexit:    call    prpmt
  1596.     call    charin
  1597. wrtxit:    call    clearp
  1598.     pop    d
  1599.     call    curadr
  1600.     ret
  1601. ;
  1602. ; Print prompt .HL, query filename. Returns CY=1 if blank name
  1603. ;
  1604. askfn:    call    prpmt
  1605.     lxi    d,filnbf
  1606.     mvi    c,10
  1607.     call    bdos
  1608.     lxi    h,filnbf+1
  1609.     mov    a,m        ;anything entered?
  1610.     ora    a
  1611.     stc
  1612.     rz            ;quit if not
  1613.     push    h
  1614.     mov    e,m        ;length to DE
  1615.     mvi    d,0
  1616.     dad    d
  1617.     inx    h        ;HL pointing past last
  1618.     mvi    m,0        ;null terminate
  1619.     pop    h
  1620. scanb:    inx    h
  1621.     mov    a,m        ;skip any leading blanks
  1622.     cpi    ' '
  1623.     jz    scanb
  1624.     ora    a        ;termination here ends it
  1625.     stc
  1626.     rz
  1627.     lxi    d,outfcb    ;parse the name
  1628.     call    fparse
  1629.     ora    a
  1630.     ret
  1631. ;
  1632. ; output FCB
  1633. ;
  1634.     db    0            ;---> outfcb's user area
  1635. outfcb:    db    0,'OUTPUTXXFCB',0,0,0,0    ;local FCB
  1636.     dw    0,0,0,0,0,0,0,0
  1637.     db    0,0,0
  1638. ;
  1639. ; input FCB
  1640. ;
  1641.     db    0            ;---> outfcb's user area
  1642. infcb:    db    0,'CALC    ANS',0,0,0,0    ;local FCB
  1643.     dw    0,0,0,0,0,0,0,0
  1644.     db    0,0,0
  1645. ;
  1646. ;
  1647. ;    *********************************
  1648. ;    * file name parsing subroutines *
  1649. ;    *********************************
  1650. ;
  1651. ;
  1652. ; getfn gets a file name from text pointed to by reg hl into
  1653. ; an fcb pointed to by reg de.    leading delimeters are
  1654. ; ignored. allows drive spec of the form <du:> (drive/user).
  1655. ; this routine formats all 33 bytes of the fcb (but not ran rec).
  1656. ;
  1657. ; entry de    first byte of fcb
  1658. ; exit b=# of '?' in name
  1659. ; fcb-1= user # parsed (if specified) or 255
  1660. ;
  1661. ;
  1662. fparse:    call    nitfcb        ;init 1st half of fcb
  1663.     call    gstart        ;scan to first character of name
  1664.     call    getdrv        ;get drive/user spec. if present
  1665.     mov    a,b        ;get user # or 255
  1666.     cpi    0ffh        ;255?
  1667.     jz    fpars1        ;jump if so
  1668.     dcx    d        ;back up to byte preceeding fcb
  1669.     dcx    d
  1670.     stax    d        ;stuff user #
  1671.     inx    d        ;onward
  1672.     inx    d
  1673. fpars1:    call    getps        ;get primary and secondary name
  1674.     ret
  1675. ;
  1676. ; nitfcb fills the fcb with dflt info - 0 in drive field
  1677. ; all-blank in name field, and 0 in ex,s1,s2,rc, disk
  1678. ; allocation map, and random record # fields
  1679. ;
  1680. nitfcb:    push    h
  1681.     push    d
  1682.     call    getusr        ;init user field
  1683.     pop    d
  1684.     pop    h
  1685.     push    d        ;save fcb loc
  1686.     dcx    d
  1687.     stax    d        ;init user # to currnt user #
  1688.     inx    d
  1689.     xchg            ;move it to hl
  1690.     mvi    m,0        ;drive=default
  1691.     inx    h        ;bump to name field
  1692.     mvi    b,11        ;zap all of name fld
  1693. nitlp:    mvi    m,' '
  1694.     inx    h
  1695.     dcr    b
  1696.     jnz    nitlp
  1697.     mvi    b,33-11        ;zero others, up to nr field
  1698. zlp:    mvi    m,0
  1699.     inx    h
  1700.     dcr    b
  1701.     jnz    zlp
  1702.     xchg            ;restore hl
  1703.     pop    d        ;restore fcb pointer
  1704.     ret
  1705. ;
  1706. ; gstart advances the text pointer (reg hl) to the first
  1707. ; non delimiter character (i.e. ignores blanks).  returns a
  1708. ; flag if end of line (00h or ';') is found while scaning.
  1709. ; exit    hl    pointing to first non delimiter
  1710. ;    a    clobbered
  1711. ;    zero    set if end of line was found
  1712. ;
  1713. gstart:    call    getch        ;see if pointing to delim?
  1714.     rnz            ;nope - return
  1715.     ora    a        ;physical end?
  1716.     rz            ;yes - return w/flag
  1717.     inx    h        ;nope - move over it
  1718.     jmp    gstart        ;and try next char
  1719. ;
  1720. ; getdrv checks for the presence of a du: spec at the text
  1721. ; pointer, and if present formats drive into fcb and returns
  1722. ; user # in b.
  1723. ;
  1724. ; entry hl    text pointer
  1725. ;    de    pointer to first byte of fcb
  1726. ; exit    hl    possibly updated text pointer
  1727. ;    de    pointer to second (primary name) byte of fcb
  1728. ;    b    user # if specified or 0ffh
  1729. ;
  1730. getdrv:    mvi    b,0ffh        ;default no user #
  1731.     push    h        ;save text pointer
  1732. dscan:    call    getch        ;get next char
  1733.     inx    h        ;skip pointer over it
  1734.     jnz    dscan        ;scan until delimiter
  1735.     cpi    ':'        ;delimiter a colon?
  1736.     inx    d        ;skip dr field in fcb in case not
  1737.     pop    h        ;and restore text pointer
  1738.     rnz            ;return if no du: spec
  1739.     mov    a,m        ;got one, get first char
  1740.     call    cvtuc        ;may be drive name, cvt to upper case
  1741.     cpi    'A'        ;alpha?
  1742.     jc    isnum        ;jump to get user # if not
  1743.     sui    'A'-1        ;yes, convert from ascii to #
  1744.     dcx    d        ;back up fcb pointer to dr field
  1745.     stax    d        ;store drive # into fcb
  1746.     inx    d        ;pass pointer over drv
  1747.     inx    h        ;skip drive spec in text
  1748. isnum:    mov    a,m        ;fetch next
  1749.     inx    h
  1750.     cpi    ':'        ;du delimiter?
  1751.     rz            ;done then
  1752.     dcx    h        ;nope, back up text pointer
  1753.     mvi    b,0        ;got a digit, init user value
  1754. uloop:    mov    a,b        ;get accumulated user #
  1755.     add    a        ;* 10 for new digit
  1756.     add    a
  1757.     add    b
  1758.     add    a
  1759.     mov    b,a        ;back to b
  1760.     mov    a,m        ;get text char
  1761.     sui    '0'        ;make binary
  1762.     add    b        ;add to user #
  1763.     mov    b,a        ;updated user #
  1764.     inx    h        ;skip over it
  1765.     mov    a,m        ;get next
  1766.     cpi    ':'        ;end of spec?
  1767.     jnz    uloop        ;jump if not
  1768.     inx    h        ;yep, return txt pointer past du:
  1769.     ret
  1770. ;
  1771. ; getps gets the primary and secondary names into the fcb.
  1772. ; entry hl    text pointer
  1773. ; exit    hl    character following secondary name (if present)
  1774. ;
  1775. getps:    mvi    c,8        ;max length of primary name
  1776.     mvi    b,0        ;init count of '?'
  1777.     call    getnam        ;pack primary name into fcb
  1778.     mov    a,m        ;see if terminated by a period
  1779.     cpi    '.'
  1780.     rnz            ;nope - secondary name not given
  1781.                 ;return default (blanks)
  1782.     inx    h        ;yup - move text pointer over period
  1783. ftpoint:mov    a,c        ;yup - update fcb pointer to secondary
  1784.     ora    a
  1785.     jz    getft
  1786.     inx    d
  1787.     dcr    c
  1788.     jmp    ftpoint
  1789. getft:    mvi    c,3        ;max length of secondary name
  1790.     call    getnam        ;pack secondary name into fcb
  1791.     ret
  1792. ;
  1793. ; getnam copies a name from the text pointer into the fcb for
  1794. ; a given maximum length or until a delimiter is found, which
  1795. ; ever occurs first.  if more than the maximum number of
  1796. ; characters is present, character are ignored until a
  1797. ; a delimiter is found.
  1798. ; entry hl    first character of name to be scanned
  1799. ;    de    pointer into fcb name field
  1800. ;    c    maximum length
  1801. ; exit    hl    pointing to terminating delimiter
  1802. ;    de    next empty byte in fcb name field
  1803. ;    c    max length - number of characters transfered
  1804. ;
  1805. getnam:    call    getch        ;are we pointing to a delimiter yet?
  1806.     rz            ;if so, name is transfered
  1807.     inx    h        ;if not, move over character
  1808.     cpi    '*'        ;ambigious file reference?
  1809.     jz    ambig        ;if so, fill the rest of field with '?'
  1810.     cpi    '?'        ;afn reference?
  1811.     jnz    notqm        ;skip if not
  1812.     inr    b        ;else bump afn count
  1813. notqm:    call    cvtuc        ;if not, convert to upper case
  1814.     stax    d        ;and copy into name field
  1815.     inx    d        ;increment name field pointer
  1816.     dcr    c        ;if name field full?
  1817.     jnz    getnam        ;nope - keep filling
  1818.     jmp    getdel        ;yup - ignore until delimiter
  1819. ambig:    mvi    a,'?'        ;fill character for wild card match
  1820. fillq:    stax    d        ;fill until field is full
  1821.     inx    d
  1822.     inr    b        ;increment count of '?'
  1823.     dcr    c
  1824.     jnz    fillq        ;fall thru to ingore rest of name
  1825. getdel:    call    getch        ;pointing to a delimiter?
  1826.     rz            ;yup - all done
  1827.     inx    h        ;nope - ignore antoher one
  1828.     jmp    getdel
  1829. ;
  1830. ; getch gets the character pointed to by the text pointer
  1831. ; and sets the zero flag if it is a delimiter.
  1832. ; entry hl    text pointer
  1833. ; exit    hl    preserved
  1834. ;    a    character at text pointer
  1835. ;    z    set if a delimiter
  1836. ;
  1837. getch:    mov    a,m        ;get the character, test for delim
  1838. ;
  1839. ; global entry: test char in a for filename delimiter
  1840. ;
  1841. fndelm:    cpi    '/'
  1842.     rz
  1843.     cpi    '.'
  1844.     rz
  1845.     cpi    ','
  1846.     rz
  1847.     cpi    ' '
  1848.     rz
  1849.     cpi    ':'
  1850.     rz
  1851.     cpi    '='
  1852.     rz
  1853.     ora    a        ;set zero flag on end of text
  1854. r0:    ret
  1855. ;
  1856. ; bdos entry: preserves bc, de.  if system call is a file
  1857. ;          function, this routine logs into the drive/
  1858. ;          user area specified, then logs back after
  1859. ;          the call.
  1860. ;
  1861. bdos:    call    filfck        ;check for a file function
  1862.     jnz    bdos1        ;jump if not a file function
  1863.     call    getdu        ;get drive/user
  1864.     shld    savedu
  1865.     ldax    d        ;get fcb's drive
  1866.     sta    fcbdrv        ;save it
  1867.     dcr    a        ;make 0-relative
  1868.     jm    bdos0        ;if not default drive, jump
  1869.     mov    h,a        ;copy to h
  1870. bdos0:    xra    a        ;set fcb to default
  1871.     stax    d
  1872.     dcx    d        ;get fcb's user #
  1873.     ldax    d
  1874.     mov    l,a
  1875.     inx    d        ;restore de
  1876.     call    setdu        ;set fcb's user
  1877. ;
  1878. ; note that unspecified user # (value=0ffh) becomes
  1879. ; a getusr call, preventing ambiguity.
  1880. ;
  1881.     call    bdos1        ;do user's system call
  1882.     push    psw        ;save result
  1883.     push    h
  1884.     lda    fcbdrv        ;restore fcb's drive
  1885.     stax    d
  1886.     lhld    savedu        ;restore prior drive/user
  1887.     call    setdu
  1888.     pop    h        ;restore bdos result registers
  1889.     pop    psw
  1890.     ret
  1891. ;
  1892. ; local variables for bdos replacement routine
  1893. ;
  1894. savedu:    dw    0        ;saved drive,user
  1895. fcbdrv:    db    0        ;fcb's drive
  1896. dmadr:    dw    80h        ;current dma adrs
  1897. ;
  1898. bdos1:    push    d
  1899.     push    b
  1900.     mov    a,c        ;doing setdma?
  1901.     cpi    setdma
  1902.     jnz    bdos1a        ;jump if not
  1903.     xchg            ;yep, keep a record of dma addresses
  1904.     shld    dmadr
  1905.     xchg
  1906. bdos1a:    call    system
  1907.     pop    b
  1908.     pop    d
  1909.     ret
  1910. ;
  1911. ; get drive, user: h=drv, l=user
  1912. ;
  1913. getdu:    push    b        ;don't modify bc
  1914.     push    d
  1915.     mvi    c,user        ;get user #
  1916.     mvi    e,0ffh
  1917.     call    bdos1
  1918.     push    psw        ;save it
  1919.     mvi    c,curdsk    ;get drive
  1920.     call    bdos1
  1921.     mov    h,a        ;drive returned in h
  1922.     pop    psw
  1923.     mov    l,a        ;user in l
  1924.     pop    d
  1925.     pop    b        ;restore caller's bc
  1926.     ret
  1927. ;
  1928. ; set drive, user: h=drv, l=user
  1929. ;
  1930. setdu:    push    b        ;don't modify bc
  1931.     push    d
  1932.     push    h        ;save info
  1933.     mov    e,h        ;drive to e
  1934.     mvi    c,seldsk    ;set it
  1935.     call    bdos1
  1936.     pop    h        ;recall info
  1937.     push    h
  1938.     mov    e,l        ;user # to e
  1939.     mvi    c,user
  1940.     call    bdos1        ;set it
  1941.     pop    h
  1942.     pop    d
  1943.     pop    b
  1944.     ret
  1945. ;
  1946. ; check for file-function: open, close, read random, write
  1947. ;    random, read sequential, write sequential.
  1948. ;
  1949. filfck:    mov    a,c        ;get function #
  1950.     cpi    open
  1951.     rz
  1952.     rc            ;ignore lower function #'s
  1953.     cpi    close
  1954.     rz
  1955.     cpi    read
  1956.     rz
  1957.     cpi    write
  1958.     rz
  1959.     cpi    erase
  1960.     rz
  1961.     cpi    make
  1962.     ret
  1963. ;
  1964. ; routine to return user # without disturbing registers
  1965. ;
  1966. getusr:    push    h
  1967.     push    d
  1968.     push    b
  1969.     mvi    c,user
  1970.     mvi    e,0ffh
  1971.     call    bdos
  1972.     pop    b
  1973.     pop    d
  1974.     pop    h
  1975.     ret
  1976. ;
  1977. ; Check A for alpha char ... return CY=1 if not
  1978. ;
  1979. alpha:    cpi    'A'
  1980.     rc            ;exit, way too lo
  1981.     cpi    'Z'+1
  1982.     cmc
  1983.     rnc            ;return if A-Z
  1984.     cpi    'a'
  1985.     rc            ;exit, >Z, <a
  1986.     cpi    'Z'+1
  1987.     cmc
  1988.     ret
  1989. ;
  1990.     end
  1991. ;
  1992. a delimiter is found.
  1993. ; entry hl    first character of name to be scanned
  1994. ;    de    po