home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / basic / b-compil.lbr / BCBCLIB.SQC / BCBCLIB.SRC
Encoding:
Text File  |  1986-07-20  |  17.5 KB  |  459 lines

  1. 1
  2.     ;PRINT A STRING: DE CONTAINS LENGTH (0-65535), HL POINTS TO STRING,
  3.     ;BC CONTAINS BDOS FUNCTION CALL VALUE (2=CONSOLE, 5=LIST DEVICE)
  4. PSTR:    MOV    A,D! ORA A! JNZ PLOOP! MOV A,E! ORA A! RZ
  5. PLOOP:    PUSH    D! PUSH B! MOV E,M! PUSH H! PUSH PSW
  6.     CALL    0005H
  7.     POP    PSW! POP H! POP B! POP D! INX H! DCX D! MOV A,E! ORA A
  8.     JNZ    PLOOP
  9.     MOV    A,D! ORA A! JNZ PLOOP
  10.     RET
  11. PLNE:    PUSH    B! MVI E,13
  12.     CALL    0005! POP B! PUSH B! MVI E,10
  13.     CALL    0005! POP B! RET
  14. 2
  15.     ;PRINT A NUMBER: HL CONTAINS NUMBER, OUTPUT IS TO SAREA (IN MEMORY),
  16.     ;THEN SAREA IS READ AND OUTPUT TO CONSOLE OR LIST DEVICE.
  17. PNUM:    LXI    D,SAREA! PUSH B! MOV A,H! ANI 080H
  18.     JZ    PNUM2
  19.     MOV    A,H! CMA! MOV H,A! MOV A,L! CMA! MOV L,A! INX H
  20.     MVI    A,'-'
  21.     STAX    D
  22.     JMP    PNUM3
  23. PNUM2:    MVI    A,'+'
  24.     STAX    D
  25. PNUM3:    INX    D
  26.     LXI    B,-10000! CALL DECDIG
  27.     LXI    B,-1000! CALL DECDIG
  28.     LXI    B,-100! CALL DECDIG
  29.     LXI    B,-10! CALL DECDIG
  30.     MOV    A,L! ORI '0'! STAX D
  31.     LXI    D,0006H! LXI H,SAREA
  32.     POP    B! JMP PSTR
  33. 3
  34. DECDIG:    MVI    A,'0'-1
  35. DECLP:    INR    A
  36.     DAD    B! JC DECLP
  37.     STAX    D! INX D
  38.     MOV    A,B! CMA
  39.     MOV    B,A! MOV A,C! CMA
  40.     MOV    C,A! INX B! DAD B! RET
  41. 4
  42.     ;ARITHMETIC ROUTINES
  43.     ;HL = MOST RECENT OPERAND, DE = OLDEST OPERAND, A = OPCODE
  44.     ;A=1 IS +; A=2 IS -; A=3 IS *; A=4 IS /; A=5 IS AND;
  45.     ;A=6 IS OR; A=7 IS NOT; A=8 IS XOR; A=9 IS MOD
  46.     ;INTEGER ADDITION
  47. 5
  48. ARITH:    DAD    D! RET
  49. 6
  50.     ;INTEGER SUBTRACTION
  51. ARITH2:    MOV    A,H! CMA! MOV H,A
  52.     MOV    A,L! CMA! MOV L,A! INX H! DAD D! RET
  53. 7
  54.     ;INTEGER MULTIPLICATION
  55. ARITH3:    LXI    B,0000H
  56.     ;PROCEDURE USED: OBTAIN (D*L+H*E) AS HIGH BYTE OF RESULT, THEN ADD L*E
  57.     ;AS 16-BIT NUMBER TO THAT ANSWER. OVERFLOW IS NOT CHECKED. MULT ROUTINE
  58.     ;RETURNS ANSWERS IN BC, WITH D AND C ORIGINALLY HOLDING THE TWO BYTES
  59.     ;WHICH ARE TO BE MULTIPLIED.
  60.     ;MULTIPLY D AND L NOW
  61.     MOV    C,L
  62.     CALL    MULT
  63.     PUSH    B! LXI B,0000H
  64.     ;MULTIPLY H AND E NOW
  65.     MOV    C,H! MOV D,E
  66.     CALL    MULT! PUSH B! LXI B,0000H
  67.     ;MULTIPLY L AND E NOW
  68.     MOV    C,L! CALL MULT
  69.     ;ANSWER COMES BACK IN BC; NOW POP H TO RESTORE H*E IN H,THEN SHL 1 BYTE
  70.     POP    H! MOV H,L! MVI L,00H! DAD B
  71.     ;INTERMEDIATE RESULT IN HL. NOW POP D AND SHL 1 BYTE FOR NEXT
  72.     POP    D! MOV D,E! MVI E,00H! DAD D
  73.     ;THAT'S IT, FOLKS. WE NOW HAVE OUR ANSWER IN HL.
  74.     RET
  75.     ;AND HERE'S THE ROUTINE TO DO THE MULTIPLICATION:
  76. MULT:    PUSH    D! MVI E,09
  77. MULT0:    MOV    A,C! RAR! MOV C,A! DCR E! JZ MULT2
  78.     MOV    A,B! JNC MULT1
  79.     ADD    D
  80. MULT1:    RAR! MOV B,A! JMP MULT0
  81. MULT2:    POP    D! RET
  82.     ;HL = MOST RECENT OPERAND, DE = OLDEST OPERAND, A = OPCODE
  83.     ;A=1 IS +; A=2 IS -; A=3 IS *; A=4 IS /; A=5 IS AND;
  84.     ;A=6 IS OR; A=7 IS NOT; A=8 IS XOR
  85. 8
  86.     ;INTEGER DIVISION
  87. ARITH4:    MOV    A,H! ANI 080H! MOV B,A! MOV A,D! ANI 080H
  88.     ;B HAS SIGN OF HL, A HAS SIGN OF DE
  89.     CMP    B! JZ DS0!
  90.     ;IF WE TOOK THE JUMP TO DS0, THEN DE & HL HAVE THE SAME SIGN. IF NOT,
  91.     ;DE AND HL HAVE DIFFERENT SIGNS. WE'LL NEED TO FIND OUT WHICH NUMBER
  92.     ;IS NEGATIVE SO WE CAN CONVERT IT APPROPRIATELY
  93.     MVI    B,080H
  94.     RAL! JNC DSA
  95.     ;WE TOOK THAT LAST JUMP IF DE WAS POSITIVE. IF NOT, HL IS.
  96.     DCX    D! MOV A,D! CMA! MOV D,A! MOV A,E! CMA! MOV E,A
  97.     JMP    DS2
  98. DSA:    DCX    H! MOV A,H! CMA! MOV H,A! MOV A,L! CMA! MOV L,A
  99.     JMP    DS2
  100. DS0:    ORA    A! JZ DSTART
  101.     ;DE AND HL HAVE THE SAME SIGN: NEGATIVE
  102.     DCX    D! MOV A,D! CMA! MOV D,A! MOV A,E! CMA! MOV E,A
  103.     DCX    H! MOV A,H! CMA! MOV H,A! MOV A,L! CMA! MOV L,A
  104. DSTART:    LXI    B,0
  105. DS2:    PUSH    B! LXI B,0
  106.     ;AT THIS POINT, WE'VE PUSHED THE SIGN OF THE RESULT ONTO THE STACK,
  107.     ;CLEARED THE BC REGISTER TO RECEIVE THE RESULT, AND KILLED THE SIGN BIT
  108.     ;ON THE DE AND HL REGISTERS (DE WILL BE DIVIDED BY HL). WE CAN NOW
  109.     ;CONTINUE UNDER THE ASSUMPTION THAT DE AND HL ARE BOTH POSITIVE.
  110.     MOV    B,D! MOV C,E! XCHG
  111.     ;BC=DIVIDEND AND QUOTIENT, DE=DIVISOR
  112.     MOV    A,D! CMA! MOV D,A! MOV A,E! CMA! MOV E,A! INX D
  113.     LXI    H,0! MVI A,17
  114. DV0:    PUSH    H! DAD D! JNC DV1! XTHL
  115. DV1:    POP    H! PUSH PSW! MOV A,C! RAL! MOV C,A
  116.     MOV    A,B! RAL! MOV B,A! MOV A,L! RAL! MOV L,A
  117.     MOV    A,H! RAL! MOV H,A! POP PSW! DCR A! JNZ DV0
  118.     ORA    A! MOV A,H! RAR! MOV D,A! MOV A,L! RAR! MOV E,A
  119.     ;DE NOW CONTAINS REMAINDER, BC CONTAINS QUOTIENT. WE'LL FIX THINGS
  120.     ;UP NOW, AND PUT THE (POSSIBLY) SIGNED RESULT INTO HL. REMEMBER THAT
  121.     ;THE REMAINDER IS RETURNED IN DE; WE MAY WANT TO USE IT LATER, EITHER
  122.     ;TO RETURN THE REMAINDER OR TO FACILITATE MULTIPLE PRECISION DIVISION.
  123.     POP    H! MOV A,H! ORA A! JNZ DV2
  124.     LXI    H,0
  125.     DAD    B
  126.     RET
  127. DV2:    MOV    A,B! CMA! MOV H,A! MOV A,C! CMA! MOV L,A! INX H! RET
  128. 9
  129.     ;LOGICAL AND
  130. ARITH5:    MOV    A,H! ANA D! MOV H,A! MOV A,L! ANA E! MOV L,A
  131.     RET
  132. 10
  133.     ;LOGICAL OR
  134. ARITH6:    MOV    A,H! ORA D! MOV H,A! MOV A,L! ORA E! MOV L,A
  135.     RET
  136. 11
  137.     ;LOGICAL NEGATION OF HL
  138. ARITH7║    MOV    A,H! CMA! MOV H,A! MOV A,L! CMA! MOV L,A
  139.     RET
  140. 12
  141.     ;LOGICAL XOR
  142. ARITH8:    MOV    A,H! XRA D! MOV H,A! MOV A,L! XRA E! MOV L,A
  143.     RET
  144. 13
  145.     ;RETURN REMAINDER OF DIVISION (MOD OPERATION)
  146. ARITH9:    CALL    ARITH4! XCHG! RET
  147. 14
  148.     ;GET A NUMBER AS INPUT FROM THE CONSOLE
  149. GETNUM:    LXI    D,SAREA! LXI H,0000H! LXI B,0
  150. IPLP:    PUSH    B! MVI C,01H! PUSH D! PUSH H! CALL 0005H
  151.     POP    H! POP D! POP B! STAX D! INX D! INX H! INX B
  152.     CPI    13! JZ IPDONE! CPI 10! JZ IPDONE! CPI 3! JZ 0000H
  153.     CPI    8! CZ IPBS
  154.     JMP    IPLP
  155. IPBS:    DCX    B! DCX B! MOV A,B! RAL! JC IPBS2
  156.     DCX    H! DCX H! DCX D! DCX D! PUSH D! PUSH H! PUSH B! MVI C,2
  157.     MVI    E,32! CALL 0005H! MVI C,2! MVI E,8! CALL 0005H
  158.     POP    B! POP H! POP D! RET
  159. IPBS2:    INX    B! DCX H! DCX D! PUSH B! PUSH D! PUSH H! MVI C,2! MVI E,32
  160.     CALL    0005H! POP H! POP D! POP B! RET
  161. IPDONE:    LXI    D,SAREA! LXI H,0000H! PUSH H!
  162. IP2:    LDAX    D! INX D! CPI '-'! JZ IP3
  163.     CPI    '0'! JC IPST! CPI '9'+1! JNC IP2
  164.     SUI    '0'! MOV B,H! MOV C,L! DAD H! DAD H! DAD B
  165.     DAD    H! ADD L! MOV L,A! JMP IP2
  166. IP3:    POP    B! INX B! PUSH B! JMP IP2
  167. IPST:    POP    B! MOV A,C! ORA A! JZ IPST2
  168.     MOV    A,H! CMA! MOV H,A! MOV A,L! CMA! MOV L,A
  169.     INX    H
  170. IPST2:    PUSH    H! MVI E,10! MVI C,2! CALL 0005H
  171.     MVI    E,13! MVI C,2! CALL 0005H! POP H! RET
  172. 15
  173.     ;GET A STRING AS INPUT FROM THE CONSOLE, INTO A STRING'S LOCATION.
  174.     ;DE POINTS TO STRING LOCATION, HL CONTAINS BYTE COUNT (LENGTH).
  175. GETSTR:    LXI    H,0! LXI B,0
  176. STRLP:    PUSH    B! MVI C,01H! PUSH D! PUSH H! CALL 0005H
  177.     POP    H! POP D! POP B! CPI 13! JZ SQUIT! CPI 3! JZ 0000H
  178.     STAX    D! INX D! INX H! INX B! CPI 8! CZ SBS! JMP STRLP
  179. SQUIT:    MVI    E,10! MVI C,2! PUSH H
  180.     CALL    0005H! POP H! RET
  181. SBS:    DCX    B! DCX B! MOV A,B! RAL! JC SBS2
  182.     DCX    D! DCX D! DCX H! DCX H! PUSH B! PUSH D! PUSH H! MVI C,2!
  183.     MVI    E,32! CALL 0005H! MVI C,2! MVI E,8! CALL 0005H
  184.     POP    H! POP D! POP B! RET
  185. SBS2:    INX    B! DCX D! DCX H! PUSH B! PUSH D! PUSH H! MVI C,2! MVI E,32
  186.     CALL    0005H! POP H! POP D! POP B! RET
  187. 16
  188.     ;RESERVED FOR STRING COMPARISONS; <, <=, =, >, >=, <>
  189.     ;IF V2$='=' THEN K3=1
  190.     ;IF V2$='<>' OR V3$='><' THEN K3=2
  191.     ;IF V2$='=<' OR V2$='<=' THEN K3=3
  192.     ;IF V2$='>=' OR V2$='=>' THEN K3=4
  193.     ;IF V2$='<' THEN K3=5:ELSE IF V2$='>' THEN K3=6
  194.     ;K3 PARAMETER IS PASSED IN THE A REGISTER
  195.     ;DE=POINTER TO FIRST STRING'S POINTER, HL=POINTER TO SECOND STRING'S
  196.     ;RETURN 0 IN A REGISTER IF COMPARISON IS FALSE, ANYTHING ELSE IF TRUE.
  197.  
  198.     ;CHECK FOR STRING EQUALITY
  199. SC:    PUSH    D! PUSH H! INX H! INX H! INX D! INX D
  200.     ;FIRST, LET'S COMPARE THE STRING LENGTHS. IF THEY'RE NOT EQUAL, QUIT.
  201.     LDAX    D! MOV C,M! CMP C! JNZ SNE
  202.     INX    H! INX D! LDAX D! MOV B,M! CMP B! JNZ SNE
  203.     POP    H! POP D! PUSH B! MOV C,M! INX H! MOV B,M
  204.     LXI    H,0! DAD B! PUSH H! LDAX D! MOV L,A! INX D
  205.     LDAX    D! MOV H,A! XCHG! POP H! POP B
  206.     ;NOW HL POINTS TO THE BEGINNING OF THE SECOND STRING, DE POINTS TO
  207.     ;THE BEGINNING OF THE FIRST, AND BC CONTAINS THE STRING LENGTHS
  208. SC2:    MOV    A,B! ORA A! JNZ SC3
  209.     MOV    A,C! ORA A! JZ SEQ
  210. SC3:    PUSH    B! MOV B,M! LDAX D! CMP B! JNZ SNE2
  211.     POP    B! DCX B! INX H! INX D! JMP SC2
  212. SEQ:    MVI    A,0FFH! RET
  213. SNE:    POP    B
  214. SNE2:    POP    B! MVI A,0! RET
  215. 17
  216.     ;NOW A COMPARISON FOR UNEQUAL STRINGS
  217. SC4:    CALL    SC! CMA! RET
  218. 18
  219.     ;NOW A COMPARISON FOR <: (DE < HL)
  220.     ;PROCEDURE USED: GET THE STRING LENGTH OF DE AND STORE IT AT SAREA,
  221.     ;THEN GET THE STRING LENGTH OF HL AND STORE IN SAREA+2. WE WILL USE
  222.     ;THESE LENGTHS TO TELL US WHEN WE ARE DONE. THEN RETRIEVE THE
  223.     ;CHARACTERS IN EACH STRING, ONE AT A TIME. IF THE CHARACTERS ARE THE
  224.     ;SAME, DECREMENT THE LENGTHS STORED IN SAREA AND CHECK TO SEE IF
  225.     ;EITHER STRING IS ENDED. IF ONE IS AND THE OTHER IS NOT, THE ONE THAT
  226.     ;ISN'T DONE IS BIGGER. IF THE CHARACTERS DIFFER, THE STRING CONTAINING
  227.     ;THE SMALLER IS LESS. THE CHECK FOR COMPLETION IS DONE AT THE BEGINNING
  228.     ;OF THE LOOP, FOR OBVIOUS REASONS.
  229. SC5:    PUSH    D! PUSH H! INX H! INX H! INX D! INX D
  230.     ;FIRST, GET THE STRING LENGTHS INTO SAREA AND SAREA+2.
  231.     LDAX    D! MOV C,A! INX D! LDAX D! MOV B,A! PUSH B
  232.     MOV    C,M! INX H! MOV B,M! LXI H,0! DAD B
  233.     SHLD    SAREA+2! POP H! SHLD SAREA
  234.     ;THAT PUTS THE LENGTH OF DE INTO SAREA AND LENGTH OF HL INTO SAREA+2
  235.     ;OK, LENGTHS ARE STORED. NOW GET THE STRING ADDRESSES INTO DE & HL
  236.     POP    H! POP D! MOV C,M! INX H! MOV B,M
  237.     LXI    H,0! DAD B! PUSH H! LDAX D! MOV L,A! INX D
  238.     LDAX    D! MOV H,A! XCHG! POP H
  239.     ;NOW HL POINTS TO THE BEGINNING OF THE SECOND STRING, DE POINTS TO
  240.     ;THE BEGINNING OF THE FIRST. NOW WE CHECK FOR COMPLETION.
  241. SC6:    PUSH    D! PUSH H! LHLD SAREA! XCHG! LHLD SAREA+2
  242.     ;NOW DE CONTAINS THE NUMBER OF BYTES LEFT IN STRING POINTED TO BY DE
  243.     ;AND HL CONTAINS THE NUMBER OF BYTES LEFT IN STRING POINTED TO BY HL
  244.     ;IF DE IS 0 AND HL IS NOT, RETURN TRUE; IF HL IS 0 AND DE IS NOT,
  245.     ;RETURN FALSE; IF NEITHER IS 0, CONTINUE COMPARISON; IF BOTH ARE 0,
  246.     ;RETURN FALSE, BECAUSE STRINGS ARE THEN EQUAL. THE HL REGISTER IS THE
  247.     ;MOST IMPORTANT ONE; IF IT IS 0, ALWAYS RETURN FALSE.
  248.     MOV    A,H! CMP L! JNZ SC6A
  249.     ORA    A! JZ SLTF
  250.     ;OK, HL IS NON-ZERO. NOW WE CHECK DE.
  251. SC6A:    MOV    A,D! CMP E! JNZ SC7
  252.     ORA    A! JZ SLTT
  253.     ;OK, DE IS NON-ZERO. LET'S CHECK THE CHARACTERS.
  254. SC7:    POP    H! POP D! LDAX D! MOV B,M
  255.     INX    H! INX D! PUSH H
  256.     LHLD    SAREA+2! DCX H! SHLD SAREA+2! LHLD SAREA
  257.     DCX    H! SHLD SAREA! POP H
  258.     CMP    B! JC SLTT2! JNZ SLTF2
  259.     JMP    SC6
  260. SLTT:    POP    B! POP B
  261. SLTT2:    MVI    A,0FFH! RET
  262. SLTF:    POP    B! POP B
  263. SLTF2:    MVI    A,0! RET
  264. 19
  265.     ;NOW WE CHECK FOR >=
  266. SC8:    CALL SC5! CMA! RET
  267. 20
  268.     ;THE ONLY TWO THINGS LEFT ARE > AND <=. LET'S TAKE <= FIRST.
  269.     ;WE CAN CHECK FOR <= BY TESTING FOR <; IF TRUE, THEN RETURN TRUE.
  270.     ;THEN WE CAN TEST FOR EQUALITY. IF TRUE, RETURN TRUE.
  271.     ;OTHERWISE, RETURN FALSE. HERE WE GO.
  272. SC9:    CALL    SC5
  273.     ORA    A! RNZ
  274.     CALL    SC! RET
  275. 21
  276.     ;OK, NOW WE'LL CHECK FOR >
  277. SCA:    CALL    SC9! CMA! RET
  278.     ;INVALID OPCODES ARE IGNORED
  279. 22
  280.     ;RESERVED FOR NUMERIC COMPARISONS; <, <=, =, >, >=, <>
  281.     ;FIRST ARGUMENT IS IN DE, LAST ONE IN HL: RETURN 0=FALSE, -1=TRUE IN A
  282.     ;NUMERIC EQUALITY
  283. NC:    MOV    A,H! CMP D! JNZ NNE
  284.     MOV    A,L! CMP E! JNZ NNE
  285. NEQ:    MVI    A,0FFH! RET
  286. NNE:    MVI    A,00H! RET
  287. 23
  288.     ;NUMERIC INEQUALITY
  289. NC1:    CALL    NC! CMA! RET
  290. 24
  291.     ;NUMERIC <
  292.     ;FIRST, LET'S LOOK AT THE SIGNS. IF DE IS NEGATIVE AND HL IS POSITIVE,
  293.     ;RETURN TRUE. IF DE AND HL ARE BOTH NEGATIVE, COMPLEMENT ALL BITS IN
  294.     ;BOTH AND COMPARE; IF DE IS POSITIVE AND HL IS NEGATIVE, RETURN FALSE;
  295.     ;IF BOTH ARE POSITIVE, COMPARE.
  296. NC2:    MOV    A,D! ANI 080H! MOV B,A! MOV A,H! ANI 080H
  297.     CMP    B! JC NEQ
  298.     ;THAT TAKES CARE OF THE CASE DE NEGATIVE AND HL POSITIVE.
  299.     ;B CONTAINS SIGN OF DE, AND A CONTAINS SIGN OF HL
  300.     ;THE LAST CHECK JUMPS TO THE 'RETURN TRUE' ROUTINE. NOW LET'S CHECK
  301.     ;TO SEE IF DE POSITIVE AND HL NEGATIVE, FOR WHICH WE RETURN FALSE.
  302.     MOV    C,A! MOV A,B! CMP C! JC NNE
  303.     ;WE HAVE LEFT THE SIGN OF DE IN A.
  304.     ;THE A REGISTER NOW CONTAINS 128 ONLY IF HL AND DE ARE BOTH NEGATIVE,
  305.     ;AND 0 ONLY IF BOTH ARE POSITIVE. LET'S SEE WHICH IS TRUE.
  306.     ORA    A! JZ NC2A
  307.     MOV    A,D! CMA! MOV D,A! MOV A,E! CMA! MOV E,A
  308.     MOV    A,H! CMA! MOV H,A! MOV A,L! CMA! MOV L,A
  309.     ;NOW WE HAVE TWO UNSIGNED NUMBERS TO COMPARE. IF D<H, WE'RE DONE:
  310.     ;RETURN TRUE. IF H<D, WE'RE DONE: RETURN FALSE.
  311. NC2A:    MOV    A,D! CMP H! JC NEQ! JNZ NNE
  312.     ;IF E<L, RETURN TRUE. IF NOT, THEN EITHER DE=HL, OR L<E: RETURN FALSE.
  313.     MOV    A,E! CMP L! JC NEQ! MVI A,0! RET
  314.     ;IF V2$='=' THEN K3=1
  315.     ;IF V2$='<>' OR V3$='><' THEN K3=2
  316.     ;IF V2$='=<' OR V2$='<=' THEN K3=3
  317.     ;IF V2$='>=' OR V2$='=>' THEN K3=4
  318.     ;IF V2$='<' THEN K3=5:ELSE IF V2$='>' THEN K3=6
  319. 25
  320.     ;NUMERIC >=
  321. NC3:    CALL    NC2! CMA! RET
  322. 26
  323.     ;NUMERIC >
  324. NC4:    XCHG! JMP NC2
  325. 27
  326.     ;NUMERIC <=
  327. NC5:    CALL    NC4! CMA! RET
  328. 28
  329.     ;RESERVED FOR POKE AND PEEK, INCLUDING USE OF POKE, PEEK, AND VARPTR
  330. 29
  331.     ;RESERVED FOR RANDOM FILE I/O; OPEN, CLOSE, LSET, RSET, GET, AND PUT
  332.     ;FOR OPEN STATEMENT, DE POINTS TO PROPOSED FCB, HL POINTS TO THE FILE
  333.     ;NAME TO USE FOR THE PROPOSED OPEN FILE, AND B CONTAINS THE LENGTH OF
  334.     ;THE PROPOSED FILE NAME. THIS ROUTINE WILL PARSE THE PROPOSED FILE
  335.     ;NAME. IF THE FILE DOES NOT EXIST, IT WILL BE CREATED BY THIS ROUTINE.
  336.     ;THE FIRST THING WE DO IS FILL OUT THE NAME PART OF THE PROPOSED FCB
  337.     ;AFTER THE DRIVE LETTER WITH BLANKS, AND THE REST OF THE FCB WITH 0s.
  338.     ;THEN WE CHECK TO SEE IF THE FILE NAME INCLUDES A DRIVE LETTER.
  339. ROPEN:    xchg!    shld SAREA! xchg! shld SAREA+2! push b! mvi b,36! mvi a,0
  340. ROPEN1:    stax d! inx d! dcr b! cmp b! jnz ROPEN1! lhld SAREA! xchg! inx d
  341.     mvi    b,11
  342. ROPEN2:    mvi    a,32! stax d! inx d! dcr b! mov a,b! ora a! jnz ROPEN2
  343.     lhld    SAREA! xchg! lhld SAREA+2! pop b
  344.     ;Now, we have set up the fcb. Does the name specify a drive letter?
  345.     inx    h! mov a,m! dcx h! cpi ':'! jnz ROPEN3
  346.     ;If not, we go to ROPEN3. Otherwise, we must perform the next line,
  347.     ;which just puts the specified drive letter into the fcb.
  348.     mov    a,m! sui 64! stax d! inx h! inx h! dcr b! dcr b
  349.     ;Now we move the file name into the fcb until we get a period.
  350.     ;If we get a period, we will advance to the file type area and put
  351.     ;the remaining characters beginning there. I do not check to see if
  352.     ;there are only three characters to go into the fcb at this point.
  353. ROPEN3:    inx    d! mov a,b! ora a! jz ROPEN6! mov a,m! cpi '.'! cz ROPEN4
  354.     stax    d! dcr b! inx h! jmp ROPEN3
  355.     ;If we hit here, there is a file type extension. I will return only if
  356.     ;there is at least one character after the period.
  357. ROPEN4:    push    h! lhld SAREA! lxi d,9! dad d! xchg! pop h! inx h
  358.     dcr    b! mov a,b! ora a! jz ROPEN5! mov a,m! ret
  359.     ;If the file name was given with a period and no letters following, we
  360.     ;will not return. Destroy the return address and continue.
  361. ROPEN5:    pop    h
  362.     ;At last, we are ready to open the file. We'll restore the DE register
  363.     ;pointer to the fcb and continue.
  364. ROPEN6:    lhld    SAREA! XCHG
  365.     MVI    C,15! PUSH D! CALL 0005
  366.     ;IF THE FILE DOES NOT EXIST, WE WILL CREATE IT. OTHERWISE, DONE.
  367.     POP    D! INR A! ORA A! JZ FCREAT! RET
  368. FCREAT:    MVI    C,22! CALL 0005! INR A! ORA A! RNZ
  369.     ;WE CANNOT CREATE THE FILE. NO SPACE IS AVAILABLE. ABORT.
  370.     MVI    C,9! LXI D,FERR! CALL 0005! JMP 0
  371. FERR:    DB    'FILE CREATION ERROR: NO DIRECTORY SPACE AVAILABLE.',13,10,'$'
  372.     ;ROUTINE TO GET A RANDOM RECORD. ON ENTRY, HL=RECORD NUMBER,
  373.     ;DE POINTS TO FCB, BC POINTS TO DMA.
  374. RGET:    PUSH    B! PUSH D! PUSH H! MOV H,B! MOV L,C! SHLD SAREA
  375.     POP    H! POP D! POP B! PUSH B! PUSH D! PUSH H
  376.     LXI    H,33! DAD D! XCHG! POP H
  377.     ;NOW HL CONTAINS THE RECORD NUMBER, DE POINTS TO WHERE TO PUT IT.
  378.     MOV    A,L! STAX D! INX D! MOV A,H! STAX D! INX D
  379.     MVI    A,0! STAX D! POP B! POP D
  380.     ;NOW BC POINTS TO FCB, DE POINTS TO DMA. FIRST THING WE DO IS
  381.     ;SET THE DMA ADDRESS APPROPRIATELY.
  382.     PUSH    B! MVI C,26! CALL 0005
  383.     ;NOW WE RESTORE DE AS THE FCB, AND CALL FOR A RANDOM READ
  384.     POP    D! MVI C,33! CALL 0005! ORA A! JNZ GETERR
  385.     RET
  386.     ;IN KEEPING WITH MICROSOFT, WE WILL FILL THE DMA WITH NULLS ON ERROR.
  387.     ;AT SAREA, WE HAVE SAVED THE DMA FOR THIS EVENTUALITY.
  388. GETERR:    LHLD    SAREA! MVI B,128
  389. GETER1:    MVI    A,0! MOV M,A! DCR B! MOV A,B! ORA A! RZ! INX H! JMP GETER1
  390.     ;ROUTINE TO WRITE A RECORD. ON ENTRY, HL CONTAINS THE RECORD NUMBER,
  391.     ;DE POINTS TO THE FCB, AND BC POINTS TO THE DMA
  392. RPUT:    PUSH    B! PUSH D! PUSH H
  393.     LXI    H,33! DAD D! XCHG! POP H
  394.     ;NOW HL CONTAINS THE RECORD NUMBER, DE POINTS TO WHERE TO PUT IT.
  395.     MOV    A,L! STAX D! INX D! MOV A,H! STAX D! INX D
  396.     MVI    A,0! STAX D! POP B! POP D
  397.     ;NOW BC POINTS TO FCB, DE POINTS TO DMA. FIRST THING WE DO IS
  398.     ;SET THE DMA ADDRESS APPROPRIATELY.
  399.     PUSH    B! MVI C,26! CALL 0005
  400.     ;NOW WE RESTORE DE AS THE FCB, AND CALL FOR A RANDOM WRITE. WE WILL
  401.     ;GENEROUSLY ALLOW CP/M TO REPORT ANY SERIOUS ERRORS.
  402.     POP    D! MVI C,34! CALL 0005! RET
  403.     ;ROUTINE TO CLOSE THE FILE. DE CONTAINS THE FCB ADDRESS.
  404. FCLOS:    MVI    C,16! CALL 0005! INR A! ORA A! RNZ
  405.     ;IF THERE WAS AN ERROR HERE, WE SHOULD REPORT IT.
  406.     MVI    C,9! LXI D,FCERR! CALL 0005! JMP 0
  407. FCERR:    DB    'FILE CLOSE ERROR REPORTED BY CP/M.',0DH,0AH,'$'
  408. 30
  409.     ;RESERVED FOR SEQUENTIAL FILE I/O; OPEN, CLOSE, INPUT#, LINPUT#, PRINT#
  410. 31
  411.     ;RESERVED FOR VAL(,STR$(,MID$(,LEFT$(,RIGHT$(, ETC.
  412.     ;
  413.     ;VAL(
  414.     ;ASCII TO BINARY CONVERSION. DE POINTS TO STRING, BC CONTAINS LENGTH,
  415.     ;HL WILL CONTAIN SIGNED BINARY FORM OF NUMBER ON EXIT. NON-DIGITS WILL
  416.     ;BE IGNORED FOR PURPOSES OF CONVERSION. I.E. 12G3F4=1234.
  417. ASCBIN:    LXI    H,0! PUSH H
  418. ASCB2:    MOV     A,B! ORA A! JNZ ASCB3
  419.     MOV    A,C! ORA A! JZ ASCB4
  420. ASCB3:    LDAX    D! DCX B! INX D! CPI '-'! CC ASCB5
  421.     CPI    '0'! JC ASCB2
  422.     CPI    '9'+1! JNC ASCB2
  423.     SUI    '0'! PUSH D! PUSH H! POP D! DAD H! DAD H! DAD D! DAD H
  424.     LXI    D,0! MOV E,A! DAD D! POP D! JMP ASCB2
  425. ASCB4:    POP    B! MOV A,B! ORA A! RZ
  426.     MOV    A,H! CMA! MOV H,A! MOV A,L! CMA! MOV L,A! INX H! RET
  427. ASCB5:    POP H!    MVI H,1! PUSH H! RET
  428.     ;
  429. 32
  430.     ;STR$(
  431.     ;SIGNED BINARY TO ASCII CONVERSION. DE POINTS TO STRING LOCATION WORD,
  432.     ;HL CONTAINS SIGNED BINARY NUMBER TO CONVERT.
  433. STR:    PUSH    D! LDAX D! MOV C,A! INX D! LDAX D! MOV D,A! MOV E,C
  434.     ;NOW DE POINTS TO THE BEGINNING OF THE TARGET STRING
  435.     MOV    A,H! ANI 080H! JZ STR2
  436.     MOV    A,H! CMA! MOV H,A! MOV A,L! CMA! MOV L,A! INX H
  437.     MVI    A,'-'
  438.     STAX    D
  439.     JMP    STR3
  440. STR2:    MVI    A,'+'
  441.     STAX    D
  442. STR3:    INX    D
  443.     MOV    A,H! ANI 07FH! MOV H,A
  444.     LXI    B,-10000! CALL DECDIG
  445.     LXI    B,-1000! CALL DECDIG
  446.     LXI    B,-100! CALL DECDIG
  447.     LXI    B,-10! CALL DECDIG
  448.     MOV    A,L! ORI '0'! STAX D
  449.     LXI    H,0006H! POP D! INX D! INX D! MOV A,L! STAX D! INX D
  450.     MOV    A,H! STAX D! RET
  451. 33
  452.     ;MOVING A STRING IN MEMORY. DE=DEST., HL=SOURCE, BC=# BYTES.
  453. STRMV:    MOV    A,B! ORA A! JNZ STRMV1
  454.     MOV    A,C! ORA A! RZ
  455. STRMV1:    MOV    A,M! STAX D! INX D! INX H! DCX B! JMP STRMV
  456. 34
  457.     ;EXPANSION AREA
  458.  
  459.