home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / misc / smc203.ark / IOLIB.ASM < prev    next >
Encoding:
Assembly Source File  |  1983-07-28  |  25.1 KB  |  1,413 lines

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