home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / cpm80 / cpsutl.asm < prev    next >
Assembly Source File  |  2020-01-01  |  41KB  |  1,228 lines

  1. ; CPSUTL.ASM
  2. ;       KERMIT - (Celtic for "FREE")
  3. ;
  4. ;       This is the CP/M-80 implementation of the Columbia University
  5. ;       KERMIT file transfer protocol.
  6. ;
  7. ;       Version 4.0
  8. ;
  9. ;       Copyright June 1981,1982,1983,1984,1985
  10. ;       Columbia University
  11. ;
  12. ; Originally written by Bill Catchings of the Columbia University Center for
  13. ; Computing Activities, 612 W. 115th St., New York, NY 10025.
  14. ;
  15. ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,
  16. ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many
  17. ; others. 
  18. ;
  19. ;       Utility routines, pure and impure data.
  20. ;
  21. ; revision history:
  22. ;
  23. ;edit 31, 21-Mar-1991 by MF. Implement edit 30 without checking takflg after
  24. ;    "r1tch1" as we are **always** TAKEing from a file if we get to that
  25. ;    point in the code. Makes for simplicity.
  26. ;edit 30, 27-Feb-1991 by MF. When TAKEing characters from a TAKE-file,
  27. ;    view semicolons as normal characters (not command separators).
  28. ;    This will allow such commands as REMOTE DELETE *.*;* to work
  29. ;    properly from TAKE-files without having to revert to old code in
  30. ;    cpsrem.asm at "remcl0" to decode Remote command arguments. TAKE-files
  31. ;    ought not (in my opinion) to have multiple commands per line anyway.
  32. ;edit 29, 30-Jan-1991 by MF. Fix bug in IN1CHR which decremented "chrcnt"
  33. ;    once too often after a call to INBUF (which predecrements it
  34. ;    already). This, along with a fix in CPSTT.ASM, fixes a bug in the
  35. ;    TRANSMIT command wherein certain characters in the file were not
  36. ;    being transmitted. This bug was reported to me by Lance Tagliapietra
  37. ;    of the University of Wisconsin at Platteville, WI (Email:
  38. ;    <TAGLANCE@ucs.UWPLATT.EDU>).
  39. ;    (he suggested not predecrementing "chrcnt" in INBUF" but this
  40. ;    breaks code in routine "GTCHR" from CPSPK1.ASM so it's better
  41. ;    to modify IN1CHR in this module and XMIT in CPSTT.ASM).
  42. ;edit 28, 30-Nov-1990 by MF. Modify routine "p20ln" to use "pausit" routine
  43. ;    rather than explicitly checking for Console input to eliminate
  44. ;    redundant code. Also fix spelling in "p20ln"'s comments.
  45. ;edit 27, 9-Sep-90 by MF.  Put RET in routine PAUSIT per CPKERM.BWR.
  46. ; edit 26, September, 1987.  Added pause-it routine to wait for a user keysroke.
  47. ;
  48. ; edit 25, August 19, 1987 by OBSchou.  Fixed a few bugs here and there.
  49. ;
  50. ; edit 24, April 8, 1987 by OBSchou.  Added routine to return one character
  51. ;    from a section of several sectors worth of file.  This routine needed
  52. ;    for TRANSMIT.
  53. ;
  54. ; edit 23, March 11, 1986 by OBSchou for Richard Russell
  55. ;    Bug in the TAKE code, such that a new sector was read in after 256
  56. ;    bytes, and not the CPM value.  A jnz is now jp in the test to see if 
  57. ;    the file buffer has bben exhausted.  Many thanks for finding this 
  58. ;    bug.  I have never used TAKE files more than 128 bytes long.
  59. ;
  60. ; edit 22, January 28, 1986 by OBSchou.
  61. ;    split off the data areas from CPSUTL to CPSDAT.ASM  (All in line
  62. ;    with keeping individual files relatively small)
  63. ;
  64. ; edit 21 August, 1986 by OBSchou.  Sorted a few more bugs in printer buffer
  65. ;       etc.  Have yet to try this with a real printer  The code, apart from 
  66. ;       actually printing works OK.
  67. ;
  68. ; edit 26  20 August, 1986 by OBSchou for Godfrey Nix:
  69. ;       edit 8-Aug-86  by Godfrey N. Nix   [gnn]  Nottingham University
  70. ;       Added two extra bytes for storage of the send and receive
  71. ;       start-of-packet characters. Used by CP4PKT, and altered
  72. ;       by SET option in CP4MIT. Also added message strings for 
  73. ;       use by show routines. Added remote filename buffer and length byte.
  74. ;
  75. ; edit 11: June 20, 1986 by OBSchou.  Added multi-fcbs for the DIR command
  76. ;       together with some bug clearing and new routines.  Had to move
  77. ;       the overlay to 5000h as we ran out of space...
  78. ;
  79. ; edit 10: June 16, 1986 OBSchou.  Added a pseudo clock and check for printer
  80. ;       ready whenever one enters BDOS...  This may slow things down a little
  81. ;       but adds in (hopefully) pseudo background printing...
  82. ;
  83. ; edit 9 30-May-86 OBSchou.  Added XON/XOFF routines here for the world 
  84. ;       at large to use.  Also added two new entries in the overlay tables.  
  85. ;       One to give the address of the family of machines using the overlay, 
  86. ;       the other to the routine for giving printer status.
  87. ;
  88. ; edit 8: 27-May-86 OBSchou.  Added code to check BDOS calls for info from
  89. ;       the console.  If so, and the take flag (takflg) is set then we 
  90. ;       substitute our own characters.  Simple, a little tatty...
  91. ;       Also added bits for SET CASE-SENSITIVE and SET FLOW=CONTROL, and 
  92. ;       removed the XMIT rubbish.  This is a prelude to better TRANSMIT
  93. ;
  94. ; edit 7: 22 April, 1986 by OBSchou Lohghborough University
  95. ;       Prlude to more changee, this time make overlay address to 4000h
  96. ;       May revert back to ($+0ffh) AND 0ff00h as address for overlay.
  97. ;       This gives us space to make quite a few modifications to the system
  98. ;       dependent part without much fear of having to change this overlay
  99. ;       address.  Should also fix the Osborne problem of having to have io 
  100. ;       routines ii memory above 16k.  I know I should not be introducing
  101. ;       such system dependent rot here, but it wont be too difficult to fill
  102. ;       memory to 4000h.
  103. ;
  104. ; edit 6: February 6, 1985
  105. ;       Added a storage location for the port value (PORT, just below
  106. ;       SPEED) which is used by the port status routine, and moved the
  107. ;       printer copy flag (PRNFLG:) into the communications area so
  108. ;       that the machine dependant overlay can toggle it. [Hal Hostetler]
  109. ;       Added ffussy flag for filename checking.  Generate the version
  110. ;       string from 'verno', which is set in CP4KER, because CP4KER has the
  111. ;       list of modules and their edit numbers. [Charles Carvalho]
  112. ;
  113. ; edit 5: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809
  114. ;
  115. ;pcc002 28-Dec-84       modules:cp4tt,cp4utl
  116. ;       Add connect mode <esc>P command to toggle printer on
  117. ;       and off.  Conflicts with "official" recommended commands
  118. ;       in protocol manual, but I don't think CP/M will ever get
  119. ;       a PUSH command.
  120. ;
  121. ;pcc003-pcc005  2-Jan-85        vjc     modules:cp4mit,cp4tt,cp4utl
  122. ;       These edits must all be installed together and change the way
  123. ;       logging is handled.  The log file spec is moved to a separate
  124. ;       fcb, and not opened until an actual CONNECT command is given.
  125. ;       This takes care of a NASTY bug that if you used any other file
  126. ;       command between the LOG and CONNECT, the log file would get
  127. ;       written over the last file used.  This also allows logging to
  128. ;       be "permanently" enabled until an CLOSE (new command) for all
  129. ;       CONNECT sessions, like most other kermits do.  If a log file
  130. ;       already exists, it will be appended to.  Also add two new
  131. ;       CONNECT mode commands <esc>Q to suspend logging and <esc>R to
  132. ;       resume.  <esc>R means something else during TRANSMIT, but
  133. ;       logging is never on then, so there shouldn't be any conflict.
  134. ;       I also changed the write code, so that it can handle one more
  135. ;       character after the XOFF is send to stop the host.  This allows
  136. ;       a little "slop" for systems that don't stop immediately (such
  137. ;       as TOPS10), but it didn't help much.
  138. ;
  139. ;pcc006 2-jan-85        VJC     modules:cp4cmd,cp4utl
  140. ;       Problems with "?" in filespecs.  On reparse, may cause action
  141. ;       flag to be reset at wrong point, requiring multiple <CR>'s
  142. ;       to terminate the line or other weird stuff.  Also need to
  143. ;       check flag and complain if wild-cards illegal.
  144. ;
  145. ;pcc008 2-Jan-85        vjc     modules:cp4def,cp4tt,cp4utl
  146. ;       Keyboard input during CONNECT mode can get locked out if
  147. ;       there is enough input from the modem port to keep prtchr
  148. ;       busy.  This can happen for example, if the printer is running
  149. ;       at the same speed as the modem line, leaving you helpless to
  150. ;       turn it off or abort the host.  Add a fairness count, so that
  151. ;       at least every prfair characters we look at console input.
  152. ;
  153. ;pcc012 4-Jan-85        vjc     modules:cp4mit,cp4tt,cp4utl
  154. ;       Use the big buffer for the log file.  Move the log file back
  155. ;       into the common fcb and only save the drive, name, and
  156. ;       extension between connects.  Add new routines to cp4utl to
  157. ;       create or append to an existing file, and to conditionally
  158. ;       advance buffers only if in memory.  Remove edit pcc003 that
  159. ;       allows one more character after the xoff, since it didn't
  160. ;       really work very well and does not fit in well with the way
  161. ;       the buffer advancing routines are set up.  If someone still
  162. ;       thinks this would be useful, it could be put back in with a
  163. ;       little more work.
  164. ;       
  165. ;       While testing this edit, I also noticed another bug that
  166. ;       the command parsing routines do not limit or check the
  167. ;       length of command lines or file specs, trashing what ever
  168. ;       comes after them.  Currently because of where the fcb and
  169. ;       command buffer are located, this does not usually cause a
  170. ;       problem, but could if an extremely long line was typed in,
  171. ;       or in the future multiple fcbs defined elsewhere in memory
  172. ;       were used.  Maybe this should be put on the bug list
  173. ;       somewhere.
  174. ;
  175. ;pcc013 8-Jan-85        vjc     modules:cp4mit,cp4utl,cp4typ
  176. ;       Replace CLOSE command to cancel session logging to SET
  177. ;       LOGGING ON/OFF.  This seems to fit in with the command
  178. ;       structure better.  Default the log file to KERMIT.LOG
  179. ;       incase no previous LOG command.  Logging is also enabled
  180. ;       by LOG command, as before.
  181. ;
  182. ; edit 4: September 9, 1984
  183. ;       Move command tables and associated help text to CP4MIT.  Add
  184. ;       makfil/clofil routines and modify outbuf to write files in big
  185. ;       chunks.  Update Kermit's version to 4.03.
  186. ;
  187. ; edit 3: August 21, 1984
  188. ;       Make inbuf read files in big chunks to minimize disk start/stop
  189. ;       delays.  Buffer size and address is specified by system-dependent
  190. ;       overlay.
  191. ;
  192. ; edit 2: August 3, 1984
  193. ;       move "mover" to CP4SYS to allow use of Z80 block move instruction.
  194. ;
  195. ; edit 1: July 27, 1984
  196. ;       extracted from CP4MIT.M80 edit 2, as part of LASM support.  This is
  197. ;       the last file linked for the system-independent code.
  198. ;
  199. utlver:    db    'CPSUTL.ASM (31) 21-Mar-1991$'
  200.  
  201. ;       Set the parity for a character in A.
  202. ;       called by: spack, rexmit, logit, vt52, conchr, intchr
  203.  
  204. setpar:    push    h        ;Save HL.
  205.     push    b
  206.     lxi    h,parity
  207.     mov    c,m        ;Get the parity routine.
  208.     mvi    b,0
  209.     lxi    h,parjmp    ;Get the first address.
  210.     dad    b
  211.     pchl
  212.  
  213. parjmp:    jmp    even
  214.     jmp    mark
  215.     jmp    none
  216.     jmp    odd
  217.     jmp    spacep
  218.  
  219. none:    jmp    parret        ;Don't touch the parity bit.
  220.  
  221. even:    ani    7FH        ;Strip parity.
  222.     jpe    parret        ;Already even, leave it.
  223.     ori    80H        ;Make it even parity.
  224.     jmp    parret
  225.  
  226. mark:    ori    80H        ;Turn on the parity bit.
  227.     jmp    parret
  228.  
  229. odd:    ani    7FH        ;Strip parity.
  230.     jpo    parret        ;Already odd, leave it.
  231.     ori    80H        ;Make it odd parity.
  232.     jmp    parret
  233.  
  234. spacep:    ani    7FH        ;Turn off the parity bit.
  235.     jmp    parret
  236.  
  237. parret:    pop    b
  238.     pop    h        ;Restore HL.
  239.     ret
  240. ;
  241. ;       Print the escape char.
  242. ;       called by: stat01, telnet, intchr
  243.  
  244. escpr:    lda    escchr        ;Get the escape char.
  245. escpr1:    cpi    ' '             ;Is it a control char?
  246.     jp    escpr2
  247.     push    psw        ; save the character
  248.     lxi    d,inms10    ;Output "Control-".
  249.     call    prtstr
  250.     pop    psw        ; restore the character
  251.     ori    100O        ;De-controlify.
  252. escpr2:    mvi    c,conout    ;Output the char
  253.     mov    e,a
  254.     call    bdos
  255.     ret
  256.  
  257. ;       fetch keyword; if unsuccessful, return to command level.
  258. ;       called by: kermit, setcom
  259.  
  260. keycmd:    mvi    a,cmkey
  261.     call    comnd
  262.     jmp    keycm2        ;no match
  263.     ret
  264.  
  265. keycm2:    lxi    d,ermes1    ;"Unrecognized Command"
  266.     call    prtstr
  267.     jmp    kermit        ;Do it again.
  268.  
  269. ;       request confirmation; if unsuccessful, return to command level
  270. ;       called by: bye, exit, help, log, setcom, show, status, send,
  271. ;               finish, logout, telnet
  272.  
  273. cfmcmd:    mvi    a,cmcfm
  274.     call    comnd
  275.     jmp    kermt3        ;"Not confirmed"
  276.     ret
  277. ;
  278.  
  279. ;       This routine prints the number in HL on the screen in decimal.
  280. ;       Uses all ACs.
  281. ;       called by: cp4sys, read, send, updrtr, dir, user
  282.  
  283. nout:    mvi    a,'0'           ; fill tempx with zeros
  284.     call    filltmp
  285.  
  286.     lxi    b,-10        ;Get some useful constants.
  287. nout1:    lxi    d,-1
  288.  
  289. nout2:    dad    b        ;Subtract as many 10s as possible.
  290.     inx    d        ;Count them.
  291.     jc    nout2        ;If some left keep going.
  292.     push    h        ;save remainder - 10
  293.     xchg        ;Swap the remainder and the quotient.
  294.     mov    a,h        ;Get the number of 10s found.
  295.     ora    l        ;check for quotient non zero
  296.     cnz    nout1        ;If non zero, recurse.
  297.     pop    h        ;Get the remainder - 10
  298.     mov    a,l        ;in a
  299.     adi    '0'+10          ;Make the number printable and add the 10 back
  300.     call    shiftmp        ; cycle temp registers
  301.     sta    temp1        ; and save digit
  302.     mov    e,a        ;Output the digit.
  303.     lda    nquiet        ; are we to be quiet?
  304.     ana    a
  305.     rnz        ; yup, so return here rather than frm bdos
  306.     mvi    c,conout
  307.     jmp    bdos
  308.  
  309. ; prcrlf - print a CR/LF.  (Saves no registers.) [Toad Hall]
  310. ; prtstr - print string pointed to by DE (now in overlay section.. see prtstx)
  311. ;       called by: lots of places.
  312. prcrlf:    lxi    d,crlf        ;Point to the CR/LF
  313.     jmp    prtstr        ; Use the one in the overlay
  314.  
  315. ; prtstx is funtionally the same as prtstr in the overaly but is here as 
  316. ;    we may need a print a string routine in case the overlay is
  317. ;    either incorrect version or simply not present.
  318. prtstx:                ; PRTSTR moved to overlay, but we do need the
  319.                 ; same function for writing the sign-on
  320.                 ; message and error message if the overlay
  321.                 ;is not present.  Thence prtstx
  322.     mvi    c,prstr        ; output string
  323.     jmp    bdos        ;a CALL followed by a RET becomes a JMP
  324.  
  325.  
  326. ;       Jumping to this location is like retskp.  It assumes the instruction
  327. ;       after the call is a jmp addr.
  328. ;       here from: many places.
  329. rskp:    pop    h        ;Get the return address.
  330.     inx    h        ;Increment by three.
  331.     inx    h
  332.     inx    h
  333.     pchl
  334.  
  335. ;       Jumping here is the same as a ret.  'jmp r' is used after routines
  336. ;       that have skip returns, where the non-skip instruction must be 3 bytes.
  337. ;       here from: many places.
  338. r:    ret
  339.  
  340. ; Pause-it routine.  Informs the user to press any key to continue
  341. ;    and then waits for a key input.  Called by the any routine 
  342. ;    with more than, say, 20 lines of output.
  343.  
  344. pausit:    lxi    d,anymes    ; ask user to press any key to continue
  345.     call    prtstr
  346. pausi1:    call    ckcon        ; see if a key typed
  347.     ana    a
  348.     jz    pausi1        ; loop until a key has been pressed.
  349.  
  350.     ret
  351.  
  352. ;
  353. ;       Open a file for reading (with inbuf).  The filename is already
  354. ;       in fcb; upon return, the end of file flag is cleared and chrcnt
  355. ;       is set to zero, so inbuf will be called to get a buffer when we
  356. ;       next attempt to get a character.
  357. ;       called by: sinit, seof
  358.  
  359. getfil:    xra    a
  360.     sta    chrcnt        ;Buffer is empty.
  361.     sta    seccnt        ;No sectors buffered.
  362.     sta    eoflag        ;Not the end of file.
  363.     sta    endsts        ;No EOF/error pending.
  364.     sta    fcb+0CH        ;Zero the extent.
  365.     sta    fcb+0EH        ;Must be zero for MAKEF or OPENF.
  366.     sta    fcb+20H        ;Zero the current record.
  367.     mvi    c,openf        ;Open the file.
  368.     lxi    d,fcb
  369.     call    bdos
  370.     ret
  371.  
  372. ;       Get next sector.  If necessary, read some more from disk.
  373. ;       preserves bc, de, hl
  374. ;       returns nonskip if EOF or error;
  375. ;       returns skip with chrcnt and bufpnt updated if success.
  376. ;       called by: gtchr, get1xc (from xmt/transmit)
  377.  
  378. inbuf:    lda    eoflag        ;Have we reached the end?
  379.     ora    a
  380.     rnz        ;Return if so.
  381.     push    b
  382.     push    d
  383.     push    h
  384. inbuf1:    lda    seccnt        ; Do we have any sectors left?
  385.     ora    a
  386.     jz    inbuf3        ; If not, go get some more.
  387. inbuf2:    lhld    nxtbuf        ; Yes.  Get address of next sector
  388.     shld    bufpnt        ; Update current buffer pointer
  389.     lxi    b,bufsiz    ; Get number of bytes in sector
  390.     dad    b        ; Update HL to point to next sector
  391.     shld    nxtbuf        ; Save for next time
  392.     dcr    a        ; Decrement count of buffered sectors
  393.     sta    seccnt        ; Put it back
  394.     mvi    a,bufsiz-1    ; Number of bytes in buffer (pre-decremented)
  395.     sta    chrcnt        ; Store for our caller
  396.     pop    h
  397.     pop    d
  398.     pop    b
  399.     jmp    rskp        ; Return success
  400.  
  401. ; We don't have any sectors buffered.  If we've already hit an error or
  402. ; EOF, return that status to the user.
  403.  
  404. inbuf3:    lda    endsts        ; Check status from previous read
  405.     ora    a
  406.     jz    inbuf4        ; It was OK.  Get some more sectors.
  407.     sta    eoflag        ; End of file or error.  Set the flag.
  408.     xra    a
  409.     sta    chrcnt        ; Say no characters in buffer.
  410.     pop    h
  411.     pop    d
  412.     pop    b
  413.     ret        ; Return failure
  414.  
  415. ; Read sectors until we fill the buffer or get an error or EOF, then return
  416. ; the first buffer to the user.  (seccnt is zero)
  417.  
  418. inbuf4:    lhld    bufadr        ; Get address of big buffer
  419.     shld    nxtbuf        ; Store as next buffer address to give user
  420. inbuf5:    shld    bufpnt        ; Store as next buffer address to read into
  421.     xchg        ; Move buffer address to DE
  422.     mvi    c,setdma    ; Tell CP/M where to put the data
  423.     call    bdos        ;  ...
  424.     mvi    c,readf        ; Read a record.
  425.     lxi    d,fcb
  426.     call    bdos
  427.     sta    endsts        ; Save ending status
  428.     ora    a        ; 00H => read O.K
  429.     jnz    inbuf6        ; EOF/error: stop reading.
  430.     lxi    h,seccnt    ; Success.  Get addr of sector count
  431.     inr    m        ; Bump sector count by one
  432.     lda    bufsec        ; Get max number of sectors in buffer
  433.     cmp    m        ; Are we there yet?
  434.     jz    inbuf7        ; Yes, can't read any more.
  435.     lhld    bufpnt        ; No, try for another.  Get buffer address,
  436.     lxi    d,bufsiz    ;  and size of sector,
  437.     dad    d        ;  giving next buffer address in HL
  438.     jmp    inbuf5        ; Go read another sector.
  439.  
  440. ; We hit EOF or got an error.  Put the DMA address back where it belongs,
  441. ; then go see if we have any sectors (before the one that got the error)
  442. ; to return to the caller.  Nxtbuf points to the first good sector, if
  443. ; any; seccnt contains the count of good sectors.
  444.  
  445. inbuf6:    call    rstdma
  446.     jmp    inbuf1        ; Go see if we have some data to return
  447.  
  448. ; We've filled the big buffer.  Reset the DMA address, then go return a
  449. ; sector to the caller.  nxtbuf points to the beginning of the buffer;
  450. ; seccnt contains the number of sectors successfully read (except that
  451. ; if we've read 256 sectors, seccnt contains zero, so we can't just go
  452. ; to inbuf1).
  453.  
  454. inbuf7:    call    rstdma        ;[pcc012]
  455.     lda    seccnt        ; Get sector count again.
  456.     jmp    inbuf2        ; Return a sector.
  457.  
  458. ; IN1CHR - get a single character from the file.  Taken code from old
  459. ;    TRANSMIT routine.
  460. in1chr:
  461.     lda    eoflag        ;EOF encountered?
  462.     ora    a
  463.     rnz        ; Yes, finish.
  464.     lxi    d,cmdbuf    ; Use comnd buffer as line buffer.
  465.     lhld    bufpnt        ; Get current buffer pointer.
  466.     lda    chrcnt        ; Get current byte count
  467.     mov    b,a        ;  in B
  468. in1ch1:    dcr    b        ; Assume there's a character there
  469.     jp    in1ch2        ; If there was, proceed.
  470.     call    inbuf        ; There wasn't.  Try for another buffer.
  471.     jmp    in1che        ; End of file.
  472.     lhld    bufpnt        ; Got another buffer.  Get new pointer in HL
  473.     lda    chrcnt        ;  and new byte count
  474.     mov    b,a        ;  in B
  475. ;[MF]The modification below was made 30-Jan-1991 per report from
  476. ;[MF]Lance Tagliapietra from the University of Wisconsin at Platteville
  477. ;[MF]The following instruction should not be executed as the character counter
  478. ;[MF]has already been decremented by INBUF.
  479. ;    dcr    b        ; we are reading in a character, so less one
  480. in1ch2:    mov    a,b        ; save new count
  481.     sta    chrcnt
  482.     mov    a,m        ; Get a character from disk buffer.
  483.     inx    h
  484.     shld    bufpnt        ; save new pointer
  485.     ani    7FH        ; Mask 7 bits.
  486.     jz    in1ch1        ; Skip nulls.
  487.     ret        ; character in a
  488.  
  489.  
  490. in1che:    mvi    a,0ffh        ; dubious about this one...
  491.     sta    eoflag
  492.     ret        ; set end of file flag...?????
  493.  
  494. ; ;[pcc012]
  495. ;   appfil - Create or append to an existing file.  File name is in FCB.
  496. ;       Non-skip return if could not be done.  Skip return with file
  497. ;       open and bufpnt pointing to end of file.
  498. ;       called by logopn
  499. appfil:    xra    a        ;[pcc012] zero out stuff for open
  500.     sta    fcb+0CH        ;[pcc012] extent
  501.     sta    fcb+0EH        ;[pcc012] Must be zero for MAKEF or OPENF.
  502.     sta    fcb+20H        ;[pcc012] Zero the current record.
  503.     mvi    c,openf        ;[pcc012] Try to open the file
  504.     lxi    d,fcb        ;[pcc012]
  505.     call    bdos        ;[pcc012]
  506.     cpi    0FFH        ;[pcc012] Did we find it?
  507.     jz    makfi1        ;[pcc012] If not, go create it
  508.     mvi    c,cflsz        ;[pcc012] Compute the file size
  509.     lxi    d,fcb        ;[pcc012]
  510.     call    bdos        ;[pcc012]
  511.     lhld    fcb+21H        ;[pcc012] random record pointer
  512.     mov    a,h        ;[pcc012] See if zero length file
  513.     ora    l        ;[pcc012]
  514.     jz    makfi2        ;[pcc012] set up pointers if null file
  515.     dcx    h        ;[pcc012] backup to last record written
  516.     shld    fcb+21H        ;[pcc012] store rec ptr back
  517.     lhld    bufadr        ;[pcc012] get buffer address
  518.     xchg        ;[pcc012] to DE
  519.     mvi    c,setdma    ;[pcc012] set dma address
  520.     call    bdos        ;[pcc012] for read
  521.     mvi    c,rrand        ;[pcc012] read the last block
  522.     lxi    d,fcb        ;[pcc012]
  523.     call    bdos        ;[pcc012]
  524.     ora    a        ;[pcc012] check results
  525.     jnz    rstdma        ;[pcc012] reset dma and return if error
  526.     lhld    bufadr        ;[pcc012] get address again
  527.     lxi    d,bufsiz    ;[pcc012] and and size
  528.     mvi    a,'Z'-40H       ;[pcc012] control-Z for comparison
  529. appcz:    cmp    m        ;[pcc012] Is this the EOF?
  530.     jz    appxit        ;[pcc012] Jump if yes
  531.     inx    h        ;[pcc012] no, bump
  532.     dcr    e        ;[pcc012] and grind
  533.     jnz    appcz        ;[pcc012] until find or buffer empty
  534. appxit:    shld    bufpnt        ;[pcc012] store buffer pointer
  535.     dad    d        ;[pcc012] compute next buffer adr
  536.     shld    nxtbuf        ;[pcc012] and store
  537.     mov    a,e        ;[pcc012] updated chr count
  538.     sta    chrcnt        ;[pcc012]
  539.     xra    a        ;[pcc012] reset sector count
  540.     sta    seccnt        ;[pcc012]
  541.     call    rstdma        ;[pcc012] reset normal dma
  542.     jmp    rskp        ;[pcc012] and give good return
  543.  
  544. ;       Create a file, deleting any previous version.  The filename is in
  545. ;       fcb.
  546. ;       Returns nonskip if file could not be created.
  547. ;       If successful, takes skip return with bufpnt and chrcnt initialized
  548. ;       for output; buffers should be output via outbuf.
  549. ;       called by: gofil
  550. makfil:    mvi    c,delf        ; delete the file if it exists.
  551.     lxi    d,fcb
  552.     call    bdos
  553.     xra    a
  554.     sta    fcb+0CH        ; zero the extent.
  555.     sta    fcb+0EH        ; must be zero for MAKEF or OPENF.
  556.     sta    fcb+20H        ; zero the current record.
  557. ;[pcc012] here from appfil above if file does not exist
  558. makfi1:    mvi    c,makef        ;[pcc012] now create it.
  559.     lxi    d,fcb
  560.     call    bdos
  561.     cpi    0FFH        ; is the disk full?
  562.     rz        ; take error return if so.
  563. ; success. set up pointers and counters for multisector buffering.
  564. ;[pcc012] also here from appfil if found zero length file
  565. makfi2:    lhld    bufadr        ;[pcc012] find beginning of buffer space.
  566.     shld    bufpnt        ; make it current buffer.
  567.     lxi    d,bufsiz    ; get sector size.
  568.     dad    d        ; find beginning of next buffer.
  569.     shld    nxtbuf        ; store for later.
  570.     mov    a,e        ; store buffer size
  571.     sta    chrcnt        ;  for caller.
  572.     xra    a
  573.     sta    seccnt        ; no sectors stored yet.
  574.     jmp    rskp        ; take success return.
  575.  
  576. ;[pcc012]
  577. ;   outadv - conditionally advance output buffer if disk write not needed.
  578. ;       preserves BC
  579. ;       skip return with with next output buffer set up
  580. ;       non-skip return if memory buffer full and must write to disk.
  581. ;       called by:logit
  582.  
  583. outadv:    push    b        ;[pcc012] save BC as advertised
  584.     lxi    h,seccnt    ;[pcc012] point to sectors buffered
  585.     inr    m        ;[pcc012] count this one
  586.     lda    bufsec        ;[pcc012] how many we can hold
  587.     cmp    m        ;[pcc012] check if full
  588.     jnz    outbf2        ;[pcc012] continue if not
  589.     dcr    m        ;[pcc012] full, un-advance sector count
  590.     pop    b        ;[pcc012] restore bc
  591.     ret        ;[pcc012] and give non-skip return
  592.  
  593. ;       get a fresh output buffer, flushing big buffer if necessary.
  594. ;       returns nonskip if disk full.
  595. ;       if successful, returns skip with bufpnt and chrcnt updated.  Note
  596. ;       that chrcnt holds one less than the buffer size.
  597. ;       preserves BC.
  598. ;       called by: ptchr,logwrt
  599.  
  600. outbuf:    push    b
  601.     lxi    h,seccnt    ; count another buffered sector
  602.     inr    m        ;  ...
  603.     lda    bufsec        ; get number of sectors we can hold
  604.     cmp    m        ; full?
  605.     jnz    outbf2        ; if not, set up pointers and return
  606.     call    outmbf        ; flush the big buffer
  607.     jmp    outbf9        ; disk error.
  608. ;[pcc012] also here from outadv to advance buffer
  609. outbf2:    lhld    nxtbuf        ; get pointer to fresh buffer
  610.     shld    bufpnt        ; store for caller
  611.     lxi    d,bufsiz    ; advance our pointer to next buffer
  612.     dad    d
  613.     shld    nxtbuf
  614.     mvi    a,bufsiz-1    ; get buffer size (pre-decremented)
  615.     sta    chrcnt        ; store for caller
  616.     pop    b
  617.     jmp    rskp        ; return success.
  618.  
  619. outbf9:    pop    b        ; clean up stack
  620.     ret        ; and take error return.
  621.  
  622. ;       flush incore output buffers.
  623. ;       returns nonskip if disk full.
  624. ;       if successful, returns skip with nxtbuf reset to start of buffer and
  625. ;       seccnt zero.
  626. ;       destroys all ac's.
  627. ;       called by: outbuf, clofil.
  628.  
  629. outmbf:    lhld    bufadr        ; get start of buffer
  630.     shld    nxtbuf        ; store for next fill cycle
  631.     shld    bufpnt        ; store for empty loop
  632. outmb2:    lhld    bufpnt        ; get address of current sector
  633.     xchg        ;  into DE
  634.     lxi    h,bufsiz    ; advance HL to next sector
  635.     dad    d        ;  ...
  636.     shld    bufpnt        ;  and store for later
  637.     mvi    c,setdma
  638.     call    bdos        ; point CP/M at current sector
  639.     lxi    d,fcb
  640.     mvi    c,writef
  641.     call    bdos        ; output the sector
  642.     ora    a        ; test for error (A non-zero)
  643.     jnz    rstdma        ;[pcc012] reset dma and take nonskip return if so
  644.     lxi    h,seccnt
  645.     dcr    m        ; count down buffered sectors
  646.     jnz    outmb2        ; loop if more saved
  647.     call    rstdma        ;[pcc012] restore normal dma
  648.     jmp    rskp        ; return success.
  649.  
  650. ;       output current buffer, flush incore buffers, and close output file.
  651. ;       returns nonskip if disk full; skip if successful.
  652. ;       called by: rdata
  653.  
  654. clofil:
  655.     lda    chrcnt        ; get the number of chars left in the buffer.
  656.     cpi    bufsiz        ; Virgin buffer?
  657.     jz    clofl3        ; yes, don't output it.
  658.     lhld    bufpnt        ; get the buffer pointer.
  659. clofl1:    dcr    a        ; lower the count.
  660.     jm    clofl2        ; if full then stop.
  661.     mvi    m,'Z'-100O      ; put in a ^Z for EOF.
  662.     inx    h        ; point to the next space.
  663.     jmp    clofl1
  664.  
  665. clofl2:    call    outbuf        ; output the last buffer.
  666.     jmp    r        ; give up if the disk is full.
  667. clofl3:    lda    seccnt        ; any sectors buffered in memory?
  668.     ora    a
  669.     jz    clofl4        ; if not, don't try to flush.
  670.     call    outmbf        ; flush buffers
  671.     jmp    r        ; disk full.
  672. clofl4:    mvi    c,closf        ; close up the file.
  673.     lxi    d,fcb
  674.     call    bdos
  675.     jmp    rskp        ; return success.
  676.  
  677.  
  678. ; Reset DMA address to the default buffer
  679. ; called from inbuf,appfil,outmbf
  680. rstdma:    lxi    d,buff        ;[pcc012]
  681.     mvi    c,setdma    ;[pcc012]
  682.     jmp    bdos        ;[pcc012]
  683.  
  684. ; [8] Intercept BDOS calls to check for console input
  685. ; This leads to simple trapping for input from disk rather than from the
  686. ; keyboard, alowing commands to be stored in a TAKE file.
  687. ; Printer is tested for readiness, and the second fuzzy clock is updated.
  688. bdos:    ;call    print        ; print a character to the printer if needed
  689.     ;call    clock        ; update the clock
  690.     push    psw        ; we will need this register
  691.     lda    takflg        ; are we taking from a 
  692.     ana    a        ; file or from command line
  693.     jz    notake        ; no, so do usual BDOS stuff
  694.     mov    a,c        ; get bdos function
  695.     cpi    conin        ; is it console in?
  696.     jz    bd1in        ; get a single character
  697.     cpi    dconio        ; direct console in or out?
  698.     jz    bd1io        ; test further for inpu or output
  699.     cpi    rdstr        ; read the console buffer?
  700.     jz    bdcbuf        ; then do it
  701.     cpi    consta        ; get the console status?
  702.     jz    bdcst        ; anything left in buffer?
  703. notake:    pop    psw        ; else we have a kosher BDOS call
  704.     jmp    0005h        ; Absolute address = BDOS entry point
  705. ;
  706. bd1in:    ; get a single character from take file
  707.     pop    psw        ; restore stack
  708.     call    r1tchr        ; read a single take character
  709.     ret        ; and return.  We dont expand tabs, 
  710.                 ; check for xon/off or backspaces.  
  711.                 ;Make sure the take file is error free?
  712. ;
  713. bd1io:    ;get or put a single character from/to console
  714.     mov    a,e        ; get e.  If 0ffh then input else output
  715.     inr    a        ; if 0 then input
  716.     jnz    notake        ; its for output, so let notake restore stack
  717.     pop    psw        ; otherwise we do it
  718.     call    r1tchr        ; read a single take character
  719.     ret        ; and return from out BDOS
  720. ;
  721. bdcbuf:    ; read a line of edited (?) input from the console
  722.     pop    psw        ; restore stack
  723.     inx    d        ; point to nc
  724. bdosc1:    call    r1tchr        ; get a character
  725.     cpi    cr        ; if a cr then return
  726.     jz    nomore
  727.     cpi    lf        ; ignore line feeds
  728.     jz    bdosc1        ; so get another character
  729.     push    psw        ; we will want it later
  730.     mvi    h,0
  731.     ldax    d        ; get nc, the no of characters in buffer
  732.     mov    l,a        ; now use as index from  de+2
  733.     mvi    h,0
  734.     inx    d        ; de is now de + 2
  735.     dad    d
  736.     pop    psw        ; Told you we will want this
  737.     mov    m,a
  738.     dcx    d        ; point again to nc
  739.     xchg        ; make hl point to memory
  740.     inr    m        ; update pointer nc
  741.     xchg        ; restore it
  742.     jmp    bdosc1
  743. nomore:    dcx    d        ; restore de to point to buffer
  744.     ret
  745.  
  746. bdcst:    ; get the console status.  Returns a 00 if at eof
  747.     pop    psw
  748.     push    h        ; now save de, hl for return
  749.     push    d        ;
  750.     lxi    d,takdma    ; make a point to next byte...
  751.     lhld    takptr        ; pointer from dma address.  There will always
  752.     dad    d        ; be at least one byte, as the buffer is 
  753.     mov    a,m        ; ...
  754.     pop    d        ; filled only if a read empties it.
  755.     pop    h        ; restore hl, de
  756.     cpi    cntlz        ; end of file?
  757.     mvi    a,0ffh        ; say there is
  758.     rnz        ; if it is not a cntl z
  759.     jmp    closet        ; otherwise, close take file etc
  760.  
  761. r1tchr:        ; read a single character from the take file or command line
  762.     push    h
  763.     push    d        ; save in case of return
  764.     lda    takflg        ; see if character is to come from file or line
  765.     ani    1        ; if bit zero set, from take file
  766.     jz    r1lchr        ; get character from the command line
  767.     lxi    d,takdma
  768.     lhld    takptr        ; get next data byte
  769.     dad    d
  770.     mov    a,m
  771.     lhld    takptr        ; cos it's destroyed with dad
  772.     inx    h
  773.     shld    takptr        ; update pointer
  774.     call    p1tchr        ; print it (so the user sees it)
  775.     push    psw        ; save the read data for a while
  776.     mov    a,l        ; if l = 0 then read another sector
  777.     ana    a
  778.     jp    r1tch1        ;[23] was jnz. jp => 128 byte sectors
  779.     call    rnsect        ;read next sector
  780. r1tch1:    pop    psw        ; now, is this a cntl-z.. in whic case
  781.     pop    d        ; also these...
  782.     pop    h
  783.     cpi    lf        ; skip if a line feed
  784.     jz    r1tchr        ;
  785. ;[MF][31][30]Following lines commented out so semicolons are not considered
  786. ;[MF][31][30]command separators and thus are considered part of the command
  787. ;[MF][31][30]so commands like REMOTE DELETE *.*;* work correctly.
  788. ;    cpi    semico        ; see if its a semicolon
  789. ;    jnz    r1tch2        ; no, ignore it
  790. ;    mvi    a,cr        ; else say its a cr (in case of command lines)
  791. r1tch2:    cpi    cntlz        ; end of file??
  792.     rnz
  793.  
  794.  
  795. c1tchr:    call    closet        ; close file etc, then
  796.     mvi    a,cr        ; fake a carriage return chr 
  797.                 ;       ( => clears kermit comnd line)
  798. c1tch1:    ret        ; and hope that editing etc not required.
  799.  
  800. r1lchr:        ; read a single character from the command line
  801.     lxi    d,cbuff        ; point to buffer
  802.     lda    cbptr        ; get pointer for next character
  803.     mov    l,a
  804.     lda    cbuff        ; get total number of characters there
  805.     cmp    l        ; ... less current character
  806.     jp    r1lch1        ; if positive, we have more characters
  807.     lda    takflg        ; no more, so reset command line bit (bit 4)
  808.     ani    0efh
  809.     sta    takflg
  810.     mvi    a,cntlz        ; fudge an end of file
  811.     push    psw        ; save for common exit (r1tch1)
  812.     jmp    r1tch1
  813. ;
  814. r1lch1:    mov    a,l        ; get count back again
  815.     mvi    h,0
  816.     dad    d        ; get offset to character
  817.     inr    a
  818.     sta    cbptr
  819.     mov    a,m        ; get next character
  820.     cpi    semico        ; if a semicolon, make it a carriage return
  821.     jnz    r1lch2
  822.     mvi    a,cr
  823. r1lch2:    call    p1tchr        ; send a copy to the console
  824.     push    psw        ; save it for r1tch1
  825.     jmp    r1tch1        ; common exit
  826.  
  827.  
  828. ; rnsect - read the next take sector from disk to the take dma address
  829. ; if there is no more then close the file too
  830. rnsect:    push    b
  831.     push    d
  832.     push    h        ; save in case we need these later
  833.     mvi    c,setdma
  834.     lxi    d,takdma    ; set a next read from disk
  835.     call    bdos        ; recursive...
  836.     mvi    c,readf
  837.     lxi    d,takfcb
  838.     call    bdos
  839.     ana    a
  840.     cnz    closet        ; if returned value not zero, assume eof
  841.     lxi    h,0
  842.     shld    takptr        ; pointer restored
  843.     call    rstdma        ; reset the dma address for fussy routines (this one)
  844.     pop    h
  845.     pop    d
  846.     pop    b
  847.     ret
  848.  
  849. ; closet - close the take file and set the take flag to 0 (ie no takes)
  850. ;
  851. closet:    lda    takflg        ; reset the take file bit (bit 0)
  852.     ani    0feh
  853.     sta    takflg        ; close the take file, and restore the flag
  854.     mvi    c,closf
  855.     lxi    d,takfcb
  856.     call    bdos
  857.     call    rstdma        ; in case we did not do it above, reset dma
  858.     ret
  859.  
  860. ;
  861. ; clock - is a 32 bit counter incremented every BDOS call.  It serves as a
  862. ;       timer of sorts and allows a background clock to tick away..
  863. clock:    push    psw        ; we need flags and hl
  864.     push    h
  865.     lhld    clkbit        ; get the counter
  866.     inx    h        ;
  867.     shld    clkbit
  868.     mov    a,h
  869.     ora    l        ; do we need to update the next lot of clock bits?
  870.     jnz    clockx
  871.     lhld    clkbit+2    ; if carry up the top 16 bits
  872.     inx    h
  873.     shld    clkbit+2
  874. clockx:    pop    h
  875.     pop    psw
  876.     ret
  877.  
  878. ;       p1tchr - print a character in accumulator directly to the console
  879. ;       bypassing the bdos trap above.
  880.  
  881. p1tchr:    cpi    lf        ; if a lf ignore it
  882.     jz    p1tchx
  883.     cpi    cr        ; ditto carriage returns
  884.     jz    p1tchx
  885.     cpi    cntlz        ; control z
  886.     jz    p1tchx        ; then dont write it out
  887.     push    psw        ; we do not want to loose it, do we?
  888.     push    b
  889.     push    d
  890.     push    h        ; 'cos you never know what bdos does...
  891.     mov    e,a
  892.     mvi    c,conout    ; direct console io
  893.     call    5        ; absolute address as we skip the trap
  894.     pop    h
  895.     pop    d
  896.     pop    b        ; ... and we need some of these regs.
  897.     pop    psw        ; 
  898. p1tchx:    ret        ; and return
  899.  
  900.  
  901.  
  902. ; outprn - This routine sends charactes to the printer if the latter is ready,
  903. ;       or to a buffer if the printer is not ready.  If the buffer is nearly
  904. ;       full, an XOFF is sent to the host, asking it to be quiet.  The buffer
  905. ;       is emptied by a series of calls in the connect state only.   
  906. ;       If the buffer is made nearly empty, then an XON is sent to the host.
  907. ;
  908. outprn:    mov    a,e        ; get the character to send back to a
  909.     sta    prntmp        ; we need all registers.
  910.     jmp    outprx        ; -testing-testing-testing- avoid buffer
  911. ;
  912. outp0:    call    tstfree        ; see how many spaces free
  913.     cpi    2        ; (free spaces in a on return)
  914.     jp    outp1        ; enough free spaces, so keep going
  915.     call    print        ; else see if we can print summat
  916.     jmp    outp0        ; and try again
  917. ;
  918. outp1:    cpi    4        ; common test - if three or less then send xoff
  919.     cm    sndxoff
  920. outpr2:    mov    a,b        ; inc ptr and check for wrap around
  921.     call    wrapt
  922.     mov    b,a        ; input pointer to b
  923.     sta    prnbuf+1    ; save the new pointer away
  924.     lxi    h,prnbuf+2    ; point to first real data entry in buffer
  925.     call    inchl        ; add offset in a to hl
  926.     lda    prntmp        ; get th character to save away
  927.     mov    m,a        ; save the data away
  928.     ret
  929.  
  930. ; outprx - send character in a to the printer. (We have checked to see if
  931. ;       the printer is ready)
  932. ;       called by outprn, print
  933. outprx:    mov    e,a        ; character has to be in e register
  934.     call    outlpt        ; send it to printer
  935.     ret        ; assume we print it
  936.  
  937. ; TSTFREE - see how many free spacse there are in the buffer
  938. ;        - returns with free space in a, ip pointer in b, op pointer in c
  939. szecyc    equ    127        ; 128 bytes in buffer (less for debugging)
  940. ;
  941. tstfree:
  942.     lda    prnbuf        ; get output pointer
  943.     mov    c,a        ;.. to c
  944.     lda    prnbuf+1    ; and input pointer ...
  945.     mov    b,a        ; ... to b
  946. ;
  947. ;
  948. ; Now comes the tricky bit.  We must establish whether there is less than 
  949. ;   three characters left in the buffer.  There are two conditions to test for
  950. ;   1)  the input pointer is a higher value than the output pointer
  951. ;   2)  the input pointer has been wrapped round and is less than the output pointer
  952. ; ie
  953. ;         |-------|-------|---------------------------------------------|
  954. ; Buffer  |o/p ptr|i/p ptr|  Buffer proper filling --->                 |
  955. ;         |-------|-------|------|-------------|-----------|------------|
  956. ;                              i/p2          o/p         i/p1
  957. ;
  958. ;  If ip = ip1 then if 
  959. ;                       (size of buffer - ip ptr + op ptr) < 3 send xoff
  960. ;  If ip = ip2 then if 
  961. ;                       (op ptr - input ptr ) < 3 send xoff
  962. ;
  963. ; First decide whice one applies
  964.  
  965.     mov    a,b        ; get ip ptr 
  966.     sub    c        ; see if op ptr > ip ptr (case 2)
  967.     jm    outp2        ; yup, so do case two
  968.     mvi    a,szecyc    ; else do buffer - ip + op
  969.     sub    b
  970.     add    c
  971.     jmp    outpx        ; do common test
  972. outp2:    mov    a,c        ; get op pointer
  973.     sub    b        ; less input pointer
  974. outpx:    ret        ; with free space in a
  975. ;
  976. ;
  977. ;
  978. ; print - get a character from the buffer and print it if the printer 
  979. ;       is ready for it.  If the buffer clears more than 3 spare characters
  980. ;       and an xoff has been sent, then send an xon again.
  981. print:    push    h        ; save for rainy days
  982.     push    d
  983.     push    b
  984.     push    psw        ; .. as we may need flags etc....
  985.     lda    initflg        ; First check if the system has initialised
  986.     ana    a
  987.     jz    printx        ; If system not set up then skip
  988. ;       nop
  989. ;       nop
  990. ;       nop                     ; debugging only...
  991.     call    ckprtr        ; check to see if printer is ready...
  992.     ana    a        ; not zero => ok
  993.     jz    printx        ; else skipit.
  994. ;       nop
  995. ;       nop
  996. ;       nop                     ; skip the jump for debugging
  997.     lxi    h,prnbuf
  998.     mov    a,m        ; get input pointer
  999.     inx    h        ; test against output pointer
  1000.     cmp    m        ; if = then buffer empty
  1001.     jz    printx        ; so quit
  1002.     dcx    h        ;pointer to output pointer
  1003.     call    wrapt        ; check for wrap around
  1004.     sta    prnbuf        ; save new pointer
  1005.     inx    h
  1006.     inx    h        ;
  1007.     call    inchl        ; add output pointer to hl
  1008.     mov    c,m        ; get byte
  1009.     lda    hosths        ; have we told host to be quiet?
  1010.     cpi    xoff        ; if = xoff then we have
  1011.     jnz    print1        ; nope, so just print it.. 
  1012.     push    b        ; save the character to print
  1013.     call    tstfree        ; see how many free bytes in buffer
  1014.     pop    b
  1015.     cpi    4        ; 3 characters left?
  1016.     jz    printx
  1017.     push    b
  1018.     call    sndxon        ; send an xon to host and wake it up.
  1019.     pop    b
  1020. print1:    mov    a,c        ; we are gonna print a character, so ...
  1021.     call    outprx        ; get it to a (as required by outprx) and print it
  1022. printx:
  1023.     pop    psw
  1024.     pop    b
  1025.     pop    d
  1026.     pop    h        ; restore regs.
  1027.     ret
  1028.  
  1029. ;
  1030. ; Utilities for the cyclical buffer.  Returns a 0ffh if printer ready, 
  1031. ;       else 0h.  Called by outprn, print
  1032.  
  1033. ckprtr:    
  1034.     call    lptstat        ; no registers saved
  1035. ;       mvi     a,0             ; FOR DEBUGGING PURPOSES
  1036. ;       nop
  1037.     ret
  1038. ;
  1039.  
  1040. inchl:    push    psw        ; we do maths through this register
  1041.     add    l
  1042.     mov    l,a
  1043.     mvi    a,0
  1044.     adc    h
  1045.     mov    h,a
  1046.     pop    psw        ; hl = a + hl
  1047.     ret
  1048.  
  1049. ; wrapt - checks the offset in a with the limits of the buffer.
  1050. ;       returns next address or if wrap around then 0 (start of buffer)
  1051. wrapt:    push    b
  1052.     inr    a
  1053.     mov    b,a        ; save new a into b for now
  1054.     mvi    a,szecyc    ; test for size of buffer
  1055.     sub    b
  1056.     mov    a,b
  1057.     pop    b        ; restore bc regs again
  1058.     rnz
  1059.     xra    a        ; if wrap around, then reset pointer
  1060.     ret        ; return with next address pointer to in a
  1061.  
  1062. ; sndxoff - send an xoff to the host and save the xoff character in hosths
  1063. ;      saves all regs.  is called by logwrt, outprn
  1064. sndxoff:
  1065.     push    psw
  1066.     push    b
  1067.     push    d
  1068.     push    h        ; some calling routines may be sensitive...
  1069.     lda    floctl        ; are we doing flow control?
  1070.     ana    a
  1071.     jz    sndxf        ; no, so dont bother.
  1072.     mvi    a,xoff        ;^S to stop the host while we write the buffer.
  1073.     sta    hosths        ; save it so we know we have sent it
  1074.     call    setpar        ; set correct parity...
  1075.     mov    e,a
  1076.     call    outmdm        ; output it.
  1077.     lxi    d,ofsnt        ; say we have sent an xoff
  1078.     call    prtstr
  1079. sndxf:    pop    h
  1080.     pop    d
  1081.     pop    b
  1082.     pop    psw        ; some routines touchy
  1083.     ret
  1084. ofsnt:    db    cr,lf,'[XOFF sent to host]',cr,lf,'$'
  1085.  
  1086. ; sndxon - send an xon to the host and clear the hosths flag.  saves everything
  1087. ;       called by logwrt, print
  1088. sndxon:    push    psw
  1089.     push    b
  1090.     push    d
  1091.     push    h
  1092.     lda    floctl        ; are we doing flow control?
  1093.     ana    a
  1094.     jz    sndxn
  1095.     xra    a
  1096.     sta    hosths        ; no xoff to hos any more
  1097.     mvi    a,xon        ;^Q to restart the host
  1098.     call    setpar        ; set appropriate parity
  1099.     mov    e,a
  1100.     call    outmdm        ; send it.
  1101.     lxi    d,onsnt
  1102.     call    prtstr        ; say xon sent to host...
  1103. sndxn:    pop    h
  1104.     pop    d
  1105.     pop    b
  1106.     pop    psw
  1107.     ret        ; shame we dont do a pushall/popall subroutine...
  1108. onsnt:    db    cr,lf,'[XON sent to host]',cr,lf,'$'
  1109. ;
  1110. ;       Routines to clear (or rather fill) TEMPnnn space with the data in A
  1111. ;       and to shift it all along one (filltmp an shiftmp respectively)
  1112. filltmp:
  1113.     push    b
  1114.     push    d
  1115.     push    h        ; save all
  1116.     lxi    h,temp1
  1117.     mvi    b,10        ; ten locations to fill
  1118. fillp:    mov    m,a
  1119.     inx    h
  1120.     dcr    b        ; loop til all done
  1121.     jnz    fillp
  1122.     pop    h
  1123.     pop    d
  1124.     pop    b        ; restore all
  1125.     ret
  1126.  
  1127. shiftmp:
  1128.     push    psw        ; save all again
  1129.     push    b
  1130.     push    d
  1131.     push    h
  1132.     lxi    d,temp9
  1133.     lxi    h,temp10
  1134.     mvi    b,9        ; shift nine times
  1135. shiftl:    ldax    d        ; from tempx
  1136.     mov    m,a        ; to tempx+1
  1137.     dcx    d
  1138.     dcx    h        ; mover does not work as that increments
  1139.     dcr    b
  1140.     jnz    shiftl
  1141.     pop    h
  1142.     pop    d
  1143.     pop    b
  1144.     pop    psw
  1145.     ret        ; else all done
  1146.  
  1147. ;       getun - get the user number to temp1 (lsd) and temp2 (msd)
  1148. ;
  1149. getun:    mvi    a,0ffh        ; tell nout to be quiet
  1150.     sta    nquiet
  1151.     mvi    c,usrcod
  1152.     mvi    e,0ffh        ; get current user from bdos
  1153.     call    bdos
  1154.     mov    l,a        ; put into hl
  1155.     mvi    h,0
  1156.     call    nout        ; decimalise it (decimalise???)
  1157.     xra    a
  1158.     sta    nquiet        ; let nout print again
  1159.     ret
  1160.  
  1161. ;    ckcon - Do a direct console IO (read) to see if there is any input
  1162. ;    returns with a=0 (no input) or character (input received)
  1163. ;    Assume that all regs may be destroy.
  1164. ckcon:    mvi    e,0ffh        ; direct console input
  1165.     mvi    c,dconio
  1166.     call    bdos
  1167.     ret        ; and return with wahtever returned in a
  1168.  
  1169.  
  1170.  
  1171. ;
  1172. ; subbc - Subtract the unsigned number in bc from the unsigned number
  1173. ;    in HL with the answer in HL.  Flags altered, all 
  1174. ;    other registers left intact.
  1175. subbc:    sta    temp1        ; hl = hl - bc.. we need the accumulator
  1176.     mov    a,l
  1177.     sub    c
  1178.     mov    l,a
  1179.     mov    a,h
  1180.     sbb    b
  1181.     mov    h,a
  1182.     lda    temp1        ; restore loop counter but not flags
  1183.     ret
  1184.  
  1185. ; P20LN - Routine to print a string at (DE) and count the number of
  1186. ;    line feeds. Pause after 20 lines printed.
  1187. p20ln:    xra    a        ; clear the line counter
  1188.     sta    lincnt
  1189. p20ln1:    ldax    d        ; get character to print
  1190.     inx    d
  1191.     cpi    '$'        ; if a dollar we have done
  1192.     rz
  1193.     push    d
  1194.     push    psw        ; save pointer and character to print
  1195.     mov    e,a
  1196.     call    outcon        ; send character
  1197.     pop    psw
  1198.     pop    d        ; restore pointers etc
  1199.     cpi    lf        ; was that last character a line feed?
  1200.     jnz    p20ln1        ; no, so carry on
  1201.     lda    lincnt        ; yup, so update counter
  1202.     inr    a
  1203.     sta    lincnt
  1204.     cpi    20        ; 20 lines printed?
  1205.     jnz    p20ln1        ; not yet
  1206.     push    d        ; we need DE
  1207. ;    lxi    d,anymes    ; pause a while [MF]removed
  1208. ;    call    prtstr        ; write the message [MF]
  1209. ;p20ln2:    call    ckcon        ; wait for any input [MF]
  1210. ;    ana    a        ;[MF]
  1211. ;    jz    p20ln2        ;[MF]
  1212.     call    pausit        ;[MF] pause a while
  1213.     pop    d
  1214.     jmp    p20ln        ; and continue
  1215.  
  1216.  
  1217. ; Little code to allow some expansion of code without changing
  1218. ;  every futher address, only up to the end of this file.
  1219. ;   TO BE REMOVED FOR RELEASE!
  1220.  
  1221. ;    org ($+100h) AND 0FF00H
  1222.  
  1223. ; link to the data area (was part of CPSUTL.ASM)
  1224.  
  1225. IF lasm
  1226.     LINK    CPSDAT
  1227. ENDIF    ;lasm
  1228.