home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols100 / vol116 / ocap11.asm < prev    next >
Encoding:
Assembly Source File  |  1984-04-29  |  18.1 KB  |  786 lines

  1. ;       I/O-CAP.ASM Version 1.0 as of September 13, 1981
  2. ;                  By: Kelly Smith, CP/M-Net
  3. ;
  4. ; Version 1.0: Initial release by Kelly Smith
  5. ; Version 1.1: modified size for LF
  6. ;               added Apple ][ equates
  7. ; by Bill McGee (613-828-9130)  
  8. ;      Note:  Please  append  any  changes to I/O-CAP  with  a 
  9. ; 'Version  Log' and change comments (your name would be  nice 
  10. ; too) top-down from the initial Version 1.0 release.
  11. ;  
  12. ;      Running  I/O-CAP  (the  first time) will  relocate  the 
  13. ; CONIN,  and CONOUT jump vectors to high memory and then  ALL 
  14. ; subsequent   input  or  output  (depending  on   conditional 
  15. ; assembly  switches)  will  be  buffered  (16  sectors)   for  
  16. ; eventual  output  to  disk with a filename and type   called  
  17. ; USER.LOG.  This file will then be updated as long as I/O-CAP 
  18. ; is   active  in  the system.   Note:   I/O-CAP may  be  made 
  19. ; inactive  by just type I/O-CAP again,  to toggle it off  (or 
  20. ; on).
  21. ;      I/O-CAP   requires   an  unusually  LARGE   amount   of 
  22. ; relocation  memory,  because it must buffer the entire  CP/M 
  23. ; system image to high memory to save and restore all CCP  and 
  24. ; BDOS pointers as it captures each 16 sector block of console 
  25. ; input or output...crude,  but the ONLY other wait to do this 
  26. ; would  be to  'hot-patch' the CCP and BDOS 'on-the-fly'  and 
  27. ; that  get's  just   a   bit  gruesome  from   a    UNIVERSAL   
  28. ; applications  standpoint...It's much easier to just SYSGEN a 
  29. ; smaller   CP/M  system  than your actual  maximum  available 
  30. ; memory,   and  then have I/O-CAP relocate itself above  your 
  31. ; BIOS.  If  anyone has a better way to do this  WITHOUT  this 
  32. ; relocation  crap,  I  would be eager to see it...I just  got 
  33. ; frustrated  with  trying to figure out what CP/M  was  doing 
  34. ; internally  to pursue it further...local  stacks,  pointers, 
  35. ; etc.,...ARGH...so I took the easy way out.
  36. ;      Thanks  to  Mike Karas for discovering  the  BDOS  CALL 
  37. ; contention  problems  when the BDOS stack was not saved  and 
  38. ; restored when saving the console buffer to disk.
  39. ;                       - Applications -
  40. ; (1)   Don't have a printer,  and want 'Hard Copy' of a  user 
  41. ; dialog  with the system?  Use I/O-CAP to creat it as a  disk 
  42. ; file...for  instance,  when making patches into  'uncertain' 
  43. ; areas of the system with DDT (or SID,  or whatever) you  can 
  44. ; keep  a  running  history on disk of the patches  AND  their 
  45. ; effects.
  46. ; (2)   Need to show example of console dialog for an  article 
  47. ; or book and you don't want to 'hand type' it in? Use I/O-CAP 
  48. ; to creat the examples for you,  and edit the dialog to  suit 
  49. ; your needs.
  50. ; (3)   Need to know all the events in 'history form'  leading 
  51. ; to  some bizarre system blow-up?  Use I/O-CAP to record that 
  52. ; history  for you (but only if the blow-up is recoverable  by 
  53. ; NOT COLD BOOTING the system).
  54. ; (4)   Want  to  (secretly) monitor the activities  of  other 
  55. ; users  of  the system?  Use I/O-CAP to record  user  console 
  56. ; input,  and check in from time-to-time to look at the system 
  57. ; activity.  Used  in  conjunction with BYE on a  remote  CP/M 
  58. ; system,  you can finally figure-out how that 'twit' clobbers 
  59. ; your  system from 3000 miles away...and NOT fill a room full 
  60. ; of  paper by logging all input to your  printer.  Note:  Run 
  61. ; I/O-CAP first,  then BYE.COM to 'grab' the vectors set-up by 
  62. ; the I/O-CAP program.The capture of incoming data will appear 
  63. ; to be transparent to the user,  with a slight pause when  it 
  64. ; updates the USER.LOG file...but this only happens every 2048 
  65. ; character entrys, so it should generally go un-noticed.
  66. ;                      - Using I/O-CAP -
  67. ;      Examine  the various conditional assembly switches  and 
  68. ; set  TRUE or FALSE depending on your requirements with  your 
  69. ; editor  (ED.COM).  Then assemble with ASM.COM (or  MAC.COM), 
  70. ; load it to creat a .COM file and then run.  The  conditional 
  71. ; assembly switches allow the following options:
  72. ; (1)   DEBUG  -  I/O-CAP runs at 8000 Hex...about  right  for 
  73. ; most small applications programs that use memory from 100 to 
  74. ; 7FFF Hex in a 56K CP/M system.  If FALSE, I/O-CAP runs above 
  75. ; a  48K  CP/M  system (C800 Hex),  with  no  restrictions  on 
  76. ; applications programs.
  77. ; (2)  QUIET - If FALSE, rings the console bell just before it 
  78. ; writes 2048 bytes of captured console INPUT or OUTPUT.
  79. ; (3)   ERRDISP - If TRUE,  I/O-CAP will display an  'OOPS...' 
  80. ; message on the console if the disk or directory is full.
  81. ; (4)   INPUT  - If  TRUE,  only  console  keyboard  INPUT  is 
  82. ; captured. Note: OUTPUT must be FALSE if INPUT is TRUE.
  83. ; (5)   OUTPUT  - If  TRUE,  both console keyboard  INPUT  and 
  84. ; OUTPUT will be captured...uses 'gobs' of disk storage if you 
  85. ; let I/O-CAP run for any length of time.  Note: INPUT must be 
  86. ; FALSE if OUTPUT is TRUE.
  87. ; (6) QUIT - If TRUE, when a Control-Z and Carriage Return are 
  88. ; entered  at  the console keyboard,  I/O-CAP will append  the 
  89. ; USER.LOG file with a physical end-of-file (i.e.,  no further 
  90. ; data  will  be  displayed in USER.LOG  although  it  may  be 
  91. ; physically appended to it)...Note: You must type I/O-CAP<cr> 
  92. ; to CLOSE the current USER.LOG,  and reset the disk to normal 
  93. ; R/W  status.  Failure  to  do so will result in a  R/O  BDOS 
  94. ; Error  on  any subsequent attempt to write to  the  disk  by 
  95. ; means other than I/O-CAP.
  96. ; (7) SYSLOG - If TRUE,  creates USER.LOG as a $SYS (invisible 
  97. ; to  directory)  file,  so that 'secrecy' is maintained  when 
  98. ; capturing  user input...be sure and rename USER.LOG to  your 
  99. ; 'private' name, or replace the TYPE command with MLIST.COM.
  100. ;      Please  send any changes,  'bug' reports,  suggestions, 
  101. ; comments,  gripes or bitches to the CP/M-Net  system,  (805) 
  102. ; 527-9321...have  fun with this program.  It's in the  public 
  103. ; domain, but NOT TO BE USED for COMMERCIAL BENEFIT.
  104. ;                                    Best regards,
  105. ;                                    Kelly Smith, CP/M-Net
  106. ;
  107. ;
  108. ; define TRUE/FALSE assembly parameters
  109. ;
  110. true    equ    -1    ; define TRUE
  111. false    equ    not true; define FALSE
  112. debug    equ    true    ; define DEBUG
  113. quiet    equ    false    ; define QUIET (ring BELL, if not true)
  114. errdisp    equ    true    ; define ERRDISP (display errors, if true)
  115. quit    equ    true    ; define QUIT (EOF, if Control-Z found)
  116. syslog    equ    false    ; define SYSLOG (make USER.LOG a $SYS file)
  117. APPLE    equ    true    ; for Apple ][ with 56K Softcard CP/M
  118. ; >>> Note: only one of the following two assembly switches may be true <<<
  119. ;
  120. input    equ    true    ; define INPUT (I/O-CAP console input)
  121. output    equ    false    ; define OUTPUT (I/O-CAP console output)
  122. ;
  123.     if    DEBUG
  124. dest    equ    08000h    ; running location of code
  125.     endif        ; DEBUG
  126.  
  127.     if    not DEBUG
  128. dest    equ    0c800h    ; running location of code
  129.     endif        ; DEBUG
  130. ;
  131. ; BDOS entry point and function codes
  132. base    equ    0    ; <<-- set to offset of CP/M for your
  133.             ; system, standard systems are 0, some
  134.             ; 'alternate' systems are 4200H
  135. bdos    equ    base+5
  136. resdsk    equ    13    ; reset disk system
  137. offc    equ    15    ; open file
  138. cffc    equ    16    ; close file
  139. dffc    equ    19    ; delete file
  140. rrfc    equ    20    ; read record
  141. wrfc    equ    21    ; write record
  142. mffc    equ    22    ; make file
  143. sdma    equ    26    ; set dma address
  144. ; secondary FCB field definitions
  145. fn    equ    1    ; file name field (rel)
  146. ft    equ    9    ; file type field (rel)
  147. ex    equ    12    ; file extent field (rel)
  148. frc    equ    15    ; file record count (rel)
  149. nr    equ    32    ; next record field (rel)
  150. ; ASCII control characters
  151. cr    equ    0dh    ; carriage return
  152. lf    equ    0ah    ; line feed
  153. bel    equ    07h    ; bell signal
  154. ;
  155. ; This  program runs up in high ram.  It gets there,  by being 
  156. ; moved  there  when 'I/O-CAP'  is typed. Change the following 
  157. ; equate to an area in your high memory where this program may 
  158. ; patch itself in.  Approximate memory requirements:  2k bytes 
  159. ; or more,  depending upon the options selected.  a marker has 
  160. ; been  placed  at  the  end to deliberately  print  an  error 
  161. ; message  during  assembly in order to determine  the  actual 
  162. ; ending  address of the program.  The error message will  not 
  163. ; affect the assembly.  make sure you have memory available up 
  164. ; to the address shown.
  165. ;
  166.     org    base+100h
  167. ;
  168. ; Move 'I/O-CAP' program up to high ram and jump to it
  169. ;
  170.     lxi    h,0    ; save old stack pointer
  171.     dad    sp
  172.     shld    oldstk
  173.     lxi    sp,stack; make a new stack pointer
  174.     lxi    h,tbuf    ; set pointer to tbuf
  175.     shld    ptr
  176.     lxi    h,0    ; set size = 0
  177.     shld    size
  178.     lhld    base+1    ; get BIOS pointer
  179.     lxi    d,5    ; add bias to console status address
  180.     dad    d
  181.     mov    d,m    ; save in [d]
  182.     lhld    newjtbl+1    ; see if vector addresses active
  183.     mov    a,h    ; been patched by previous execution?
  184.     cmp    d
  185.     jz    unpatch    ; un-patch, if so
  186.     lxi    b,pend-start+1        ; number of bytes to move
  187.     lxi    h,dest+pend-start+1    ; end of moved code
  188.     lxi    d,source+pend-start    ; end of source code
  189. ;
  190. mvlp    ldax    d    ; get byte
  191.     dcx    h    ; bump pointers
  192.     mov    m,a    ; new home
  193.     dcx    d
  194.     dcx    b    ; bump byte count
  195.     mov    a,b    ; check if zero
  196.     ora    c
  197.     jnz    mvlp    ; if not, do some more
  198.     pchl        ; do it, to it...
  199. ;
  200. source    equ    $    ; boundary memory marker
  201. ;
  202. offset    equ    dest-source ; relocation amount
  203. ;
  204. ; The following code gets moved to high ram located at "dest", 
  205. ; where it is executed. C A U T I O N :  if modifying anything 
  206. ; in this program from here on: ALL labels must be of the form:
  207. ;
  208. ; label    equ    $+offset        
  209. ;
  210. ; ...in   order   that  the  relocation  to  high   ram   work 
  211. ; successfully.   Forgetting  to specify '$+offset' will cause 
  212. ; the program to jmp into whatever is currently in low memory, 
  213. ; with unpredictable results.  Be careful....        
  214. ;
  215. start    equ    $+offset
  216. ;
  217. ; patch in the new jump table (saving the old)
  218. ;
  219. patch    equ    $+offset
  220.     call    tbladdr        ; calc [hl] =  CP/M jmp table
  221.     lxi    d,vcstat    ; point to save location
  222.     call    move        ; move it
  223. ;
  224. ; now move new jump table to CP/M
  225. ;
  226.     call    tbladdr        ; calc [hl] = CP/M's jmp table
  227.     xchg            ; move to de
  228.     lxi    h,newjtbl    ; point to new
  229.     call    move        ; move it
  230.     lxi    h,active$message
  231.     call    msgout
  232.     lhld    oldstk        ; get old CP/M stack pointer
  233.     sphl
  234.     ret
  235. ;
  236. unpatch equ    $+offset
  237.     call    reset    ; reset disk in case it's R/O
  238.     lxi    h,inactive$message
  239.     call    msgout
  240.     call    tbladdr        ; [hl] = CP/M's jmp table
  241.     xchg            ; move to de
  242.     lxi    h,vcstat    ; get saved table
  243.     call    move        ; move orig back
  244.     lhld    oldstk        ; get old CP/M stack pointer
  245.     sphl
  246.     ret            
  247. ;
  248. ; calculate [hl] = CP/M's jump table, [b] = length
  249. ;
  250. tbladdr equ    $+offset
  251.     lhld    base+1        ; get BIOS pointer
  252.     inx    h        ; ..skip
  253.     inx    h        ; ..to
  254.     inx    h        ; ..console status
  255.     mvi    b,9        ; move console jump vectors
  256.     ret
  257. ;
  258. ; move [hl] to [de], length in [b]
  259. ;
  260. move    equ    $+offset
  261.     mov    a,m        ; get a byte
  262.     stax    d        ; put at new home
  263.     inx    d        ; bump pointers
  264.     inx    h
  265.     dcr    b        ; decrement byte count
  266.     jnz    move        ; if more, do it
  267.     ret            ; if not, return
  268. ;
  269. ; move [hl] to [de], length in [bc]
  270. ;
  271. movecpm    equ    $+offset
  272.     mov    a,m        ; get a byte
  273.     stax    d        ; put at new home
  274.     inx    d        ; bump pointers
  275.     inx    h
  276.     dcx    b        ; decrement byte count
  277.     mov    a,b
  278.     ora    c
  279.     jnz    movecpm        ; if more, do it
  280.     ret            ; if not, return
  281. ;
  282. msgout    equ    $+offset
  283.     mov    a,m        ; get character from message string
  284.     ora    a        ; all of string displayed?
  285.     rz            ; return, if so
  286.     inx    h        ; no, bump pointer for next character
  287.     mov    c,a        ; pass character to 'old' BIOS vector
  288.     call    conout
  289.     jmp    msgout        ; display next character in message string
  290. ;
  291. ; This area is used for vectoring calls to the user's CBIOS, 
  292. ; but saving the registers first in case they are destroyed.
  293. ;
  294. constat equ    $+offset
  295.     push    b
  296.     push    d
  297.     push    h
  298.     call    vcstat
  299.     pop    h
  300.     pop    d
  301.     pop    b
  302.     ret
  303. ;
  304. conin    equ    $+offset
  305.     push    b
  306.     push    d
  307.     push    h
  308.     call    vcin
  309.     pop    h
  310.     pop    d
  311.     pop    b
  312.     ret
  313. ;
  314. conout    equ    $+offset
  315.     push    b
  316.     push    d
  317.     push    h
  318.     call    vcout
  319.     pop    h
  320.     pop    d
  321.     pop    b
  322.     ret
  323. ;
  324. ; This  is  the jump table which is copied on top of  the  one 
  325. ; pointed to by location 1 in CP/M
  326. ;
  327. newjtbl equ    $+offset
  328.     jmp    constat    ; console status test
  329.  
  330.     if    INPUT
  331.     jmp    capture    ; console input I/O-CAP routine
  332.     endif        ; INPUT
  333.  
  334.     if    OUTPUT
  335.     jmp    conin    ; console input routine
  336.     endif        ; OUTPUT
  337.  
  338.     if    INPUT
  339.     jmp    conout    ; console output routine
  340.     endif        ; INPUT
  341.  
  342.     if    OUTPUT
  343.     jmp    capture    ; console I/O-CAP output routine
  344.     endif        ; OUTPUT
  345.  
  346. ;
  347. capture    equ    $+offset
  348.     push    h
  349.     push    d
  350.     push    b
  351.     lxi    h,0    ; save old stack pointer
  352.     dad    sp
  353.     shld    oldstk
  354.     lxi    sp,stack; make a new stack pointer
  355.  
  356.     if    INPUT
  357.     call    vcin    ; get console input
  358.     mov    c,a    ; save in [c] for 'save'
  359.     push    psw    ; and save on the stack
  360.     endif        ; INPUT
  361.  
  362.     call    save    ; save characters in buffer
  363.  
  364.     if    INPUT
  365.     pop    psw    ; get console input of the stack
  366.     endif        ; INPUT
  367.  
  368.     lhld    oldstk    ; get old CP/M stack pointer
  369.     sphl
  370.     pop    b
  371.     pop    d
  372.     pop    h
  373.  
  374.     if    OUTPUT
  375.     jmp    vcout
  376.     endif        ; OUTPUT
  377.  
  378.     if    INPUT
  379.     ret
  380.     endif        ; INPUT
  381.  
  382. save:    equ    $+offset
  383.     lhld    size    ; size = size + 1
  384.     inx    h
  385.     shld    size
  386.     lhld    ptr
  387.     mov    m,c
  388.     inx    h
  389.  
  390.     if    INPUT
  391.     mov    a,c
  392.     cpi    cr    ; carriage return?
  393.     jnz    notcr
  394.     mvi    m,lf    ; yes, so add line feed because CP/M does not
  395.     inx    h    ; bump pointer, for next time thru
  396.     shld    ptr    ; added for 1.1 to
  397.     lhld    size    ;        /
  398.     inx    h    ;       /
  399.     shld    size    ;      /
  400.     lhld    ptr    ; here
  401.     endif        ; INPUT
  402.  
  403. notcr    equ    $+offset; make label for next instruction...
  404.  
  405.     if    QUIT
  406.     mov    a,c
  407.     cpi    'Z'-40h    ; control-Z?
  408.     jz    wtb    ; write buffer, if so
  409.     endif        ; QUIT
  410.  
  411.     shld    ptr
  412.     lxi    d,endmark    ; get 'endmark' for buffer top address
  413.     mov    a,d
  414.     cmp    h    ; getting near the end of buffer yet?
  415.     rnz        ; if not, just return
  416.     mov    a,e    ; very near the top now, final address loaded?
  417.     cmp    l
  418.     rnz        ; if not, just return
  419.  
  420.     if    not QUIET
  421.     mvi    c,bel    ; warn user that we need to write to disk
  422.     call    conout
  423.     endif        ; QUIET
  424.  
  425. ; wtb - write text buffer to disk
  426. wtb:    equ    $+offset
  427.     IF NOT APPLE
  428.     lhld    base+6    ; get warm boot address for next bias to CCP
  429.     lxi    d,0fffah; make bias to CCP
  430.     dad    d    ; add bias to [hl]
  431.     lxi    b,1600h    ; make quantity to move
  432.     lxi    d,cpmbuf; buffer all of CP/M system
  433.     call    movecpm    ; move it...
  434.     ENDIF
  435.     IF APPLE
  436.     lxi    h,0CC00h
  437.     lxi    b,1400h
  438.     lxi    d,cpmbuf
  439.     call    movecpm
  440.     lxi    h,0F000h
  441.     lxi    b,1000h
  442.     lxi    d,cpmbuf1
  443.     call    movecpm
  444.     ENDIF    ; APPLE
  445.     call    reset    ; reset disk in case it's R/O
  446.     call    open    ; attempt to open USER.LOG
  447.     inr    a    ; check CP/M return code
  448.     jnz    makeok    ; USER.LOG already exist?
  449. ;
  450. nolog:    equ    $+offset
  451. ;
  452.     call    make    ; make new file
  453.     inr    a    ; check CP/M return code
  454.     jnz    makeok
  455.  
  456.     if    ERRDISP
  457.     lxi    h,dirful; oops...can't make file, return to CP/M
  458.     call    msgout
  459.     endif        ; ERRDISP
  460.  
  461.     jmp    base
  462. ;
  463. ; USER.LOG exists, so set the FCB entry for next append to file
  464. ;
  465. makeok:    equ    $+offset
  466. ;
  467.     lda    fcb+frc    ; get record count
  468.     sta    fcb+nr    ; make next record
  469.     lhld    size    ; [de] = tbuf size
  470.     xchg
  471.     lxi    h,dbuf    ; top of stack points to dbuf
  472.     push    h
  473.     lxi    h,tbuf    ; [hl] points to tbuf
  474. wtb1:    equ    $+offset
  475.     mvi    c,128    ; disk buffer size
  476. wtb2:    equ    $+offset
  477.     mov    a,m    ; fetch next byte of tbuf
  478.     inx    h
  479.     xthl
  480.     mov    m,a    ; store in dbuf
  481.     inx    h
  482.     xthl
  483.     dcx    d    ; size = size - 1
  484.     mov    a,d    ; exit loop if size = 0
  485.     ora    e
  486.     jz    wtb3
  487.     dcr    c    ; loop until dbuf full
  488.     jnz    wtb2
  489.     call    setdma    ; set dma to dbuf
  490.     call    write    ; write full dbuf to disk
  491.     push    psw    ; save possible error code
  492.     lda    fcb+frc    ; get record count
  493.     sta    fcb+nr    ; make next record
  494.     pop    psw    ; get possible error code
  495.     ora    a    ; check CP/M return code
  496.     jz    nextbuf
  497.  
  498.     if    ERRDISP
  499.     lxi    h,dskful; oops...disk is full
  500.     call    msgout
  501.     endif        ; ERRDISP
  502.  
  503.     jmp    base
  504. ;
  505. nextbuf    equ    $+offset
  506. ;
  507.     xthl        ; top of stack points to dbuf
  508.     lxi    h,dbuf
  509.     xthl
  510.     jmp    wtb1    ; loop until end of tbuf
  511. wtb3:    equ    $+offset
  512.     pop    h    ; [hl] points to current place in dbuf
  513. wtb4:    equ    $+offset
  514.     mvi    m,'Z'-40h ; store eof code
  515.     inx    h
  516.     dcr    c    ; loop thru rest if dbuf
  517.     jnz    wtb4
  518.     call    setdma    ; set dma to dbuf
  519.     call    write    ; write last sector to disk
  520.     push    psw    ; save possible error code
  521.     lda    fcb+frc    ; get record count
  522.     sta    fcb+nr    ; make next record
  523.     pop    psw    ; get possible error code
  524.     ora    a    ; check CP/M return code
  525.     jz    closeup
  526.  
  527.     if    ERRDISP
  528.     lxi    h,dskful; oops...disk is full
  529.     call    msgout
  530.     endif        ; ERRDISP
  531.  
  532.     jmp    base
  533. ;
  534. closeup    equ    $+offset
  535. ;
  536.     call    close    ; clean up act and go home
  537.     lxi    h,tbuf    ; clear text buffer
  538.     shld    ptr
  539.     lxi    h,0
  540.     shld    size
  541. wtb5:    equ    $+offset
  542.     IF NOT APPLE
  543.     lhld    base+6    ; get warm boot address for next bias to CCP
  544.     lxi    d,0fffah; make bias to CCP
  545.     dad    d    ; add bias to [hl]
  546.     lxi    b,1600h    ; make quantity to move
  547.     lxi    d,cpmbuf; buffer all of CP/M system
  548.     xchg        ; swap
  549.     call    movecpm    ; move it...
  550.     ENDIF
  551.     IF APPLE
  552.     lxi    h,0CC00h
  553.     lxi    b,1400h
  554.     lxi    d,cpmbuf
  555.     xchg
  556.     call    movecpm
  557.     lxi    h,0F000h
  558.     lxi    b,1000h
  559.     lxi    d,cpmbuf1
  560.     xchg
  561.     call    movecpm
  562.     ENDIF    ; APPLE
  563.     ret
  564. ;  reset - reset disk
  565. ;
  566. reset:    equ    $+offset
  567.     push    h
  568.     push    d
  569.     push    b
  570.     mvi    c,resdsk
  571.     call    bdos
  572.     pop    b
  573.     pop    d
  574.     pop    h
  575.     ret
  576. ; open - open disk file
  577. open:    equ    $+offset
  578.     push    h
  579.     push    d
  580.     push    b
  581.     lxi    d,fcb
  582.     mvi    c,offc
  583.     call    bdos
  584.     pop    b
  585.     pop    d
  586.     pop    h
  587.     ret
  588. ; read - read record from disk file
  589. read:    equ    $+offset
  590.     push    h
  591.     push    d
  592.     push    b
  593.     lxi    d,fcb
  594.     mvi    c,rrfc
  595.     call    bdos
  596.     pop    b
  597.     pop    d
  598.     pop    h
  599.     ret
  600. ; close - close disk file
  601. close:    equ    $+offset
  602.     push    h
  603.     push    d
  604.     push    b
  605.     lxi    d,fcb
  606.     mvi    c,cffc
  607.     call    bdos
  608.     pop    b
  609.     pop    d
  610.     pop    h
  611.     ret
  612. ; delt - delete disk file
  613. delt:    equ    $+offset
  614.     push    h
  615.     push    d
  616.     push    b
  617.     lxi    d,fcb
  618.     mvi    c,dffc
  619.     call    bdos
  620.     pop    b
  621.     pop    d
  622.     pop    h
  623.     ret
  624. ; write - write record to disk
  625. write:    equ    $+offset
  626.     push    h
  627.     push    d
  628.     push    b
  629.     lxi    d,fcb
  630.     mvi    c,wrfc
  631.     call    bdos
  632.     pop    b
  633.     pop    d
  634.     pop    h
  635.     ret
  636. ; make - make new disk file
  637. make:    equ    $+offset
  638.     push    h
  639.     push    d
  640.     push    b
  641.     lxi    d,fcb
  642.     mvi    c,mffc
  643.     call    bdos
  644.     pop    b
  645.     pop    d
  646.     pop    h
  647.     ret
  648. ; setdma - set dma address for disk file
  649. setdma:    equ    $+offset
  650.     push    h
  651.     push    d
  652.     push    b
  653.     lxi    d,dbuf
  654.     mvi    c,sdma
  655.     call    bdos
  656.     pop    b
  657.     pop    d
  658.     pop    h
  659.     ret
  660. ;
  661.  
  662.     if    ERRDISP
  663. dskful:    equ    $+offset
  664.     db    cr,lf,bel,'OOPS...disk is full!',0
  665. ;
  666. dirful:    equ    $+offset
  667.     db    cr,lf,bel,'OOPS...directory is full!',0
  668.     endif        ; ERRDISP
  669.  
  670. ;
  671. active$message    equ    $+offset
  672.     db    '  (Active)',0
  673. ;
  674. inactive$message    equ    $+offset
  675.     db    '  (Inactive)',0
  676. ;
  677. fcb    equ    $+offset
  678.     db    0    ; default drive specifier
  679.  
  680.     if    SYSLOG
  681.     db    'USER    L','O'+80h,'G'
  682.     endif        ; SYSLOG
  683.  
  684.     if    not SYSLOG
  685.     db    'USER    LOG'
  686.     endif        ; SYSLOG
  687.  
  688.     db    0,0,0,0,0,0,0,0,0,0
  689. ;
  690. pend    equ    $+offset; end of relocated code
  691. ;
  692. ; data area
  693.     ds    128    ; 64 level stack
  694. stack    equ    $+offset;local stack
  695. ;
  696. ptr:    equ    $+offset
  697.     ds    2    ; text buffer pointer
  698. ;
  699. size:    equ    $+offset
  700.     ds    2    ; text buffer size
  701. ;
  702. ; Save the CP/M jump table here
  703. ;
  704. vcstat    equ    $+offset
  705.     ds    3
  706. ;
  707. vcin    equ    $+offset
  708.     ds    3
  709. ;
  710. vcout    equ    $+offset
  711.     ds    3
  712. ;
  713. oldstk    equ    $+offset
  714.     ds    2    ; storage for old CP/M stack pointer
  715. ;
  716.     IF NOT APPLE
  717.     cpmbuf    equ    $+offset
  718.     ds    1600h    ; storage CP/M system image
  719.     ENDIF
  720.     IF APPLE
  721.     cpmbuf    equ    $+offset
  722.     ds    1400h
  723.     cpmbuf1    equ    $+offset
  724.     ds    1000h
  725.     ENDIF    ;APPLE
  726. ;
  727. dbuf    equ    $+offset
  728.     ds    128    ; secondary disk buffer address
  729. ;
  730. tbuf:    equ    $+offset
  731.     ds    16*128    ; I/O-CAP storage for 16 sectors (2048 bytes)
  732. ;
  733. endmark    equ    $+offset;! ignore error - this marks end of program
  734. ;
  735.     end
  736.