home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 223_02 / rdrtl.mac < prev    next >
Text File  |  1989-02-23  |  27KB  |  1,444 lines

  1. ;
  2. ;RDRTL.MAC  Small C Runtime Library with redirectable output
  3. ;        Always used with compiler
  4. ;        Must be linked first when used
  5. ;        Supports 8 1k file buffers
  6. ;        Redirected output via > (only to a file)
  7. ;        Redirected append output via >> (only to a file)
  8. ;        Functions included:
  9. ;        fopen()        fclose()    (r, w, & a modes)
  10. ;        getchar()    putchar()
  11. ;        gets()        puts()
  12. ;        getc()        putc()
  13. ;        fgetc()        fputc()
  14. ;        fgets()        fputs()
  15. ;        exit()        abort()
  16. ;        bdos() (for cp/m calls)
  17. ;
  18. ;        and all supporting functions
  19. ;
  20. ;        grabio(), freeio(), fcb(), fcbfill(), fcbpad()
  21. ;        cpmio(), cpmdisk()
  22. ;
  23. ;            by
  24. ;
  25. ;        F. A. Scacchitti
  26. ;        25 Glenview Lane
  27. ;        Rochester, NY 14609
  28. ;
  29. ;           3 - 25 - 86
  30. ;
  31. ;
  32. ;    *** 
  33.     EXTRN    MAIN, CCDSGI, CCSXT, ZZBUF 
  34. ;    ***
  35. ;
  36. ; ========================================
  37. ;  I/O subroutines for CP/M
  38. ;    originally
  39. ;              By Glen    Fisher
  40. ;        The Code Works(tm)
  41. ;    then
  42. ;        [modified by Bill Randle]
  43. ;    and finally
  44. ;        [significantly modified by Fred Scacchitti]
  45. ;
  46. ; ========================================
  47. ;
  48. NULL    EQU    0    ;pointer to nothing
  49. FCBSIZE    EQU    36    ;size, in bytes, of an FCB
  50. NEXTP    EQU    0    ;offset    to next-character pointer in I/O structure
  51. UNUSED    EQU    2    ;offset    to unused-positions-count in I/O structure
  52. UNGOT    EQU    5    ;offset to char ungotten by ungetc()
  53. BUFFER    EQU    6    ;offset    to disk    sector buffer in I/O structure
  54. FLAG    EQU    33    ;file-type flag    byte (in unused    part of    FCB)
  55. FREEFLG    EQU    128    ;This I/O structure is available for the taking
  56. EOFFLG    EQU    2    ;The end of this file has been hit
  57. WRTFLG    EQU    1    ;This file open    for writing
  58. BUFSIZ    EQU    1024    ;how long the sector buffer is
  59. NBUFS    EQU    8    ;number    of I/O buffers 
  60. NSECTS    EQU    8    ;sectors per buffer
  61. TBUFSZ    EQU    128    ;default CP/M buffer size
  62.             ; (change buffer declarations, too)
  63.     ; CP/M system call codes
  64. CLOSE    EQU    16    ;close a file
  65. CPMSTR    EQU    9    ;print '$' delimited string on console
  66. CREATE    EQU    22    ;make a    file
  67. DMA    EQU    26    ;set DMA (I/O address)
  68. DELETE    EQU    19    ;delete    a file
  69. GETCH    EQU    1    ;read character    from console
  70. GETSTR    EQU    10    ;read string from console
  71. OPEN    EQU    15    ;open a    file
  72. PUTCH    EQU    2    ;write character to console
  73. QUERY    EQU    25    ;get logged-in drive id
  74. READ    EQU    20    ;read a    sector
  75. SELECT    EQU    14    ;log-in    a drive
  76. WRITE    EQU    21    ;write a sector
  77. ;
  78. LF    EQU    10    ;line feed
  79. EOL    EQU    13    ;end-of-line character (=carriage return)
  80. CTRLZ    EQU    26    ;end-of-file mark for text files
  81. EOF    EQU    0FFH    ;end of file marker for other
  82. TBUFF    EQU    80H    ;address of default I/O    address
  83. CBDOS    EQU    5    ;Entry point to    CP/M BDOS (mod to cbdos(fas)) 
  84. CPMARG    EQU    80H    ;CP/M command line
  85. MAXARG    EQU    24    ;Maximum number    of args    in input line
  86. STDOUT    EQU    1    ;Default for stdout
  87. STDERR    EQU    2    ;Default for stderr
  88. ;
  89. DFLTDSK: DS    1    ;drive to use if no drive is named
  90. UNIT:    DS    2    ;I/O structure address to act on
  91. IP:    DS    2    ;int *ip;
  92. CHP:    DS    2    ;char *chp;
  93. DP:    DS    2    ;char *dp;
  94. FILE:    DS    2    ;file name
  95. MODE:    DS    2    ;char *mode;(read or write)
  96. ZCH:    DS    2    ;char ch;
  97. ZT:    DS    2    ;int t;
  98. FN:    DS    2    ;int fn;    i/o function (for cpmio)
  99. NUBUFF:    DS    2    ;# TEMPORARY BUFFER STORAGE 
  100. MAXSEC:    DS    1    ;# SECTOR COUNTER
  101. AFLAG:    DS    1    ;# append flag
  102. ;
  103. SVCHP:    DS    2    ;char *svchp;    saved character    pointer
  104. RSTDOUT: DS    2    ;int rstdout;    unit of    redirected stdout
  105. ;
  106. ZZMEM::        DS    2    ;memory pointer used by calloc
  107. ZZSTAK::    DS    2
  108. ;
  109. ; First    thing, we save CPM's stack pointer and current disk and
  110. ; init stdin and stdout.
  111. ; Second thing,    we run through the CPM input line and
  112. ; modify it so that we can pass    the C program the
  113. ; command line in the argc, argv form that it expects
  114.  
  115. ; HL = pointer to next argv entry
  116. ; DE = pointer to next character in command line
  117. ; B = number of    characters left    in line
  118. ; C = argument count (argc)
  119.  
  120. ULINK::    LXI    H,0    ; Get CPM's stack pointer
  121.     DAD    SP
  122.     SHLD    ZZSTAK    ; Save it for later
  123. ;
  124.     MVI    C,26
  125.     LXI    D,ZZBUF
  126.     CALL    CBDOS    ;Set the default buffer way out there
  127. ;
  128. SETIO:    
  129.     MVI    B,NBUFS
  130.     LXI    H,ZZBUF+TBUFSZ+FLAG
  131.     LXI    D,FCBSIZE+BUFFER+BUFSIZ
  132.     MVI    A,FREEFLG
  133. SETIO2:    MOV    M,A            ;# SET ALL BUFFERS TO FREE
  134.     DAD    D            ;on to next buffer
  135.     DCR    B
  136.     JNZ    SETIO2            ;if there is one...
  137. ;
  138.     SHLD    ZZMEM
  139. ;
  140.     MVI    C,QUERY    ; get logged-in    disk
  141.     CALL    CBDOS    ; (mod to cbdos(fas))
  142.     INR    A    ; make it so it    will work in fcb
  143.     STA    DFLTDSK
  144. ;
  145.     LDA    CBDOS+2    ; Get base of BDOS (mod to cbdos(fas))
  146.     MOV    H,A    ; Save page in HL
  147.     MVI    L,0
  148.     SPHL        ; Set stack pointer
  149. ;
  150.     LXI    H,STDOUT
  151.     SHLD    RSTDOUT    ; Init rstdout
  152. ;
  153.     MVI    C,0    ; Init argc
  154.     LXI    H,ARGV    ; Pointer to first entry of argv array
  155.  
  156. ; Unfortunately, CPM does not tell us what the first word of
  157. ; the command line was (the name of pgm), so we    fake
  158. ; it by    pointing it to a ascii string with '*' in    it
  159.  
  160.     LXI    D,PGM    ; Pointer to 'pgmname' string
  161.     CALL    SVARG    ; Save next argument
  162.  
  163. ; Ok, now for the real stuff.  Set DE pair to point to
  164. ; CPM command line and start searching for arguments
  165.  
  166.     LXI    D,CPMARG ; Pointer to CPM arg line
  167.     LDAX    D    ; Load # character in line
  168.     MOV    B,A    ; Save it in B
  169. NXTSP:    INX    D    ; Point    to next    character
  170.     DCR    B    ; Decrement character count
  171.     JM    ENDCMD    ; End of cmd line
  172.     LDAX    D    ; Load next character in line
  173.     CPI    ' '    ; Space?
  174.     JZ    NXTSP    ; Yes...continue searching
  175.     CPI    '>'    ; Redirect output?
  176.     JZ    RDOUT    ; Yes...open the file for output
  177.     CALL    SVARG    ; Nope,    save starting point of this arg
  178.  
  179. ; Loop looking for either end of line of a space
  180.  
  181. NXTCH:    INX    D    ; Point    to next    character
  182.     DCR    B    ; Decrement character count
  183.     JM    ENDWRD    ; End of cmd line, but need to end arg
  184.     LDAX    D    ; Load next character in line
  185.     CPI    ' '    ; Space?
  186.     JNZ    NXTCH    ; Nope...keep looking
  187.     MVI    A,0    ; Yes, replace it with a zero byte
  188.     STAX    D
  189.     JMP    NXTSP    ; Look for start of next arg
  190. ENDWRD:    MVI    A,0
  191.     STAX    D
  192. ENDCMD:    MVI    B,0    ; Zero B (BC now is 16 bit argc)
  193.     PUSH    B    ; First    arg to main procedure
  194.     LXI    H,ARGV    ; Point    to argv    array
  195.     PUSH    H    ; Second argument to main procedure
  196.     MVI    A,2    ; Load up the argument count
  197.     CALL    MAIN    ; Transfer to the C world....
  198. ;
  199. ;    off
  200. ;        we
  201. ;            go
  202. ;                into
  203. ;                     the
  204. ;                         wild
  205. ;                          b
  206. ;                           l
  207. ;                        u
  208. ;                         e
  209. ;
  210.     JMP    EXIT    ; Return to CPM
  211. ;
  212. SVARG:    MOV    M,E    ; Save pointer to start    of string
  213.     INX    H
  214.     MOV    M,D
  215.     INX    H
  216.     INR    C    ; Increment argc
  217.     RET
  218. ARGV:    DS    MAXARG*2
  219. PGM:    DB    '*',0
  220. ;
  221.  
  222. RDOUT:  INX    D    ; get next character
  223.     DCR    B
  224.     LDAX    D
  225.     CPI    '>'    ; check for append mode
  226.     JNZ    RDOUT1
  227.     MVI    A,0FH
  228.     STA    AFLAG    ; Set flag for appending
  229.     INX    D    ; stand on next character
  230.     DCR    B
  231. RDOUT1:    CALL    DEBLNK    ; Skip leading spaces
  232.     JM    RDERR    ; End of line reached
  233.     PUSH    H
  234.     CALL    CPYNAM    ; Copy filename    to temp    buffer
  235.     PUSH    D    ; Save registers
  236.     PUSH    B
  237.     LXI    H,NAMBUF ; Begining of filename
  238.     PUSH    H
  239.     LDA    AFLAG    ; Test for append mode
  240.     CPI    0FH
  241.     JNZ    RDOUT2    ; No, set write mode
  242.     XRA    A    ; Yes, clear the flag and
  243.     STA    AFLAG
  244.     LXI    H,APOPN    ; set append mode
  245.     JMP    RDOUT3    ; doit
  246. RDOUT2:    LXI    H,WROPN    ; Mode
  247. RDOUT3:    PUSH    H
  248.     CALL    FOPEN    ; Open the file
  249.     POP    D
  250.     POP    D
  251.     MOV    A,H
  252.     ORA    L    ; Check    return status
  253.     JZ    RDERR
  254.     SHLD    RSTDOUT    ; Save unit for    redirected output
  255.     POP    B    ; Restore registers
  256.     POP    D
  257.     POP    H
  258.     MVI    A,0FFH
  259.     CMP    B    ; End of command line?
  260.     JZ    ENDCMD
  261.     JMP    NXTSP    ; Get next argument
  262. ;
  263. DEBLNK:
  264.     LDAX    D
  265.     CPI    ' '
  266.     RNZ
  267.     INX    D    ; Skip leading spaces
  268.     DCR    B
  269.     RM        ; End of line reached
  270.     JMP    DEBLNK
  271. ;
  272. CPYNAM:    LXI    H,NAMBUF ; Copy    filename to temp buffer
  273.     PUSH    B    ; Save reg C
  274.     MVI    C,16    ; Maximum filename length
  275. CPY1:    MOV    M,A
  276.     INX    D
  277.     INX    H
  278.     DCR    B
  279.     JM    ENDNAM
  280.     DCR    C
  281.     JZ    RDERR
  282.     LDAX    D
  283.     CPI    ' '
  284.     JNZ    CPY1
  285. ENDNAM:    MVI    M,0
  286.     POP    H
  287.     MOV    C,L    ; Restore reg C
  288.     RET
  289. ;
  290. RDERR:    LXI    D,RDEMSG ; Error message
  291.     MVI    C,CPMSTR
  292.     CALL    CBDOS    ; Make sure it gets put    on the terminal (mod fas)
  293.     JMP    EXIT
  294. ;
  295. TEMP:    DB    0,0
  296. RDOPN:    DB    'r',0
  297. WROPN:    DB    'w',0
  298. APOPN:    DB    'a',0
  299. NAMBUF:    DS    16
  300. RDEMSG:    DB    'rdrtl:    Unable to open output file$'
  301. ;
  302. ;
  303. ;
  304. ; This assembly    routine    allows CPM calls from Small C.
  305. ;
  306. ;     cpm(cpmfunction#,    inputparameter)
  307. ;    bdos(bdos#,data)
  308. ;
  309. ; NOTE - These two functions are the same. This addition may just
  310. ;     save editing some code. (fas)
  311. ;
  312. ; Since    this function returns whatever is returned in register
  313. ; it cannot be used to call ReturnVersionNumber, ReturnLoginVector,
  314. ; WriteProtectDisk, or GetAddr.
  315.  
  316. BDOS::            ; added alias (fas)
  317. CPM::    POP    H    ; Pop rtn address
  318.     POP    D    ; Pop input parameter in DE register pair
  319.     POP    B    ; Pop function code into C register
  320.     PUSH    B    ; Restore stack
  321.     PUSH    D
  322.     PUSH    H
  323.     CALL    CBDOS    ; Call CPM (mod to cbdos (fas))
  324.     MOV    L,A    ; Sign extend A    into HL    register pair
  325.     RLC
  326.     SBB    A
  327.     MOV    H,A
  328.     RET
  329.  
  330. ;    exit()
  331. ;
  332. ;    Stop execution of the program,
  333. ;    restore    the logged-in drive,
  334. ;    and re-boot CP/M
  335. ;
  336. EXIT::    LHLD    RSTDOUT
  337.     MOV    A,H
  338.     ORA    A        ; See if stdout    has been redirected
  339.     JZ    EXIT1
  340.     PUSH    H
  341.     CALL    FCLOSE        ; If so, close the file
  342.     POP    B
  343. EXIT1:    LDA    DFLTDSK        ; Grab orig. logged-in disk
  344.     MOV    E,A
  345.     DCR    E        ; (cvt.    back to    0-n)
  346.     MVI    C,SELECT    ; and log it in    again
  347.     CALL    CBDOS        ; (mod to cbdos (fas))
  348.     LHLD    ZZSTAK        ; Load stack pointer
  349.     SPHL
  350.     JMP    0        ; return to CP/M
  351. ;
  352. ;    abort(reason)
  353. ;
  354. ABORT::    POP    B
  355.     POP    H
  356.     ORA    A
  357.     JZ    ABORT2
  358.     MOV    A,L
  359.     STA    ABCODE
  360. ABORT2:    LXI    D,ABTMSG    ; Load abort message
  361.     MVI    C,9
  362.     CALL    CBDOS
  363.     JMP    EXIT
  364.  
  365. ABTMSG:    DB    0DH, 'Aborted '
  366. ABCODE:    DB    07H,0DH,'$'
  367. ;
  368. ;    grabio()
  369. ;
  370. ;    find an    input buffer, and return its address.
  371. ;    if there isn't one, return a NULL.
  372. ;
  373. GRABIO::                        ;6 May 80 rj
  374.     MVI    B,NBUFS
  375.     LXI    H,ZZBUF+TBUFSZ+FLAG
  376.     LXI    D,FCBSIZE+BUFFER+BUFSIZ
  377.     MVI    A,FREEFLG
  378. GRAB2:    CMP    M            ;flag byte == freeflg?
  379.     JZ    GRAB3            ;if so,    found a    free buffer
  380.     DAD    D            ;on to next buffer
  381.     DCR    B
  382.     JNZ    GRAB2            ;if there is one...
  383.     LXI    H,NULL            ;there ain't
  384.     RET                ;give up
  385. ;
  386. GRAB3:    MVI    M,0            ;mark buffer as    taken
  387.     LXI    D,-FLAG            ;back up to buffer start
  388.     DAD    D    
  389.     RET                ;and hand it back
  390. ;
  391. ;    freeio(unit)
  392. ;
  393. ;    mark a buffer as free.
  394. ;
  395. FREEIO::                ;Mod  6    May 80 rj
  396.     POP    B            ;save rtn addr
  397.     POP    H            ;get buffer addr
  398.     PUSH    H            ;put the stack back together
  399.     PUSH    B
  400.     LXI    D,FLAG            ;find flag byte
  401.     DAD    D
  402.     MVI    M,FREEFLG        ;mark buffer as    'free'
  403.     LXI    H,NULL            ;return    something
  404.     RET
  405. ;
  406. ; Storage variables used by append mode
  407. ;
  408. CURREC:    DB    0
  409. CUREXT:    DB    0
  410. OLDREC:    DB    0
  411. OLDEXT:    DB    0
  412. ;
  413. ;    fopen(name,mode)
  414. ;
  415. FOPEN::
  416. ;
  417.     POP    B            ;get args
  418.     POP    H            ;mode
  419.     SHLD    MODE
  420.     POP    D
  421.     XCHG
  422.     SHLD    FILE
  423.     PUSH    H
  424.     PUSH    D
  425.     PUSH    B
  426.     CALL    GRABIO            ; unit = grabio();
  427.     SHLD    UNIT
  428.     MOV    A,H            ; if(unit==NULL)
  429.     ORA    L            ;    return(NULL);
  430.     RZ
  431.     LXI    D,FCBSIZE        ; ZZIP = unit+FCBSIZE;
  432.     DAD    D
  433.     SHLD    IP
  434. ;
  435.     LXI    D,UNGOT            ;# OFFSET TO UNGOTTEN CHAR
  436.     DAD    D
  437.     MVI    M,0FFH            ;# EOF TO AVOID EXTRA CHAR
  438. ;
  439.     DCX    H            ;# POINT TO ERROR BYTE
  440.     MVI    M,0            ;# CLEAR IT
  441. ;
  442.     LHLD    IP            ;ZZIP[NEXTP]=&ZZIP[BUFFER];
  443.     LXI    D,BUFFER
  444.     DAD    D
  445.     XCHG
  446.     LHLD    IP
  447.     LXI    B,NEXTP
  448.     DAD    B
  449.     MOV    M,E
  450.     INX    H
  451.     MOV    M,D
  452.     LHLD    UNIT            ; fcb(unit,name);
  453.     PUSH    H
  454.     LHLD    FILE
  455.     PUSH    H
  456.     CALL    FCB
  457.     POP    H
  458.     POP    H
  459.     LHLD    UNIT            ; cpmdisk(*unit);
  460.     MOV    L,M
  461.     MVI    H,0
  462.     PUSH    H
  463.     CALL    CPMDISK
  464.     POP    H
  465.     LHLD    MODE            ;if(*mode=='R'||*mode=='A'){
  466.     MOV    A,M
  467. ;
  468.     ANI    5FH            ;# CONVERT TO UPPERCASE
  469.     CPI    'R'            ;# MODE = R ?
  470.     JNZ    FOPIF1
  471. ;
  472. FOPIF0:
  473.     MVI    C,OPEN            ;    if(cpm(OPEN,unit)<0){
  474.     LHLD    UNIT
  475.     XCHG
  476.     CALL    CBDOS        ; (mod toÇcbdos (fas))
  477.     ORA    A
  478.     JP    FOPIF2
  479.     LHLD    UNIT        ;        freeio(unit);
  480.     PUSH    H
  481.     CALL    FREEIO
  482.     POP    H
  483.     LXI    H,NULL        ;        return(NULL);
  484.     RET
  485.                 ;        }
  486. FOPIF2:
  487.     LHLD    IP        ;    IP[UNUSED] = 0;
  488.     LXI    D,UNUSED
  489.     DAD    D
  490.     LXI    D,0
  491.     MOV    M,E
  492.     INX    H
  493.     MOV    M,D
  494.                 ;    }
  495.     JMP    FOPIFX
  496. FOPIF1:                ; else if(*mode=='W'){
  497.     LHLD    MODE    
  498.     MOV    A,M
  499.     ANI    5FH
  500.     CPI    'W'        ;# WRITE MODE ?
  501.     JZ    FOPIFA        ;# YES - GO DO IT
  502.     CPI    'A'        ;# APPEND MODE ?
  503.     JNZ    FOPIF5        ;# NO  - BACK TO CALLER OF FOPEN
  504. ;                ;#     NO MODES LEFT TO TRY
  505. ;
  506.     MVI    C,OPEN        ;# FIRST LET'S SEE IF IT'S THERE
  507.     LHLD    UNIT
  508.     XCHG
  509.     CALL    CBDOS
  510.     ORA    A
  511.     JP    FOPIF3        ;# YES  - SET IT UP FOR USE
  512. ;
  513.                 ;# NO   - LET'S MAKE ONE
  514.     LHLD    MODE        ;# SET MODE TO 'W' ON NEW FILE
  515.     MVI    M,'W'        ;# TO AVOID WASTING TIME AND CODE
  516.                 ;# SEARCHING AN EMPTY FILE
  517. ;
  518. FOPIFA:
  519.     MVI    C,DELETE    ;    cpm(DELETE,unit);
  520.     LHLD    UNIT
  521.     XCHG
  522.     CALL    CBDOS        ; (mod to cbdos(fas))
  523.     MVI    C,CREATE    ;    if(cpm(CREATE,unit)<0){
  524.     LHLD    UNIT
  525.     XCHG
  526.     CALL    CBDOS        ; (mod to cbdos(fas))
  527.     ORA    A
  528.     JP    FOPIF3
  529.     LHLD    UNIT        ;        freeio(unit);
  530.     PUSH    H
  531.     CALL    FREEIO
  532.     POP    H
  533.     LXI    H,NULL        ;        return(NULL);
  534.     RET
  535.                 ;        }
  536. FOPIF3:
  537.     LHLD    IP        ;    IP[UNUSED] = BUFSIZ;
  538.     LXI    D,UNUSED
  539.     DAD    D
  540.     LXI    D,BUFSIZ
  541.     MOV    M,E
  542.     INX    H
  543.     MOV    M,D
  544.     LHLD    UNIT        ;    unit[FLAG] = WRITE_FL;
  545.     LXI    D,FLAG
  546.     DAD    D
  547.     MVI    A,WRTFLG
  548.     ORA    M
  549.     MOV    M,A
  550.     JMP    FOPIF4
  551.                 ;    }
  552. FOPIF5:
  553.     LHLD    UNIT        ; else{    freeio(unit);
  554.     PUSH    H
  555.     CALL    FREEIO
  556.     POP    H
  557.     LXI    H,NULL        ;    return(NULL);
  558.     RET
  559. ;
  560.                 ;    }
  561. FOPIF4:
  562. ;
  563.     LHLD    MODE        ;#
  564.     MOV    A,M        ;# GET MODE
  565.     ANI    5FH
  566.     CPI    'A'        ;# APPEND MODE ?
  567.     JNZ    FOPIFX        ;# NO  -  RETURN NORMALLY
  568. ;
  569. AMSCRD:
  570. ;
  571.     LDA    CUREXT        ;# SAVE EXTENT AND RECORD NUMBERS
  572.     STA    OLDEXT        ;#    TWO DEEP
  573.     LDA    CURREC
  574.     STA    OLDREC
  575.     LHLD    UNIT
  576.     LXI    D,12
  577.     DAD    D
  578.     MOV    A,M        ;# GET CURRENT EXTENT #
  579.     STA    CUREXT
  580.     LXI    D,20
  581.     DAD    D
  582.     MOV    A,M        ;# GET CURRENT RECORD #
  583.     STA    CURREC
  584. ;
  585.     LHLD    UNIT        ;# YES -  LET'S READ TO THE END
  586.     XCHG            ;# DE --> FCB
  587.     MVI    C,READ
  588.     CALL    CBDOS        ;# READ A SECTOR
  589.     ORA    A
  590.     JZ    AMSCRD        ;# READ TO PHYSICAL END OF FILE
  591. ;
  592.     LHLD    UNIT
  593.     LXI    D,12
  594.     DAD    D
  595.     LDA    OLDEXT
  596.     MOV    M,A        ;# RESTORE LAST EXTENT #
  597.     LXI    D,20
  598.     DAD    D
  599.     LDA    OLDREC
  600.     MOV    M,A        ;# RESTORE LAST RECORD #
  601. ;
  602.     LXI    H,ZZBUF
  603.     SHLD    TEMP        ;# SAVE THE BUFF. WE'RE READING FROM
  604. ;
  605.     XRA    A
  606.     STA    OLDREC        ;# use oldrec for a counter
  607. AMCHRD:
  608.     LHLD    TEMP        ;# HL --> TEMPORARY BUFFER
  609.     MOV    A,M
  610. ;
  611.     CPI    0AH        ;# LINE FEED CHECK
  612.     JNZ    NOTLF
  613.     INX    H        ;# INCREMENT POINTER 
  614.     SHLD    TEMP        ;#  AND GO ON TO NEXT CHARACTER
  615.     JMP    AMCHRD
  616. ;
  617. NOTLF:    CPI    1AH        ;# END OF FILE MARKER ?
  618.     JZ    FOPIFX        ;# YES - EXIT GRACEFULLY
  619.     MOV    C,A
  620.     MVI    B,0        ;# BC CONTAINS THE CHARACTER
  621.     INX    H
  622.     SHLD    TEMP        ;# SAVE UPDATED POINTER
  623.     LHLD    UNIT
  624.     PUSH    B
  625.     PUSH    H
  626.     CALL    PUTC        ;# PUTC(CHAR,ZZUNIT)
  627.     POP    B
  628.     POP    B
  629. ;
  630.     LDA    OLDREC        ;# get the counter
  631.     INR    A        ;# add a count
  632.     STA    OLDREC        ;# store it
  633. ;
  634.     JNZ    AMCHRD        ;# keep going (max 128 bytes)
  635. ;
  636. FOPIFX:
  637.     LHLD    UNIT        ; return(unit);
  638.     RET
  639. ;
  640. ;
  641. ;    fclose(unit)
  642. ;
  643. FCLOSE::
  644.     POP    B
  645.     POP    H
  646.     SHLD    UNIT
  647.     PUSH    H
  648.     PUSH    B
  649.     MOV    A,H            ; if (unit<256)
  650.     ORA    A            ; /* assume stdin, stdout, etc. */
  651.     MVI    L,0    
  652.     RZ                ;     return NULL;
  653.     LXI     H,1             ; t = 1;
  654.     SHLD    ZT
  655.     LHLD    UNIT            ; if(unit[FLAG]    & WRITE_FL){
  656.     LXI    D,FLAG
  657.     DAD    D
  658.     MOV    A,M
  659.     ANI    WRTFLG
  660.     JZ    FCLIF1
  661.     LXI    H,CTRLZ            ;    putc(CTRL_Z,unit);    
  662.     PUSH    H
  663.     LHLD    UNIT
  664.     PUSH    H
  665.     CALL    PUTC
  666.     POP    H
  667.     POP    H
  668.     LHLD    UNIT            ;    ip = unit + FCBSIZE;
  669.     LXI    D,FCBSIZE
  670.     DAD    D
  671.     SHLD    IP
  672.     LHLD    IP            ;        cp = ip[NEXTP];
  673.     LXI    D,NEXTP
  674.     DAD    D
  675.     MOV    E,M
  676.     INX    H
  677.     MOV    D,M
  678.     XCHG
  679.     SHLD    CHP
  680.     LHLD    IP            ;    dp = &ip[BUFFER]+BUFSIZ;
  681.     LXI    D,BUFFER+BUFSIZ
  682.     DAD    D
  683.     SHLD    DP
  684. FCLWH1:                    ;        while(cp<dp)
  685.     LHLD    CHP
  686.     XCHG
  687.     LHLD    DP
  688.     MOV    A,D
  689.     CMP    H
  690.     JC    FCLWH2
  691.     JNZ    FCLWH3
  692.     MOV    A,E
  693.     CMP    L
  694.     JNC    FCLWH3
  695. FCLWH2:                    ;        *cp++ =    CTRL_Z;
  696.     LHLD    CHP
  697.     MVI    M,CTRLZ
  698.     INX    H
  699.     SHLD    CHP
  700.     JMP    FCLWH1
  701. FCLWH3:
  702.     LXI    H,WRITE            ;    if(cpmio(WRITE,unit)<0)
  703.     PUSH    H
  704.     LHLD    UNIT
  705.     PUSH    H
  706.     CALL    CPMIO
  707.     POP    D
  708.     POP    D
  709.     MOV    A,H
  710.     ORA    A
  711.     JP    FCLIF4
  712.     LXI    H,0            ;            t = 0;
  713.     SHLD    ZT
  714. FCLIF4:
  715.                     ;        }
  716. FCLIF3:
  717.                     ;    }
  718. FCLIF1:
  719.     MVI    C,CLOSE            ; if(cpm(CLOSE,unit)<0)
  720.     LHLD    UNIT
  721.     XCHG
  722.     CALL    CBDOS        ; (mod tocbdos(fas))
  723.     ORA    A
  724.     JP    FCLIF5
  725.     LXI    H,0            ;    t = 0;
  726.     SHLD    ZT
  727. FCLIF5:
  728.     LHLD    UNIT            ; freeio(unit);
  729.     PUSH    H
  730.     CALL    FREEIO
  731.     POP    H
  732.     LHLD    ZT            ; return(NULL+t);
  733.     RET
  734. ;
  735.  
  736. ;
  737. ;    fcb(fp,name)
  738. ;
  739. FCB::
  740.     POP    H            ;get args
  741.     POP    D            ;name
  742.     POP    B            ;fp
  743.     PUSH    B
  744.     PUSH    D
  745.     PUSH    H
  746.     INX    D            ; if(name[1]==':'){
  747.     LDAX    D
  748.     DCX    D
  749.     CPI    ':'
  750.     JNZ    FCBIF1
  751.     LDAX    D            ;    A = *name - '@';
  752.     SUI    40H            ; '@' 9    Jun 80 rj
  753.         
  754.     INX    D            ;    name +=    2;
  755.     INX    D
  756.  
  757.     CPI    61H-41H
  758.     JC    FCBIF2
  759.     SUI    61H-41H            ;    A -= 'a'-'A'; 9    Jun 80 rj
  760.     JMP    FCBIF2            ;    }
  761. FCBIF1:
  762.     LDA    DFLTDSK            ; else    A = default_drive;
  763. FCBIF2:
  764.     STAX    B            ; *fp++    = A;
  765.     INX    B
  766.     MVI    H,' '            ; fp = fcbfill(fp,name,' ',8);
  767.     MVI    L,8
  768.     CALL    FCBFILL
  769.     MVI    L,3            ; fp = fcbfill(fp,name,' ',3);
  770.     CALL    FCBFILL
  771.     MVI    H,0            ; fp = fcbpad(fp,0,4);
  772.     MVI    L,4
  773.     CALL    FCBPAD
  774.     LXI    H,16            ; fp[16] = 0;
  775.     DAD    B
  776.     MVI    M,0
  777.     RET                ; return;
  778. ;
  779. ;    fcbfill(dest,name,pad,size)
  780. ;        B    D      H   L
  781. ;
  782. FCBFILL::
  783.     MOV    A,L        ; while(L>0 && (A= *D)~='.' && A~=0){
  784.     ORA    A
  785.     JZ    FILL2
  786.     LDAX    D
  787.     CPI    '.'
  788.     JZ    FILL2
  789.     CPI    0
  790.     JZ    FILL2
  791.     CPI    61H        ;    if(A>='a' && A<='z')
  792.     JC    FILL1
  793.     CPI    7AH+1        ; 'z' 9    Jun 80 rj
  794.     JNC    FILL1
  795.     SUI    61H-41H        ;        A = A -    'a' + 'A';
  796. FILL1:
  797.     STAX    B        ;    *B++ = A;
  798.     INX    B
  799.     INX    D        ;    D++;
  800.     DCR    L        ;    L--;
  801.     JMP    FCBFILL        ;    }
  802. FILL2:
  803.     LDAX    D        ; while(*D~='.'    && *D~=0)    
  804.     CPI    '.'
  805.     JZ    FILL3
  806.     CPI    0
  807.     JZ    FILL3
  808.     INX    D        ;    D++;
  809.     JMP    FILL2
  810. FILL3:
  811.     CPI    '.'        ; if(*D=='.')
  812.     JNZ    FILL4
  813.     INX    D        ;    D++;
  814. FILL4:
  815. ;    fall into...
  816. ;
  817. ;    fcbpad(dest,pad,size)
  818. ;        B   H    L
  819. ;
  820. FCBPAD::
  821.     MOV    A,L            ; while(L>0){
  822.     ORA    A
  823.     JZ    PAD2
  824.     MOV    A,H            ;    *B++ = H;
  825.     STAX    B
  826.     INX    B
  827.     DCR    L            ;    L--;
  828.     JMP    FCBPAD            ;    }
  829. PAD2:
  830.     RET                ; return;
  831. ;
  832. ;    getc(unit)
  833. ;
  834. FGETC::
  835. GETC::
  836.     POP    B
  837.     POP    H            ; get args
  838.     PUSH    H
  839.     PUSH    B
  840.                     ; c=cget(unit);
  841.     PUSH    H
  842.     CALL    CGET
  843.     POP    D
  844.     MOV    A,L            ; if(c=='\r')    
  845.     ANI    7FH            ; /* mask parity in compare */
  846.     CPI    EOL
  847.     JNZ    GETCRET
  848.     PUSH    H            ;    cget(unit);
  849.     PUSH    D            ;    /* to skip LF */
  850.     CALL    CGET
  851.     MOV    A,L
  852.     ANI    7FH
  853.     CPI    0AH            ; and only skip line feeds
  854.     JZ    GETCNLF
  855.     LHLD    UNIT
  856.     LXI    D,FCBSIZE+UNGOT
  857.     DAD    D
  858.     MOV    M,A            ; if not LF, the next cgets it
  859. GETCNLF:
  860.     POP    H
  861.     POP    H
  862. GETCRET:
  863.     RET
  864. ;
  865. ;    cget(unit)
  866. ;
  867. CGET:
  868.     POP    D
  869.     POP    H
  870.     PUSH    H
  871.     PUSH    D
  872.     MOV    A,H            ; file or console ?
  873.     ORA    A
  874.     JNZ    CGET1            ; file
  875.     CALL    GETCHAR            ; console
  876.     POP    D
  877.     POP    D
  878.     RET
  879. CGET1:    SHLD    UNIT
  880.     LXI    D,FLAG            ; if(unit[FLAG]    & EOF_FL)
  881.     DAD    D
  882.     MOV    A,M
  883.     ANI    EOFFLG
  884.     JZ    GTCIF1
  885.     LXI    H,-1            ;    return(-1);
  886.     RET
  887. GTCIF1:
  888.     LHLD    UNIT            ; ip = unit + FCBSIZE;
  889.     LXI    D,FCBSIZE
  890.     DAD    D
  891.     SHLD    IP
  892. ;
  893.     LXI    D,UNGOT            ; check for ungotten char
  894.     DAD    D
  895.     MOV    A,M
  896.     CPI    EOF            ; is it an end of file ?
  897.     JZ    GTCCON
  898.     MOV    B,A
  899.     MVI    A,EOF
  900.     MOV    M,A
  901.     MOV    L,B
  902.     MOV    H,0
  903.     RET                ; return with char in HL
  904. ;
  905. GTCCON:    LHLD    IP
  906.     LXI    D,NEXTP            ; cp = ip[NEXTP];
  907.     DAD    D
  908.     MOV    E,M
  909.     INX    H
  910.     MOV    D,M
  911.     XCHG
  912.     SHLD    CHP
  913.     LHLD    IP            ; if(ip[UNUSED]==0){
  914.     LXI    D,UNUSED
  915.     DAD    D
  916.     MOV    A,M
  917.     INX    H
  918.     ORA    M
  919.     JNZ    GTCIF2
  920. ;
  921. ; Mark beginning of each 128 byte segment of buffer with EOF to
  922. ; eliminate possible bogus read
  923. ;
  924.     LHLD    UNIT            ;  unit + FCBSIZE;
  925.     LXI    D,FCBSIZE + BUFFER
  926.     DAD    D
  927.     LXI    D,128
  928.     MVI     B,NSECTS
  929.     MVI    A,1AH
  930. SETEOF:
  931.     MOV    M,A            ; mark it with an EOF
  932.     DAD    D
  933.     DCR    B
  934.     JNZ    SETEOF
  935. ;
  936.     LXI    H,READ            ;if(cpmio(READ,unit)~=0)
  937.     PUSH    H
  938.     LHLD    UNIT
  939.     PUSH    H
  940.     CALL    CPMIO
  941.     POP    D
  942.     POP    D
  943.     MOV    A,H
  944.     ORA    L
  945.     JZ    GTCIF3
  946.     LDA    MAXSEC            ;# IS THIS THE FIRST READ
  947.     CPI    NSECTS            ;#
  948.     JNZ    GTCIF3            ;# NO, THERE'S CHARS IN THAT BUFFER
  949.                     ;# YES, GETOUTAHERE
  950.     LXI    H,-1            ;        return(-1);
  951.     RET
  952. GTCIF3:
  953.     LHLD    IP            ;    else {    ip[UNUSED] = BUFSIZ;
  954.     LXI    D,UNUSED
  955.     DAD    D
  956.     LXI    D,BUFSIZ
  957.     MOV    M,E
  958.     INX    H
  959.     MOV    M,D
  960.     LHLD    IP            ;        cp = &ip[BUFFER];
  961.     LXI    D,BUFFER
  962.     DAD    D
  963.     SHLD    CHP
  964.                     ;        }
  965.                     ;    }
  966. GTCIF2:
  967.     LHLD    IP            ; ip[UNUSED]--;
  968.     LXI    D,UNUSED
  969.     DAD    D
  970.     MOV    E,M
  971.     INX    H
  972.     MOV    D,M
  973.     DCX    D
  974.     MOV    M,D
  975.     DCX    H
  976.     MOV    M,E
  977.     LHLD    CHP            ; ip[NEXTP] = cp+1;
  978.     INX    H
  979.     XCHG
  980.     LHLD    IP
  981.     LXI    B,NEXTP
  982.     DAD    B
  983.     MOV    M,E
  984.     INX    H
  985.     MOV    M,D
  986.     LHLD    CHP            ; if(*cp==CTRL_Z){
  987.     MOV    A,M
  988.     ANI    7FH            ; /* mask parity in compare */
  989.     CPI    CTRLZ
  990.     JNZ    GTCIF4
  991.     LHLD    UNIT            ;    unit[FLAG] |= EOF_FL;
  992.     LXI    D,FLAG
  993.     DAD    D
  994.     MOV    A,M
  995.     ORI    EOFFLG
  996.     MOV    M,A
  997.     LXI    H,-1            ;    return(-1);
  998.     RET
  999.                     ;    }
  1000. GTCIF4:
  1001.     MOV    A,M
  1002.     MOV    L,A            ; return(*cp & 0377);
  1003.     MVI    H,0
  1004.     RET
  1005.  
  1006. ;
  1007. ;    getchar()
  1008. ;
  1009. GETCHAR::
  1010. GETCHR1:            ; } else { /* read from    console    */
  1011.     MVI    C,GETCH            ; t = cpm(GETCH,0) & 0377;
  1012.     CALL    CBDOS        ; (mod to cbdos(fas))
  1013.     MOV    L,A        
  1014.     MVI    H,0
  1015.     ANI    7FH            ; /* mask parity in compare */
  1016.     CPI    CTRLZ            ; if(t==CTRLZ)
  1017.     JNZ    GET1CHAR
  1018.     LXI    H,-1            ;    t = -1;
  1019. GET1CHAR:
  1020.     CPI    EOL            ; if(t==EOL)
  1021.     JNZ    GET2CHAR
  1022.     PUSH    H            ;    putchar('\n');
  1023.     MVI    C,PUTCH
  1024.     MVI    E,LF
  1025.     CALL    CBDOS        ; (mod to cbdos(fas))
  1026.     POP    H
  1027. GET2CHAR:                ; return(t);
  1028.     RET            ; }
  1029.  
  1030. ;
  1031. ;    gets(buff)
  1032. ;
  1033. GETS::
  1034. GETS1:    POP    H        ; } else {
  1035.     SHLD    CHP
  1036.     DCX    H            ; save = buff[-1]; save2 = buff[-2];
  1037.     MOV    D,M            ; buff[-1] = 0;     buff[-2] = 79;
  1038.     MVI    M,0
  1039.     DCX    H
  1040.     MOV    E,M
  1041.     MVI    M,79                    ;6 May 80 rj
  1042.     PUSH    H
  1043.     PUSH    D
  1044.     XCHG                ; cpm(GETSTR,buff-2);
  1045.     MVI    C,GETSTR
  1046.     CALL    CBDOS        ; (mod to cbdos(fas))
  1047.     LHLD    CHP            ; buff[buff[-1]] = 0; (9 Jun 80. Was cp)
  1048.     DCX    H
  1049.     MOV    E,M
  1050.     INX    H
  1051.     MVI    D,0
  1052.     DAD    D
  1053.     MVI    M,0
  1054.     POP    D            ; buff[-1] = save; buff[-2] = save2;
  1055.     POP    H
  1056.     MOV    M,E
  1057.     INX    H
  1058.     MOV    M,D
  1059.     INX    H
  1060.     MVI    C,PUTCH            ; putchar('\n');
  1061.     MVI    E,LF
  1062.     CALL    CBDOS        ; (mod to cbdos(fas))
  1063.     LHLD    CHP            ; return(buff);
  1064.     RET            ; }
  1065. ;
  1066. ;    fgets(cp,len,unit)
  1067. ;
  1068. FGETS::
  1069.     INX    SP    ; skip rtn addr
  1070.     INX    SP
  1071.     POP    B    ; unit
  1072.     POP    D    ; length
  1073.     POP    H    ; cp
  1074.     PUSH    H
  1075.     PUSH    D
  1076.     PUSH    B
  1077.     DCX    SP
  1078.     DCX    SP
  1079. FGETS1:    SHLD    SVCHP        ;    save_cp    = cp;
  1080.     PUSH    D    ; keep stack right
  1081. FGETS2:    POP    D
  1082.     DCX    D        ;    while (--len) {
  1083.     PUSH    D
  1084.     MOV    A,D
  1085.     ORA    E
  1086.     JZ    FGETS4
  1087.     PUSH    H    ; save cp
  1088.     PUSH    B    ; unit
  1089.     CALL    GETC        ;        c =    getc(unit);
  1090.     POP    B
  1091.     MOV    A,H        ;        if(c==EOF) /* c>255    */
  1092.     ORA    A
  1093.     JZ    FGETS3
  1094.     POP    D    ; cp
  1095.     LHLD    SVCHP        ;          if (cp<>save_cp)
  1096.     XCHG            ;            /* read    something */
  1097.     MOV    A,H
  1098.     CMP    D
  1099.     JNZ    FGETS4        ;            goto fgets4;
  1100.     MOV    A,L
  1101.     CMP    E
  1102.     JNZ    FGETS4        ;          else
  1103.     LXI    H,0        ;            /* no characters */
  1104.     POP    D    ; fix stack
  1105.     RET            ;            return (NULL);
  1106. FGETS3:    MOV    A,L        ;        else {
  1107.     POP    H
  1108.     MOV    M,A        ;        *cp++ =    c;
  1109.     INX    H
  1110.     ANI    7FH        ;         /*    mask parity in compare */
  1111.     CPI    EOL        ;        if(c=='\n')
  1112.     JNZ    FGETS2
  1113. FGETS4:    MVI    M,0        ;            *cp='\0';
  1114.     POP    D    ; fix stack
  1115.     LHLD    SVCHP        ;            return save_cp;
  1116.     RET            ; }    }    }    }
  1117. ;
  1118. ;    putc(c,unit)
  1119. ;
  1120. FPUTC::
  1121. PUTC::
  1122.     POP    B    ;rtn addr
  1123.     POP    D    ;unit
  1124.     POP    H    ;c
  1125.     PUSH    H
  1126.     PUSH    D
  1127.     PUSH    B
  1128.     MOV    A,D
  1129.     ORA    A        ; if(unit < 256) {
  1130.     JNZ    PUTC4        ;    /* assume stdout, stderr */
  1131.     MOV    A,E
  1132.     CPI    STDOUT        ;    if(unit    == stdout) {
  1133.     JNZ    PUTC1
  1134.     PUSH    H
  1135.     CALL    PUTCHAR        ;        putchar(c);
  1136.     POP    H
  1137.     RET            ;        return;}
  1138. PUTC1:    CPI    STDERR        ;    elseif(unit == stderr) {
  1139.     JNZ    PUTC3
  1140.     CALL    PUTCON        ;        putconsole(c);
  1141.     RET            ;        return;}
  1142. PUTC3:    JMP    PTCER1        ;    else goto putcerr; }
  1143.  
  1144. PUTC4:    PUSH    H            ; if(cput(c,unit)<0)
  1145.     PUSH    D            ;    goto putcerr;
  1146.     CALL    CPUT
  1147.     POP    D
  1148.     MOV    A,H
  1149.     ORA    A
  1150.     JM    PUTCERR
  1151.     MOV    A,L            ; if(c=='\r')
  1152.     CPI    EOL
  1153.     JNZ    PUTCRET
  1154.     LXI    H,LF            ;    cput('\n',unit);
  1155.     PUSH    H
  1156.     PUSH    D
  1157.     CALL    CPUT
  1158.     POP    D
  1159.     POP    D
  1160.     MOV    A,H
  1161.     ORA    A
  1162.     JM    PUTCERR
  1163. PUTCRET:
  1164.     POP    H            ; return(c);
  1165.     RET
  1166. PUTCERR:                ;putcerr:
  1167.     POP    B            ; return(-1);
  1168. PTCER1:
  1169.     LXI    H,-1
  1170.     RET
  1171. ;
  1172. ;    cput(c,unit)
  1173. ;
  1174. CPUT::
  1175.     POP    B
  1176.     POP    D
  1177.     POP    H
  1178.     PUSH    H
  1179.     PUSH    D
  1180.     PUSH    B
  1181.     SHLD    ZCH
  1182.     XCHG
  1183.     SHLD    UNIT
  1184.     LXI    D,FCBSIZE        ; ip = unit + FCBSIZE;
  1185.     DAD    D
  1186.     SHLD    IP
  1187.     LXI    D,NEXTP            ; cp = ip[NEXTP];
  1188.     DAD    D
  1189.     MOV    E,M
  1190.     INX    H
  1191.     MOV    D,M
  1192.     XCHG
  1193.     SHLD    CHP
  1194.     LHLD    IP            ; if(ip[UNUSED]==0){
  1195.     LXI    D,UNUSED
  1196.     DAD    D
  1197.     MOV    A,M
  1198.     INX    H
  1199.     ORA    M
  1200.     JNZ    PTCIF1
  1201.     LXI    H,WRITE            ;    if(cpmio(WRITE,unit)~=0)    
  1202.     PUSH    H
  1203.     LHLD    UNIT
  1204.     PUSH    H
  1205.     CALL    CPMIO
  1206.     POP    D
  1207.     POP    D
  1208.     MOV    A,H
  1209.     ORA    L
  1210.     JZ    PTCIF2
  1211.     LXI    H,-1            ;        return(-1);
  1212.     RET
  1213. PTCIF2:
  1214.     LHLD    IP            ;    else {    ip[UNUSED] = BUFSIZ;
  1215.     LXI    D,UNUSED
  1216.     DAD    D
  1217.     LXI    D,BUFSIZ
  1218.     MOV    M,E
  1219.     INX    H
  1220.     MOV    M,D
  1221.     LHLD    IP            ;        cp = &ip[BUFFER];
  1222.     LXI    D,BUFFER
  1223.     DAD    D
  1224.     SHLD    CHP
  1225.                     ;        }
  1226.                     ;    }
  1227. PTCIF1:
  1228.     LHLD    IP
  1229.     LXI    D,UNUSED        ; ip[UNUSED]--;
  1230.     DAD    D
  1231.     MOV    E,M
  1232.     INX    H
  1233.     MOV    D,M
  1234.     DCX    D
  1235.     MOV    M,D
  1236.     DCX    H
  1237.     MOV    M,E
  1238.     LHLD    CHP            ; ip[NEXTP] = cp+1;
  1239.     INX    H
  1240.     XCHG
  1241.     LHLD    IP
  1242.     LXI    B,NEXTP
  1243.     DAD    B
  1244.     MOV    M,E
  1245.     INX    H
  1246.     MOV    M,D
  1247.     LDA    ZCH            ; return((*cp =    c) & 0377);
  1248.     LHLD    CHP
  1249.     MOV    M,A
  1250.     MVI    H,0
  1251.     MOV    L,A
  1252.     RET
  1253. ;
  1254. ;    putchar(c)
  1255. ;
  1256. PUTCHAR::
  1257.     POP    B
  1258.     POP    H
  1259.     PUSH    H
  1260.     PUSH    B
  1261.     PUSH    H
  1262.     LHLD    RSTDOUT        ; if(rdstdout >= 256) {
  1263.     MOV    A,H        ;    /* stdout has been redirected */
  1264.     ORA    A
  1265.     JZ    PUTCHR1
  1266.     PUSH    H
  1267.     CALL    PUTC        ;    putc(c,    rdstdout);
  1268.     POP    B
  1269.     POP    B        ;    return;
  1270.     RET
  1271. PUTCHR1:            ; } else {
  1272.     POP    H
  1273. PUTCON:    SHLD    ZCH        ;    /* send to console */
  1274.     XCHG                ; cpm(PUTCH,c);
  1275.     MVI    C,PUTCH
  1276.     CALL    CBDOS        ; (mod fas)
  1277.     LDA    ZCH            ; if(c==EOL)
  1278.     ANI    7FH            ; /* mask parity in compare */
  1279.     CPI    EOL
  1280.     JNZ    PUTCHIF1
  1281.     MVI    E,LF            ;    cpm(PUTCH,LF);
  1282.     MVI    C,PUTCH
  1283.     CALL    CBDOS        ; (mod fas)
  1284. PUTCHIF1:
  1285.     LHLD    ZCH            ; return(c & 0377);
  1286.     MVI    H,0
  1287.     RET            ; }
  1288. ;
  1289. ;    puts(cp)
  1290. ;
  1291. PUTS::
  1292.     POP    B            ; get args
  1293.     POP    H
  1294.     PUSH    H
  1295.     PUSH    B
  1296.     PUSH    H    ; cp
  1297.     LHLD    RSTDOUT
  1298.     PUSH    H
  1299.     CALL    FPUTS        ;    return (fputs(cp, rstdout));
  1300.     POP    B
  1301.     POP    B
  1302.     RET
  1303. ;
  1304. ;    fputs(cp,unit)
  1305. ;
  1306. FPUTS::
  1307.     POP    B
  1308.     POP    D    ; unit
  1309.     POP    H    ; cp
  1310.     PUSH    H
  1311.     PUSH    D
  1312.     PUSH    B
  1313. FPUTS1:    MOV    A,M        ; while((c=*cp++) <> NULL) {
  1314.     INX    H
  1315.     ORA    A
  1316.     JZ    FPUTS3
  1317.     PUSH    H
  1318.     MOV    C,A
  1319.     MVI    B,0
  1320.     PUSH    B
  1321.     PUSH    D
  1322.     CALL    PUTC        ;    if(putc(c,unit)==EOF)
  1323.     POP    D
  1324.     POP    B
  1325.     MOV    A,H
  1326.     ORA    A
  1327.     JZ    FPUTS2
  1328.     POP    B
  1329.     RET            ;        return(EOF);
  1330. FPUTS2:    POP    H
  1331.     JMP    FPUTS1        ; }
  1332. FPUTS3:    LXI    H,0
  1333.     RET            ; return(NULL);
  1334. ;
  1335. ;    cpmio(fn,unit)
  1336. ;
  1337. CPMIO:
  1338.     POP    B
  1339.     POP    D
  1340.     POP    H
  1341.     SHLD    FN
  1342.     XCHG
  1343.     SHLD    UNIT
  1344.     PUSH    D
  1345.     PUSH    H
  1346.     PUSH    B
  1347.     LHLD    UNIT            ; cpmdisk(*unit);
  1348.     MOV    L,M
  1349.     MVI    H,0
  1350.     PUSH    H
  1351.     CALL    CPMDISK
  1352.     POP    H
  1353.     LHLD    UNIT            ; ip = unit+FCBSIZE;
  1354.     LXI    D,FCBSIZE        ; cpm(DMA,&ip[BUFFER]);
  1355.     DAD    D
  1356.     LXI    D,BUFFER
  1357.     DAD    D
  1358.     SHLD    NUBUFF        ;# SAVE TO UPGRADE DURING LOOPING
  1359.     XCHG
  1360.     MVI    C,DMA
  1361.     CALL    CBDOS        ; (mod fas)
  1362.     LHLD    FN            ; t = cpm(fn,unit);
  1363.     MOV    C,L
  1364.     MVI    A,NSECTS    ;# READ/WRITE UP TO NSECT SECTORS
  1365.     STA    MAXSEC        ;# SAVE IT
  1366.     LHLD    UNIT
  1367.     XCHG
  1368. IOLOOP:    PUSH    H        ;# NEW CONSTRUCT TO ACCOMODATE 1K BUFFERS
  1369.     PUSH    D        ;# SAVE IT ALL FOR REPEAT PERFORMANCE
  1370.     PUSH    B
  1371. ;
  1372.     PUSH    H        ;# DON'T WRITE BLANKS
  1373.     MOV    A,C
  1374.     CPI    READ
  1375.     POP    H
  1376.     JZ    NOWRIT
  1377.     PUSH    H
  1378.     LHLD    NUBUFF
  1379.     MOV    A,M
  1380.     POP    H
  1381.     CPI    1AH        ;# END OF FILE CHAR ?
  1382.     JZ    IOEXIT
  1383. ;
  1384. NOWRIT:
  1385.     CALL    CBDOS        ;# READ/WRITE A SECTOR
  1386.     PUSH    PSW
  1387.     CALL    CCSXT
  1388.     SHLD    ZT
  1389.     POP    PSW
  1390.     ORA    A        ;# CHECK FOR LAST SECTOR
  1391.     JNZ    IOEXIT        ;# IF LAST GET OUT OF HERE
  1392.     LDA    MAXSEC
  1393.     DCR    A        ;# CHECK FOR 8 SECTORS DONE
  1394.     JZ    IOEXIT
  1395.     STA    MAXSEC
  1396.     LHLD    NUBUFF        ;# GET BUFFER ADDRESS
  1397.     LXI    D,128
  1398.     DAD    D        ;# COMPUTE NEW BUFFER ADDRESS
  1399.     SHLD    NUBUFF        ;# SAVE TIL NEXT TIME
  1400.  
  1401.     XCHG
  1402.     MVI    C,DMA
  1403.     CALL    CBDOS        ;# SET THE NEW BUFFER
  1404.     POP    B
  1405.     POP    D
  1406.     POP    H
  1407.     JMP    IOLOOP
  1408. IOEXIT:    POP    B        ;# CLEAN UP
  1409.     POP    D
  1410.     POP    H
  1411.     MVI    C,DMA            ; cpm(DMA,TBUFF);
  1412.     LXI    D,ZZBUF
  1413.     CALL    CBDOS        ; (mod fas)
  1414.     LHLD    ZT            ; if(t~=0) return(-1);
  1415.     MOV    A,H            ; else       return(0);
  1416.     ORA    L
  1417.     JNZ    CPMIF1
  1418.     LXI    H,0
  1419.     JMP    CPMIF2
  1420. CPMIF1:
  1421.     LXI    H,-1
  1422. CPMIF2:
  1423.     RET
  1424. ;
  1425. ;    cpmdisk(disk)
  1426. ;
  1427. CPMDISK:
  1428.     POP    D
  1429.     POP    H
  1430.     PUSH    H
  1431.     PUSH    D
  1432.     MOV    A,L            ; if(d~=0)
  1433.     ORA    H
  1434.     JZ    DISKIF1
  1435.     XCHG                ;    cpm(SELECT,d-1);
  1436.     DCX    D
  1437.     MVI    C,SELECT
  1438.     CALL    CBDOS        ; (mod fas)
  1439. DISKIF1:
  1440.     RET
  1441. ;
  1442.     END    ULINK    
  1443.  
  1444.