home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / MACLIB / SEQIO22.LIB < prev    next >
Text File  |  2000-06-30  |  18KB  |  725 lines

  1. ;    SEQUENTIAL FILE I/O LIBRARY
  2.  
  3. ;    VRS 2.2    Jack Riley, Boulder Colorado(RCPM phone: (303)499-9169)
  4. ;
  5. ;    This is a highly modified version of the original by unknown author
  6. ;    believed to be Ward Christensen.
  7. ;    It has been expanded to include the following new features:
  8. ;    1) An APPEND mode to the FILE macro to allow the opening of files
  9. ;       with automatic positioning to the EOF. Both GET and PUT macros
  10. ;       are expanded to allow full random access to the file. Random
  11. ;       access reads and writes are used instead of sequential(and also
  12. ;       in other modes of use of the FILE macro so 1.4 is now incompatible).
  13. ;    2) PUBLIC and NONLOC options have been added to the FILE macro
  14. ;       to allow access to files not in the current user area or on the
  15. ;       current disk drive. The GET and PUT macros also handle the switching
  16. ;       needed to provide for multiple opens in multiple areas. The way
  17. ;       they work is to momentarily switch the user area to the one needed
  18. ;       for the file undergoing an IO operation. A return is made to the
  19. ;       'home' user area to allow for 'local' file accesses or switches
  20. ;       to other areas to access other files. This is not completely
  21. ;       satisfactory and one could wish for a more elegant method which
  22. ;       should have been available under CPM. Also an additional byte
  23. ;       has been added to the FCB generated by FILLFCB to contain the
  24. ;       user area. The NONLOC option prevents an otherwise automatic
  25. ;       sequence to look first in the current user area and on the current
  26. ;       disk for the file, then switch the user area, then the disk to
  27. ;       the default locations. When PUBLIC is included in an invocation 
  28. ;       of FILE, then code accessing default and current values is made.
  29. ;       The allocations for these variables is shown below.
  30. ;        DEFAULT$USER:
  31. ;            DB    0    ; or other user area
  32. ;        DEFAULT$DISK:
  33. ;            DB    'x'-'A'    ; where x is the default
  34. ;        CUR$USER:
  35. ;            DB    0FFH    ; necessary initial value
  36. ;        CUR$DISK:
  37. ;            DB    0FFH    ;  "           "
  38. ;
  39. ;       The intention was to allow the default values to be modified
  40. ;       at run time(one of the failings of MACRO-economics) so that
  41. ;       determinations of the availability of hard disks, for example,
  42. ;       could be included. Also it is sometimes nice to have these
  43. ;       values at the very beginning of a program so that DDT-style
  44. ;       customizations can be made.
  45. ;    3) A SECTBUF parameter has been added to FILE to turn off the
  46. ;       standard character buffering previously provided. It seemed
  47. ;       reasonable to provide this new open machinery even when
  48. ;       simple sector buffering was intended. Also when SECTBUF=NONE
  49. ;       all buffering is turned off and only the new open code is
  50. ;       produced. This can also be done through use of the POPEN macro
  51. ;       directly(without FCB's being generated).
  52.  
  53. FILERR    SET    0000H    ;REBOOT AFTER ERROR
  54. @FALSE    SET    0000H
  55. @TRUE    SET    NOT @FALSE
  56. @BDOS    EQU    0005H    ;BDOS ENTRY POINT
  57. @TFCB    EQU    005CH    ;DEFAULT FILE CONTROL BLOCK
  58. @TBUF    EQU    0080H    ;DEFAULT BUFFER ADDRESS
  59. ;
  60. ;    BDOS FUNCTIONS
  61. @MSG    EQU    9    ;SEND MESSAGE
  62. @OPN    EQU    15    ;FILE OPEN
  63. @CLS    EQU    16    ;FILE CLOSE
  64. @DIR    EQU    17    ;DIRECTORY SEARCH
  65. @DEL    EQU    19    ;FILE DELETE
  66. @MAK    EQU    22    ;FILE MAKE
  67. @REN    EQU    23    ;FILE RENAME
  68. @DMA    EQU    26    ;SET DMA ADDRESS
  69. @FRD    EQU    33    ;FILE RANDOM READ OPERATION
  70. @FWR    EQU    34    ;FILE RANDOM WRITE OPERATION
  71. @CFS    EQU    35    ;COMPUTE FILE SIZE
  72. @SETRR    EQU    36    ;SET RANDOM RECORD
  73. ;
  74. @SECT    EQU    128    ;SECTOR SIZE
  75. EOF    EQU    1AH    ;END OF FILE
  76. @CR    EQU    0DH    ;CARRIAGE RETURN
  77. @LF    EQU    0AH    ;LINE FEED
  78. TAB    EQU    09H    ;HORIZONTAL TAB
  79. ;
  80. @KEY    EQU    1    ;KEYBOARD
  81. @CON    EQU    2    ;CONSOLE DISPLAY
  82. @RDR    EQU    3    ;READER
  83. @PUN    EQU    4    ;PUNCH
  84. @LST    EQU    5    ;LIST DEVICE
  85. ;
  86. ;    KEYWORDS FOR "FILE" MACRO
  87. NONE    EQU    1
  88. SECTBUFF    EQU    @TRUE
  89. NONLOC    EQU    @TRUE
  90. INFILE    EQU    1    ;INPUT FILE
  91. OUTFILE    EQU    2    ;OUTPUTFILE
  92. SETFILE    EQU    3    ;SETUP NAME ONLY
  93. APPEND    EQU    4    ;APPEND TO FILE
  94. ;
  95. ;    THE FOLLOWING MACROS DEFINE SIMPLE SEQUENTIAL
  96. ;    FILE OPERATIONS:
  97. ;
  98. FILLNAM    MACRO    FC,C
  99. ;;    FILL THE FILE NAME/TYPE GIVEN BY FC FOR C CHARACTERS
  100. @CNT    SET    C    ;;MAX LENGTH
  101.     IRPC    ?FC,FC    ;;FILL EACH CHARACTER
  102. ;;    MAY BE END OF COUNT OR NUL NAME
  103.     IF    @CNT=0 OR NUL ?FC
  104.     EXITM
  105.     ENDIF
  106.     DB    '&?FC'    ;;FILL ONE MORE
  107. @CNT    SET    @CNT-1    ;;DECREMENT MAX LENGTH
  108.     ENDM        ;;OF IRPC ?FC
  109. ;;
  110. ;;    PAD REMAINDER
  111.     REPT    @CNT    ;;@CNT IS REMAINDER
  112.     DB    ' '    ;;PAD ONE MORE BLANK
  113.     ENDM        ;;OF REPT
  114.     ENDM
  115. ;
  116. FILLDEF    MACRO    FCB,?FL,?LN
  117. ;;    FILL THE FILE NAME FROM THE DEFAULT FCB
  118. ;;    FOR LENGTH ?LN (9 OR 12)
  119.     LOCAL    PSUB
  120.     JMP    PSUB    ;;JUMP PAST THE SUBROUTINE
  121. @DEF:    ;;THIS SUBROUTINE FILLS FROM THE TFCB (+16)
  122.     MOV    A,M    ;;GET NEXT CHARACTER TO A
  123.     STAX    D    ;;STORE TO FCB AREA
  124.     INX    H
  125.     INX    D
  126.     DCR    C    ;;COUNT LENGTH DOWN TO 0
  127.     JNZ    @DEF
  128.     RET
  129. ;;    END OF FILL SUBROUTINE
  130. PSUB    EQU $
  131. FILLDEF    MACRO    ?FCB,?F,?L
  132.     LXI    H,@TFCB+?F    ;;EITHER @TFCB OR @TFCB+16
  133.     LXI    D,?FCB
  134.     MVI    C,?L        ;;LENGTH = 9,12
  135.     CALL    @DEF
  136.     ENDM
  137.     FILLDEF    FCB,?FL,?LN
  138.     ENDM
  139. ;
  140. FILLNXT    MACRO
  141. ;;    INITIALIZE BUFFER AND DEVICE NUMBERS
  142. @NXTB    SET    0    ;;NEXT BUFFER LOCATION
  143. @NXTD    SET    @LST+1    ;;NEXT DEVICE NUMBER
  144. FILLNXT    MACRO
  145.     ENDM
  146.     ENDM
  147. ;
  148. FILLFCB    MACRO    MD,FID,DN,FN,FT,BS,BA
  149. ;;    FILL THE FILE CONTROL BLOCK WITH DISK NAME
  150. ;;    DEFINE FILE USING MODE MD:
  151. ;;        INFILE = 1    INPUT FILE
  152. ;;        OUTFILE = 2    OUTPUT FILE
  153. ;;        SETFILE = 3    SETUP FCB
  154. ;;    FID IS AN INTERNAL NAME FOR THE FILE,
  155. ;;    DN IS THE DRIVE NAME (A,B..), OR BLANK
  156. ;;    FN IS THE FILE NAME, OR BLANK
  157. ;;    FT IS THE FILE TYPE 
  158. ;;    BS IS THE BUFFER SIZE
  159. ;;    BA IS THE BUFFER ADDRESS
  160.     LOCAL    PFCB
  161. ;;
  162. FID&TYP    SET    MD    ;;SET MODE FOR LATER REF'S
  163. ;;    SET UP THE FILE CONTROL BLOCK FOR THE FILE
  164. ;;    LOOK FOR FILE NAME = 1 OR 2
  165. @C    SET    1    ;;ASSUME TRUE TO BEGIN WITH
  166.     IRPC    ?C,FN    ;;LOOK THROUGH CHARACTERS OF NAME
  167.     IF    NOT ('&?C' = '1' OR '&?C' = '2')
  168. @C    SET    0    ;;CLEAR IF NOT 1 OR 2
  169.     ENDIF
  170.     ENDM
  171. ;;    @C IS TRUE IF FN = 1 OR 2 AT THIS POINT
  172.     IF    @C    ;;THEN FN = 1 OR 2
  173. ;;    FILL FROM DEFAULT AREA
  174.     IF    NUL FT    ;;TYPE SPECIFIED?
  175. @C    SET    12    ;;BOTH NAME AND TYPE
  176.     ELSE
  177. @C    SET    9    ;;NAME ONLY
  178.     ENDIF
  179.     FILLDEF    FCB&FID,(FN-1)*16,@C    ;;TO SELECT THE FCB
  180.     JMP    PFCB    ;;PAST FCB DEFINITION
  181.     DS    @C    ;;SPACE FOR DRIVE/FILENAME/TYPE
  182.     FILLNAM    FT,12-@C    ;;SERIES OF DB'S
  183.     ELSE
  184.     JMP    PFCB    ;;PAST INITIALIZED FCB
  185.     IF    NUL DN
  186.     DB    0    ;;USE DEFAULT DRIVE IF NAME IS ZERO
  187.     ELSE
  188.     DB    '&DN'-'A'+1    ;;USE SPECIFIED DRIVE
  189.     ENDIF
  190.     FILLNAM    FN,8    ;;FILL FILE NAME
  191. ;;    NOW GENERATE THE FILE TYPE WITH PADDED BLANKS
  192.     FILLNAM    FT,3    ;;AND THREE CHARACTER TYPE
  193.     ENDIF
  194. FCB&FID    EQU    $-12    ;;BEGINNING OF THE FCB
  195.     DB    0    ;;EXTENT FIELD 00 FOR SETFILE
  196. ;;    NOW DEFINE THE 3 BYTE FIELD, AND DISK MAP
  197.     DS    23    ;;X,X,RC,DM0...DM15,CR,R0,R1,R2 FIELDS
  198.     DB    0FFH    ;; DEFAULT CURRENT USER AREA
  199. ;;
  200.     IF    FID&TYP<=2    ;;IN/OUTFILE
  201. ;;    GENERATE CONSTANTS FOR INFILE/OUTFILE
  202.     FILLNXT        ;;@NXTB=0 ON FIRST CALL
  203.     IF    BS+0<@SECT
  204. ;;    BS NOT SUPPLIED, OR TOO SMALL
  205. @BS    SET    @SECT    ;;DEFAULT TO ONE SECTOR
  206.     ELSE
  207. ;;    COMPUTE EVEN BUFFER ADDRESS
  208. @BS    SET    (BS/@SECT)*@SECT
  209.     ENDIF
  210. ;;
  211. ;;    NOW DEFINE BUFFER BASE ADDRESS
  212.     IF    NUL BA
  213. ;;    USE NEXT ADDRESS AFTER @NXTB
  214. FID&BUF    SET    BUFFERS+@NXTB
  215. ;;    COUNT PAST THIS BUFFER
  216. @NXTB    SET    @NXTB+@BS
  217.     ELSE
  218. FID&BUF    SET    BA
  219.     ENDIF
  220. ;;    FID&BUF IS BUFFER ADDRESS
  221. FID&ADR    EQU $
  222.     DW    FID&BUF
  223. ;;
  224. FID&SIZ    EQU    @BS    ;;LITERAL SIZE
  225. FID&LEN    EQU $
  226.     DW    @BS    ;;BUFFER SIZE
  227. FID&PTR    EQU $
  228.     DS    2    ;;SET IN INFILE/OUTFILE
  229. ;;    SET DEVICE NUMBER
  230. @&FID    SET    @NXTD    ;;NEXT DEVICE
  231. @NXTD    SET    @NXTD+1
  232.     ENDIF    ;;OF FID&TYP<=2 TEST
  233. PFCB    EQU $
  234.     ENDM
  235. ;
  236. FILE    MACRO    FMODE,FID,DN,FN,FT,BS,BA,PU,NOLOC,SECTBUF
  237. ;;    (SEE FILLFCB FOR PARAMETERS)
  238. FID&FLG    SET    1
  239.     IF NUL PU
  240. FID&PUB    SET    0
  241.     ELSE
  242. FID&PUB    SET    1
  243.     ENDIF
  244.  
  245. @SETRC    SET    @SETRR
  246.     IF    FMODE=APPEND
  247. @SETRC    SET    @CFS
  248.     GFILE    FMODE,FID,DN,FN,FT,BS,BA,PU,NOLOC,SECTBUF,0
  249. FID&TYP    SET    OUTFILE        ;;SET MODE FOR LATER REF'S
  250.     ENDIF
  251.     GFILE    FMODE,FID,DN,FN,FT,BS,BA,PU,NOLOC,SECTBUF,@SETRC
  252.     ENDM
  253. ;
  254. GFILE    MACRO    FMODE,FID,DN,FN,FT,BS,BA,PU,NOLOC,SECTBUF,@SETRC
  255.     LOCAL    PSUB,MSG,PMSG
  256.     LOCAL    PND,EOD,EOB,PNC,GLOOP,SAMEUSR
  257. ;;    CONSTRUCT THE FILE CONTROL BLOCK
  258. ;;
  259. MD    SET    FMODE
  260.     IF    FMODE=APPEND
  261.     IF    @SETRC=0
  262. MD    SET    INFILE
  263.     ELSE
  264. MD    SET    OUTFILE
  265.     ENDIF
  266.     ENDIF
  267.     IF    FID&FLG
  268.     FILLFCB    MD,FID,DN,FN,FT,BS,BA
  269.     ENDIF
  270.     IF    MD=SETFILE    ;;SETUP FCB ONLY, SO EXIT
  271.     EXITM
  272.     ENDIF
  273. ;;    FILE CONTROL BLOCK AND RELATED PARAMETERS
  274. ;;    ARE CREATED INLINE, NOW CREATE IO FUNCTION
  275. BLOCKING    SET    @TRUE
  276.     IF    NUL SECTBUF    ;;INPUT FILE
  277.     JMP    PSUB    ;;PAST INLINE SUBROUTINE
  278.     IF    MD=OUTFILE
  279. PUT&FID    EQU $
  280.     PUSH    PSW    ;;SAVE OUTPUT CHARACTER
  281.     ELSE
  282. GET&FID    EQU $
  283.     ENDIF
  284.     LHLD    FID&LEN    ;;LOAD CURRENT BUFFER LENGTH
  285.     XCHG        ;;DE IS LENGTH
  286.     LHLD    FID&PTR    ;;LOAD NEXT TO GET/PUT TO HL
  287.     MOV    A,L    ;;COMPUTE CUR-LEN
  288.     SUB    E
  289.     MOV    A,H
  290.     SBB    D    ;;CARRY IF NEXT<LENGTH
  291.     JC    PNC    ;;CARRY IF LEN GTR CURRENT
  292. ;;    END OF BUFFER, FILL/EMPTY BUFFERS
  293.     ELSE
  294.     IF    SECTBUF=NONE
  295. BLOCKING    SET    @FALSE
  296.     ENDIF
  297.     ENDIF
  298.     IF    BLOCKING
  299.     LXI    H,0
  300.     SHLD    FID&PTR    ;;CLEAR NEXT TO GET/PUT
  301. PND    EQU $
  302. ;;    PROCESS NEXT DISK SECTOR:
  303.     XCHG        ;;FID&PTR TO DE
  304.     LHLD    FID&LEN    ;;DO NOT EXCEED LENGTH
  305. ;;    DE IS NEXT TO FILL/EMPTY, HL IS MAX LEN
  306.     MOV    A,E    ;;COMPUTE NEXT-LEN
  307.     SUB    L    ;;TO GET CARRY IF MORE
  308.     MOV    A,D
  309.     SBB    H    ;;TO FILL
  310.     JNC    EOB
  311. ;;    CARRY GEN'ED, HENCE MORE TO FILL/EMPTY
  312.     LHLD    FID&ADR    ;;BASE OF BUFFERS
  313.     DAD    D    ;;HL IS NEXT BUFFER ADDR
  314.     XCHG
  315.     MVI    C,@DMA    ;;SET DMA ADDRESS
  316.     CALL    @BDOS    ;;DMA ADDRESS IS SET
  317.     IF    FID&PUB
  318.     LDA    FCB&FID+36    ;; GET USER AREA OF FILE
  319.     CPI    0FFH
  320.     JZ    SAMEUSR
  321.     MVI    C,32
  322.     MOV    E,A
  323.     CALL    @BDOS        ;; GO TO FILE USER AREA
  324. SAMEUSR    EQU    $
  325.     ENDIF
  326.     LXI    D,FCB&FID    ;;FCB ADDRESS TO DE
  327.     IF    MD=INFILE    ;;READ BUFFER FUNCTION
  328.     MVI    C,@FRD    ;;FILE READ FUNCTION
  329.     ELSE
  330.     MVI    C,@FWR    ;;FILE WRITE FUNCTION
  331.     ENDIF
  332.     CALL    @BDOS    ;;RD/WR TO/FROM DMA ADDRESS
  333.     IF    FID&PUB
  334.     CALL    RESET$SYSTEM
  335.     ENDIF
  336.     ORA    A    ;;CHECK RETURN CODE
  337.     JNZ    EOD    ;;END OF FILE/DISK?
  338. ;;    NOT END OF FILE/DISK, INCREMENT LENGTH
  339.     LHLD    FCB&FID+33    ;;INDEX TO RANDOM RECORD #
  340.     INX    H
  341.     SHLD    FCB&FID+33    ;;POINTER UPDATED
  342.     LXI    D,@SECT    ;;SECTOR SIZE
  343.     LHLD    FID&PTR    ;;NEXT TO FILL
  344.     DAD    D
  345.     SHLD    FID&PTR    ;;BACK TO MEMORY
  346.     JMP    PND    ;;PROCESS ANOTHER SECTOR
  347. ;;
  348. EOD    EQU $
  349. ;;    END OF FILE/DISK ENCOUNTERED
  350.     IF    MD=INFILE    ;;INPUT FILE
  351.     LHLD    FID&PTR    ;;LENGTH OF BUFFER
  352.     SHLD    FID&LEN    ;;RESET LENGTH
  353.     ELSE
  354. ;;    FATAL ERROR, END OF DISK
  355.     LOCAL    EMSG
  356.     MVI    C,@MSG    ;;WRITE THE ERROR
  357.     LXI    D,EMSG
  358.     CALL    @BDOS    ;;ERROR TO CONSOLE
  359.     POP    PSW    ;;REMOVE STACKED CHARACTER
  360.     JMP    FILERR    ;;USUALLY REBOOTS
  361. EMSG    EQU $
  362.     DB    @CR,@LF
  363.     DB    'DISK FULL: &FID'
  364.     DB    '$'
  365.     ENDIF
  366. ;;
  367. EOB    EQU $
  368. ;;    END OF BUFFER, RESET DMA AND POINTER
  369.     LXI    D,@TBUF
  370.     MVI    C,@DMA
  371.     CALL    @BDOS
  372.     LXI    H,0
  373.     SHLD    FID&PTR    ;;NEXT TO GET
  374. ;;
  375. PNC    EQU $
  376.     IF    NUL SECTBUF
  377. ;;    PROCESS THE NEXT CHARACTER
  378.     XCHG        ;;INDEX TO GET/PUT IN DE
  379.     LHLD    FID&ADR    ;;BASE OF BUFFER
  380.     DAD    D    ;;ADDRESS OF CHAR IN HL
  381.     XCHG        ;;ADDRESS OF CHAR IN DE
  382.     IF    MD=INFILE    ;;INPUT PROCESSING DIFFERS
  383.     LHLD    FID&LEN    ;;FOR EOF CHECK
  384.     MOV    A,L    ;;0000?
  385.     ORA    H
  386.     MVI    A,EOF    ;;END OF FILE?
  387.     RZ        ;;ZERO FLAG IF SO
  388.     LDAX    D    ;;NEXT CHAR IN ACCUM
  389.     ELSE
  390. ;;    STORE NEXT CHARACTER FROM ACCUMULATOR
  391.     POP    PSW    ;;RECALL SAVED CHAR
  392.     STAX    D    ;;CHARACTER IN BUFFER
  393.     ENDIF
  394.     LHLD    FID&PTR    ;;INDEX TO GET/PUT
  395.     INX    H
  396.     SHLD    FID&PTR    ;;POINTER UPDATED
  397. ;;    RETURN WITH NON ZERO FLAG IF GET
  398.     ENDIF
  399.     RET
  400.     ENDIF        ; IF BLOCKING
  401. ;;
  402. PSUB    EQU $
  403.     IF    FID&FLG
  404.     ;;PAST INLINE SUBROUTINE
  405.     XRA    A        ;;ZERO TO ACC
  406.     STA    FCB&FID+12    ;;CLEAR EXTENT
  407.     STA    FCB&FID+32    ;;CLEAR CUR REC
  408.     LXI    H,FID&SIZ    ;;BUFFER SIZE
  409.     SHLD    FID&LEN        ;;SET BUFF LEN
  410.     IF    MD=INFILE    ;;INPUT FILE
  411.     SHLD    FID&PTR    ;;CAUSE IMMEDIATE READ
  412.     ELSE        ;;OUTPUT FILE
  413.     LXI    H,0    ;;SET NEXT TO FILL
  414.     SHLD    FID&PTR    ;;POINTER INITIALIZED
  415.     MVI    C,@DEL
  416.     LXI    D,FCB&FID    ;;DELETE FILE
  417.     CALL    @BDOS    ;;TO CLEAR EXISTING FILE
  418.     MVI    C,@MAK    ;;CREATE A NEW FILE
  419.     ENDIF
  420. ;;    NOW OPEN (IF INPUT), OR MAKE (IF OUTPUT)
  421.     LXI    D,FCB&FID
  422. LOCALT    SET    NUL NOLOC
  423.     IF    NOT FID&PUB OR LOCALT
  424.     PUSH    D
  425.     MVI    C,@OPN    ;;OPEN FILE FUNCTION
  426.     CALL    @BDOS    ;;OPEN/MAKE OK?
  427.     INR    A    ;;255 BECOMES 00
  428.     POP    D
  429.     JNZ    PMSG
  430.     ENDIF        ; NUL NOLOC OR NUL PU
  431.     IF    FID&PUB AND MD=INFILE
  432.     POPEN    NOLOC
  433.     JNZ    PMSG
  434.     ENDIF
  435.     IF    FMODE=APPEND
  436.     MVI    A,EOF    ;; PRIME THE BUFFER
  437.     STA    FID&BUF
  438.     LXI    H,0    ;;SET NEXT TO FILL
  439.     SHLD    FID&PTR    ;;POINTER INITIALIZED
  440.     LXI    D,FCB&FID
  441.     MVI    C,@MAK
  442.     CALL    @BDOS
  443.     INR    A    ;;255 BECOMES 00
  444.     JNZ    PMSG
  445.     ENDIF
  446.     MVI    C,@MSG    ;;PRINT MESSAGE FUNCTION
  447.     LXI    D,MSG    ;;ERROR MESSAGE
  448.     CALL    @BDOS    ;;PRINTED AT CONSOLE
  449.     JMP    FILERR    ;;TO RESTART
  450. MSG    EQU $
  451.     DB    @CR,@LF
  452.     IF    MD=INFILE AND NOT (FMODE=APPEND)    ;;INPUT MESSAGE
  453.     DB    'NO &FID FILE'
  454.     ELSE
  455.     DB    'NO DIR SPACE: &FID'
  456.     ENDIF
  457.     DB    '$'
  458.  
  459.     IF    @SETRC=0
  460. BACK&FID    EQU    $
  461.     LXI    H,FID&SIZ    ;;RESET THE LENGTH, IT MAY BE ZERO
  462.     SHLD    FID&LEN        ;;IF NO EOF CHARACTER WAS FOUND
  463.     LHLD    FID&PTR        ;;GET INDEX TO GET/PUT
  464.     MOV    A,L        ;;IF =0000 NO EOF CHARACTER TO BACK UP OVER
  465.     ORA    H
  466.     RZ
  467.     DCX    H
  468.     SHLD    FID&PTR    ;;POINTER UPDATED
  469. @@&FID    EQU    $
  470.     LHLD    FCB&FID+33    ;;INDEX TO RANDOM RECORD #
  471.     MOV    A,L        ;;=0000? BE SURE WE DON'T GO BELOW
  472.     ORA    H
  473.     RZ
  474.     DCX    H
  475.     SHLD    FCB&FID+33    ;;POINTER UPDATED
  476.     RET
  477.     ENDIF
  478. PMSG    EQU $
  479.     ENDIF
  480.     IF    NOT (@SETRC=0)
  481.     MVI    C,@SETRC    ; GET RANDOM RECORD #
  482.     LXI    D,FCB&FID
  483.     CALL    @BDOS
  484.     IF    FMODE=APPEND
  485.     CALL    @@&FID
  486. GLOOP    EQU    $        ; MOVE TO EOF IN LAST RECORD
  487.     CALL    GET&FID
  488.     CPI    EOF
  489.     JNZ    GLOOP
  490.     CALL    BACK&FID
  491.     ENDIF        ; FMODE=APPEND
  492.     IF    FID&PUB
  493.     CALL    RESET$SYSTEM
  494.     ENDIF        ; FID&PUB
  495.     ENDIF        ; @SETRC
  496. FID&FLG    SET    0
  497.     ENDM
  498. ;
  499. PUT    MACRO    DEV
  500. ;;    WRITE CHARACTER FROM ACCUM TO DEVICE
  501.     IF    @&DEV <= @LST
  502. ;;    SIMPLE OUTPUT
  503.     PUSH    PSW    ;;SAVE CHARACTER
  504.     MVI    C,@&DEV    ;;WRITE CHAR FUNCTION
  505.     MOV    E,A    ;;READY FOR OUTPUT
  506.     CALL    @BDOS    ;;WRITE CHARACTER
  507.     POP    PSW    ;;RESTORE FOR TESTING
  508.     ELSE
  509.     CALL    PUT&DEV
  510.     ENDM
  511. ;
  512. FINIS    MACRO    FID
  513. ;;    CLOSE THE FILE(S) GIVEN BY FID
  514.     IRP    ?F,<FID>
  515. ;;    SKIP ALL BUT OUTPUT FILES
  516.     IF    ?F&TYP=OUTFILE
  517.     LOCAL    EOB?,PEOF,MSG,PMSG,SAMEUSR
  518. ;;    WRITE ALL PARTIALLY FILLED BUFFERS
  519. EOB?    EQU $
  520.     ;;ARE WE AT THE END OF A BUFFER?
  521.     LHLD    ?F&PTR    ;;NEXT TO FILL
  522.     MOV    A,L    ;;ON BUFFER BOUNDARY?
  523.     ANI    (@SECT-1) AND 0FFH
  524.     JNZ    PEOF    ;;PUT EOF IF NOT 00
  525.     IF    @SECT>255
  526. ;;    CHECK HIGH ORDER BYTE ALSO
  527.     MOV    A,H
  528.     ANI    (@SECT-1) SHR 8
  529.     JNZ    PEOF    ;;PUT EOF IF NOT 00
  530.     ENDIF
  531. ;;    ARRIVE HERE IF END OF BUFFER, SET LENGTH
  532. ;;    AND WRITE ONE MORE BYTE TO CLEAR BUFFS
  533.     SHLD    ?F&LEN    ;;SET TO SHORTER LENGTH
  534. PEOF    EQU $
  535.     MVI    A,EOF    ;;WRITE ANOTHER EOF
  536.     PUSH    PSW    ;;SAVE ZERO FLAG
  537.     CALL    PUT&?F
  538.     POP    PSW    ;;RECALL ZERO FLAG
  539.     JNZ    EOB?    ;;NON ZERO IF MORE
  540. ;;    BUFFERS HAVE BEEN WRITTEN, CLOSE FILE
  541.     IF    ?F&PUB
  542.     LDA    FCB&?F+36    ;; GET USER AREA OF FILE
  543.     CPI    0FFH
  544.     JZ    SAMEUSR
  545.     MVI    C,32
  546.     MOV    E,A
  547.     CALL    @BDOS        ;; GO TO FILE USER AREA
  548. SAMEUSR    EQU    $
  549.     ENDIF
  550.     LXI    D,FCB&?F    ;;FCB ADDRESS TO DE
  551.     MVI    C,@CLS
  552.     CALL    @BDOS        ;; CLOSE THE FILE
  553.     IF    ?F&PUB
  554.     CALL    RESET$SYSTEM
  555.     ENDIF
  556.     INR    A    ;;255 IF ERR BECOMES 00
  557.     JNZ    PMSG
  558. ;;    FILE CANNOT BE CLOSED
  559.     MVI    C,@MSG
  560.     LXI    D,MSG
  561.     CALL    @BDOS
  562.     JMP    PMSG    ;;ERROR MESSAGE PRINTED
  563. MSG    EQU $
  564.     DB    @CR,@LF
  565.     DB    'CANNOT CLOSE &?F'
  566.     DB    '$'
  567. PMSG    EQU $
  568.     ENDIF
  569.     ENDM    ;;OF THE IRP
  570.     ENDM
  571. ;
  572. ERASE    MACRO    FID
  573. ;;    DELETE THE FILE(S) GIVEN BY FID
  574.     IRP    ?F,<FID>
  575.     MVI    C,@DEL
  576.     LXI    D,FCB&?F
  577.     CALL    @BDOS
  578.     ENDM    ;;OF THE IRP
  579.     ENDM
  580. ;
  581. DIRECT    MACRO    FID
  582. ;;    PERFORM DIRECTORY SEARCH FOR FILE
  583. ;;    SETS ZERO FLAG IF NOT PRESENT
  584.     LXI    D,FCB&FID
  585.     MVI    C,@DIR
  586.     CALL    @BDOS
  587.     INR    A    ;00 IF NOT PRESENT
  588.     ENDM
  589. ;
  590. RENAME    MACRO    NEW,OLD
  591. ;;    RENAME FILE GIVEN BY "OLD" TO "NEW"
  592.     LOCAL    PSUB,REN0
  593. ;;    INCLUDE THE RENAME SUBROUTINE ONCE
  594.     JMP    PSUB
  595. @RENS    EQU $
  596.     ;;RENAME SUBROUTINE, HL IS ADDRESS OF
  597.     ;;OLD FCB, DE IS ADDRESS OF NEW FCB
  598.     PUSH    H    ;;SAVE FOR RENAME
  599.     LXI    B,16    ;;B=00,C=16
  600.     DAD    B    ;;HL = OLD FCB+16
  601. REN0    EQU $
  602.     LDAX    D    ;;NEW FCB NAME
  603.     MOV    M,A    ;;TO OLD FCB+16
  604.     INX    D    ;;NEXT NEW CHAR
  605.     INX    H    ;;NEXT FCB CHAR
  606.     DCR    C    ;;COUNT DOWN FROM 16
  607.     JNZ    REN0
  608. ;;    OLD NAME IN FIRST HALF, NEW IN SECOND HALF
  609.     POP    D    ;;RECALL BASE OF OLD NAME
  610.     MVI    C,@REN    ;;RENAME FUNCTION
  611.     CALL    @BDOS
  612.     RET        ;;RENAME COMPLETE
  613. PSUB    EQU $
  614. RENAME    MACRO    N,O    ;;REDEFINE RENAME
  615.     LXI    H,FCB&O    ;;OLD FCB ADDRESS
  616.     LXI    D,FCB&N    ;;NEW FCB ADDRESS
  617.     CALL    @RENS    ;;RENAME SUBROUTINE
  618.     ENDM
  619.     RENAME    NEW,OLD
  620.     ENDM
  621. ;
  622. GET    MACRO    DEV
  623. ;;    READ CHARACTER FROM DEVICE
  624.     IF    @&DEV <= @LST
  625. ;;    SIMPLE INPUT
  626.     MVI    C,@&DEV
  627.     CALL    @BDOS
  628.     ELSE
  629.     CALL    GET&DEV
  630.     ENDM
  631. ;
  632. POPEN    MACRO    NOLOC
  633. ;    DE is assumed to point to the file FCB on entry
  634. OPEN    SET    0FH
  635.     LOCAL    PSUB,LEAVE
  636. ;OPEN MAST.CAT
  637. *  OPTION 1:  TRY TO OPEN FILE IN CURRENT USER NUMBER ON CURRENT DISK
  638.     JMP    PSUB
  639. @OPEN    EQU    $
  640.     PUSH    D    ; save the FCB
  641.     MVI    A,0FFH    ; DECLARE CURRENT USER AREA ON FILE
  642.     STA    FILEUA
  643.     MVI    C,12    ; GET VERSION NUMBER
  644.     CALL    @BDOS
  645.     MOV    A,H    ; CP/M 1.X?
  646.     ORA    L
  647.     JZ    START2$DISK    ; CHECK FOR DEFAULT DISK IF SO
  648.  
  649. *  OPTION 2:  TRY TO OPEN FILE IN USER 0 ON CURRENT DISK
  650.     MVI    E,0FFH    ; GET CURRENT USER NUMBER
  651.     MVI    C,32    ; GET USER CODE
  652.     CALL    @BDOS
  653.     MOV    C,A
  654.     LDA    DEFAULT$USER    ; CHECK IF AT DEFAULT USER
  655.     CMP    C
  656.     JZ    START2$DISK    ; DON'T TRY IF AT DEFAULT USER AREA
  657.     STA    FILEUA        ; WHERE THE FILE IS IF ANYWHERE
  658.     MOV    E,A
  659.     MOV    A,C
  660.     STA    CUR$USER    ; WHERE WE ARE(SAVE FOR LATER)
  661.     MVI    C,32    ; SET USER CODE TO DEFAULT$USER
  662.     CALL    @BDOS
  663.     IF    NUL NOLOC
  664.     POP    D    ; GET BACK FCB
  665.     PUSH    D    ; PRESERVE THE STACK
  666.     MVI    C,OPEN
  667.     CALL    @BDOS    ; TRY TO OPEN FILE AGAIN
  668.     CPI    255    ; NOT PRESENT?
  669.     JNZ    LEAVE
  670.     ENDIF        ; NUL NOLOC
  671. *  OPTION 3:  TRY TO OPEN FILE IN USER 0 ON DEFAULT DISK IF NOT CURRENT DISK
  672. START2$DISK    EQU    $
  673.     MVI    C,25    ; DETERMINE IF CURRENT DISK IS THE DEFAULT
  674.     CALL    @BDOS
  675.     MOV    C,A
  676.     LDA    DEFAULT$DISK    ; CHECK IF AT DEFAULT DISK
  677.     CMP    C
  678.     IF    NUL NOLOC
  679.     JZ    LEAVE        ;FAILURE TO OPEN SINCE NOTHING LEFT TO TRY
  680.     ENDIF
  681.     POP    H        ; FCB INTO HL
  682.     PUSH    H        ; PRESERVE STACK
  683.     IF    NUL NOLOC
  684.     ELSE
  685.     JZ    START3$DISK
  686.     ENDIF
  687.     INR    A        ; ADD ONE TO DISK NUMBER
  688.     MOV    M,A    ; PUT INTO FCB
  689. START3$DISK    EQU    $
  690.     XCHG        ; FCB INTO DE
  691.     MVI    C,15    ; OPEN FILE
  692.     CALL    @BDOS
  693.     CPI    255    ; NOT PRESENT?
  694.  
  695. LEAVE    EQU    $
  696.     POP    D    ; GET THE FCB AGAIN(AND CLEAN UP STACK)
  697.     PUSH    PSW    ; SAVE OPEN STATUS ON FILE
  698.     LXI    H,36
  699.     DAD    D
  700.     LDA    FILEUA        ; GET THE USER AREA FOR THE FILE
  701.     MOV    M,A        ; PUT USER AREA INTO FCB
  702.     POP    PSW
  703.     RET
  704. ;
  705. RESET$SYSTEM    EQU    $
  706.     PUSH    PSW
  707.     LDA    CUR$USER    ; CHECK USER
  708.     CPI    0FFH    ; 0FFH=NO CHANGE
  709.     JZ    RESET$RET
  710.     MOV    E,A    ; USER IN E
  711.     MVI    C,32    ; GET/SET USER CODE
  712.     CALL    @BDOS
  713. RESET$RET    EQU    $
  714.     POP    PSW
  715.     RET
  716.  
  717. FILEUA    EQU    $
  718.     DS    1
  719. PSUB    EQU    $
  720. POPEN    MACRO
  721.     CALL    @OPEN
  722.     ENDM
  723.     POPEN
  724.     ENDM
  725.