home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / PROGRAMS / LIST / LIST.ASM < prev    next >
Assembly Source File  |  2000-06-30  |  13KB  |  596 lines

  1. *  PROGRAM NAME:  LIST
  2. *  AUTHOR:  RICHARD CONN
  3. *  VERSION:  1.0
  4. *  DATE:  10 FEB 81
  5. *  PREVIOUS VERSIONS:  -None-
  6. VERS    equ    10    ; Version Number
  7.  
  8. *
  9. *
  10. *  Section 0:  Introduction to the LIST Program
  11. *
  12.  
  13.  
  14.  
  15. *
  16. *    LIST is a CP/M utility which displays a file on the user console in
  17. * paged mode.  It prints 24 lines of text and pauses; typing a ^C at this point
  18. * returns to CP/M, while any other character continues.  If a line is more than
  19. * LINE$LENGTH character long, it is broken and the line count is incremented
  20. * accordingly.
  21. *
  22.  
  23. *
  24. *    The structure of the LIST Program is as follows --
  25. *
  26. *  Section    Functions/Routines
  27. *  -------    ------------------
  28. *
  29. *     0        Introduction and Documentation
  30. *
  31. *     1        Initialization of the LIST Program
  32. *        Significant Labels are:
  33. *          OPTION:  Command Line option processing
  34. *            OPTION$NUMBER:  Set the Line Numbering Flag (/N)
  35. *          DRIVE:  Extract the disk drive letter from the command line
  36. *
  37. *     2        Mainline of the LIST Program
  38. *        Significant Labels are:
  39. *          LIST:  Open files, perform tests, etc
  40. *          LIST1:  Start processing loop
  41. *          LIST$LOOP:  Main program loop
  42. *
  43. *     3        Support Utilties
  44. *        Significant Routines are:
  45. *          PRINT$ID:  Print Program ID
  46. *          TYP$COMP:  Compare the 3-byte file type pted to by HL to
  47. *            the FCB type; return w/Zero Set if match
  48. *          PRINT$MESSAGE:  Print string pted to by return address;
  49. *            string ends in 0
  50. *          LOADER:  Copy top of buffer down to front of buffer and
  51. *            load up to 16K into buffer
  52. *          LOADER1:  Load the buffer pted to by HL for B blocks (max)
  53. *          CRLF:  Print <CR> <LF> (no regs affected)
  54. *          CHAR$OUT:  Print char in A; no regs affected
  55. *          CHAR$IN:  Input char in A; only PSW affected
  56. *          PRINT$LINE:  Print line pted to by HL on console; process
  57. *            line numbering, tab expansion, line overflow fcts
  58. *          PRINT$NUMBER:  Print HL as up to 5 decimal digits with
  59. *            leading <SP>; follow by <SP>
  60. *
  61. *      4    Buffers
  62. *
  63.  
  64. NUMBER$LINES    equ    24    ; Number of lines/screen
  65. LINE$LENGTH    equ    77    ; Maximum number of characters/line
  66. NUMBER$LENGTH    equ    7    ; Number of characters in line number
  67.  
  68. *
  69. *  DEFINE MISCELLANEOUS CONSTANTS USED IN PROGRAM
  70. *
  71. OPT$CHAR    equ    '/'    ; Option character
  72. CR        equ    13    ; <CR>
  73. LF        equ    10    ; <LF>
  74. BS        equ    8    ; <BS>
  75. TAB        equ    9    ; <TAB>
  76. BEL        equ    7    ; <BEL>
  77. CPM        equ    0    ; Warm Boot Address
  78. BUFF        equ    80H    ; CP/M Buffer
  79. FCB        equ    5CH    ; CP/M FCB
  80. WBADR        equ    1    ; CP/M Warm Boot Address
  81. BDOS        equ    5    ; CP/M BDOS Entry Point
  82. CTRLC        equ    'C'-'@'    ; ^C
  83. CTRLZ        equ    'Z'-'@'    ; ^Z
  84.  
  85. *
  86. *
  87. *  Section 1:  Initialization of LIST Program
  88. *
  89.  
  90.  
  91.  
  92.     ORG    100H
  93.  
  94.     LXI    H,BUFF    ; SCAN FOR OPTION
  95.     MOV    A,M    ; GET CHAR COUNT
  96.     ADD    L    ; ADD TO HL
  97.     MOV    L,A
  98.     MOV    A,H
  99.     ACI    0
  100.     MOV    H,A
  101.     INX    H    ; HL PTS TO CHAR AFTER LAST CHAR IN COMMAND LINE
  102.     MVI    M,0    ; STORE ENDING 0
  103.     LXI    H,BUFF+1    ; PT TO 1ST CHAR
  104.     PUSH    H    ; SAVE PTR FOR LATER
  105.     XRA    A    ; A=0
  106.     STA    NFLG    ; TURN OFF LINE NUMBERING FLAG
  107.     STA    OVFL    ; TURN OFF LINE LENGTH OVERFLOW FLAG
  108. OPTION:
  109.     MOV    A,M    ; SCAN FOR OPTION
  110.     ORA    A    ; DONE?
  111.     JZ    OPTION$DONE
  112.     INX    H    ; PT TO NEXT
  113.     CPI    OPT$CHAR    ; OPTION?
  114.     JNZ    OPTION
  115.     MOV    A,M    ; GET OPTION LETTER
  116.     CPI    'N'    ; NUMBER LINES?
  117.     JZ    OPTION$NUMBER
  118.     CALL    PRINT$ID    ; PRINT PROGRAM ID
  119.     CALL    PRINT$MESSAGE
  120.     DB    CR,LF,'    The LIST command takes the following format --'
  121.     DB    CR,LF,'        LIST d:filename.typ [/N]'
  122.     DB    CR,LF,'    Only the "/N" option is available; this option prints'
  123.     DB    CR,LF,'line numbers in front of each line.'
  124.     DB    CR,LF,'    The drive specification "d:" is optional.',0
  125.     JMP    CPM
  126. *  THIS OPTION TURNS ON THE LINE NUMBERING FLAG
  127. OPTION$NUMBER:
  128.     MVI    A,0FFH    ; TURN ON FLAG
  129.     STA    NFLG
  130.     JMP    OPTION
  131. *  DONE PROCESSING OPTIONS
  132. OPTION$DONE:
  133.     POP    H    ; GET PTR TO COMMAND LINE
  134. DRIVE:
  135.     MOV    A,M    ; SCAN FOR DRIVE NAME
  136.     ORA    A    ; DONE?
  137.     JZ    LIST
  138.     INX    H    ; PT TO NEXT CHAR
  139.     CPI    ' '    ; NON-SPACE?
  140.     JZ    DRIVE    ; CONTINUE SCAN IF SO
  141.     MOV    A,M    ; CHECK FOR COLON
  142.     CPI    ':'    ; COLON MEANS DRIVE NAME PRECEEDS
  143.     JNZ    LIST
  144.     DCX    H    ; PT TO DRIVE NAME
  145.     MOV    A,M    ; GET IT
  146.     SUI    'A'    ; ADJUST FROM LETTER TO NUMBER (A=0,B=1,ETC)
  147.     JC    DRIVE$ERROR
  148.     CPI    16    ; IN RANGE?
  149.     JNC    DRIVE$ERROR
  150.     MOV    E,A    ; PLACE NUMBER IN E
  151.     MVI    C,14    ; SELECT DISK
  152.     CALL    BDOS
  153.     JMP    LIST
  154. DRIVE$ERROR:
  155.     CALL    PRINT$MESSAGE
  156.     DB    CR,LF,'ERROR:  Invalid Drive Specification',0
  157.     JMP    CPM
  158.  
  159. *
  160. *
  161. *  Section 2:  Mainline of LIST Program
  162. *
  163.  
  164.  
  165.  
  166. LIST:
  167.     CALL    PRINT$ID    ; PRINT PROGRAM ID
  168.     LXI    H,COM$TYPE    ; DON'T PRINT *.COM OR *.OBJ FILES
  169.     CALL    TYP$COMP    ; COMPARE TYPES
  170.     JZ    TYPE$ERROR
  171.     LXI    H,OBJ$TYPE
  172.     CALL    TYP$COMP
  173.     JNZ    LIST0
  174. TYPE$ERROR:
  175.     CALL    PRINT$MESSAGE
  176.     DB    CR,LF,'ERROR:  Attempt to List COM or OBJ File',0
  177.     JMP    CPM
  178. LIST0:
  179.     LXI    D,FCB        ; TRY TO OPEN FILE
  180.     MVI    C,15        ; OPEN FILE
  181.     CALL    BDOS
  182.     CPI    0FFH    ; ERROR?
  183.     JNZ    LIST1
  184.     CALL    PRINT$MESSAGE
  185.     DB    CR,LF,'ERROR:  File Not Found',0
  186.     JMP    CPM
  187.  
  188. LIST1:
  189.     CALL    CRLF        ; NEW LINE
  190.     LXI    H,BUFFER    ; FILE BUFFER (16K)
  191.     MVI    B,8*16        ; LOAD 16K OF FILE (MAX)
  192.     CALL    LOADER1        ; LOAD BUFFER PTED TO BY HL FOR 16K
  193.     LXI    H,BUFFER    ; PT TO FIRST CHARACTER
  194.     LDA    NFLG        ; NUMBER LINES?
  195.     ORA    A        ; SET FLAGS
  196.     JZ    LIST$LOOP
  197.     PUSH    H        ; SAVE HL
  198.     LXI    H,0        ; SET FOR 1ST LINE NUMBER
  199.     SHLD    LINE$NUMBER
  200.     POP    H        ; RESTORE HL
  201.  
  202. *
  203. *  MAIN LOOP FOR PRINTING LINES
  204. *
  205. LIST$LOOP:
  206.     MVI    C,NUMBER$LINES    ; NUMBER OF LINES/SCREEN
  207. LIST$LOOP1:
  208.     CALL    PRINT$LINE    ; PRINT ONE LINE
  209.     CPI    CTRLZ
  210.     JZ    CPM
  211.     CPI    LF        ; LINE FEED?
  212.     JNZ    LIST$LOOP2
  213.     INX    H        ; PT TO CHAR AFTER <LF>
  214.     MOV    A,M        ; GET POSSIBLE ^Z
  215.     CPI    CTRLZ        ; ^Z IF SO
  216.     JZ    CPM
  217. LIST$LOOP2:
  218.     DCR    C        ; COUNT DOWN
  219.     JNZ    LIST$LOOP3
  220.     CALL    CHAR$IN        ; WAIT FOR CHAR
  221.     CALL    CRLF        ; NEW LINE
  222.     CPI    CTRLC        ; ^C?
  223.     JZ    CPM        ; ABORT IF SO
  224.     JMP    LIST$LOOP    ; CONTINUE
  225. LIST$LOOP3:
  226.     CALL    CRLF        ; NEW LINE
  227.     JMP    LIST$LOOP1
  228.  
  229. *
  230. *
  231. *  Section 3:  Support Utilities
  232. *
  233.  
  234.  
  235.  
  236. *
  237. *  THIS ROUTINE PRINTS THE PROGRAM ID
  238. *
  239. PRINT$ID:
  240.     CALL    PRINT$MESSAGE
  241.     DB    'LIST  Version ',VERS/10+'0','.',(VERS MOD 10)+'0',0
  242.     RET
  243.  
  244. *
  245. *  THIS ROUTINE COMPARES THE THREE BYTES PTED TO BY HL AGAINST THE TYPE
  246. *    IN THE FCB; RETURNS W/ZERO SET IF MATCH
  247. *
  248. TYP$COMP:
  249.     LXI    D,FCB+9    ; PT TO TYPE IN FCB
  250.     MVI    B,3        ; 3 BYTES
  251. TYP$COMP$LOOP:
  252.     LDAX    D        ; GET BYTE
  253.     CMP    M        ; COMPARE
  254.     RNZ
  255.     INX    H        ; PT TO NEXT
  256.     INX    D
  257.     DCR    B
  258.     JNZ    TYP$COMP$LOOP
  259.     RET
  260.  
  261. *
  262. *  PRINT MESSAGE PTED TO BY RETURN ADDRESS ENDING IN 0
  263. *
  264. PRINT$MESSAGE:
  265.     XTHL            ; SAVE HL AND GET PTR
  266. PRINT$MESSAGE$LOOP:
  267.     MOV    A,M        ; GET CHAR
  268.     INX    H        ; PT TO NEXT
  269.     ORA    A        ; DONE?
  270.     JZ    PRINT$MESSAGE$DONE
  271.     CALL    CHAR$OUT    ; PRINT IT
  272.     JMP    PRINT$MESSAGE$LOOP
  273. PRINT$MESSAGE$DONE:
  274.     XTHL            ; RESTORE HL AND RETURN ADDRESS
  275.     RET
  276.  
  277. *
  278. *  THIS ROUTINE LOADS THE FILE BUFFER
  279. *    ENTRY POINT 'LOADER' COPIES THE END OF THE FILE BUFFER DOWN TO THE
  280. * BEGINNING AND LOADS THE REST OF THE BUFFER (UP TO 16K).
  281. *    ENTRY POINT 'LOADER1' LOADS THE BUFFER POINTED TO BY HL FOR B-BLOCKS
  282. * (1 BLOCK = 128 BYTES).
  283. *
  284. LOADER:
  285.     PUSH    B        ; SAVE BC
  286.     LXI    H,BUFFER$LAST    ; PT TO LAST BLOCK
  287.     LXI    D,BUFFER    ; PT TO 1ST BLOCK
  288.     CALL    MOVE$BLOCK    ; MOVE BLOCK FROM HL TO DE
  289.     CALL    MOVE$BLOCK    ; MOVE PAGE (2 BLOCKS)
  290.     XCHG            ; PT TO 2ND BLOCK
  291.     MVI    B,8*16-2    ; 2 BLOCKS LESS THAN 16K
  292.     CALL    LOADER1        ; LOAD BLOCKS
  293.     POP    B        ; RESTORE BC
  294.     RET
  295. LOADER1:
  296.     CALL    LOADER2        ; LOAD NEXT BLOCK
  297.     RNZ            ; DONE IF PAST EOF
  298.     LXI    D,BUFF        ; PT TO BUFFER
  299.     XCHG            ; EXCHANGE PTRS
  300.     CALL    MOVE$BLOCK    ; MOVE BLOCK LOADED INTO FILE BUFFER
  301.     XCHG            ; RESTORE PTRS
  302.     DCR    B        ; COUNT DOWN
  303.     JNZ    LOADER1
  304.     RET
  305. *
  306. *  LOAD BUFFER FROM DISK
  307. *
  308. LOADER2:
  309.     PUSH H ! PUSH D ! PUSH B
  310.     LXI    D,FCB        ; PT TO FILE NAME
  311.     MVI    C,20        ; READ BLOCK
  312.     CALL    BDOS
  313.     ORA    A        ; SET FLAG
  314.     POP B ! POP D ! POP H
  315.     RET
  316.  
  317. *
  318. *  MOVE BLOCK (128 BYTES) FROM HL TO DE
  319. *
  320. MOVE$BLOCK:
  321.     PUSH    B        ; SAVE BC
  322.     MVI    B,128        ; 128 BYTES
  323. MOVE$BLOCK$LOOP:
  324.     MOV    A,M        ; GET BYTE
  325.     STAX    D        ; PUT BYTE
  326.     INX    H        ; PT TO NEXT
  327.     INX    D
  328.     DCR    B        ; COUNT DOWN
  329.     JNZ    MOVE$BLOCK$LOOP
  330.     POP    B        ; RESTORE BC
  331.     RET
  332.  
  333. *
  334. *  OUTPUT <CR> <LF>; DON'T CHANGE A
  335. *
  336. CRLF:
  337.     PUSH    PSW    ; SAVE A
  338.     MVI    A,CR    ; <CR>
  339.     CALL    CHAR$OUT
  340.     MVI    A,LF    ; <LF>
  341.     CALL    CHAR$OUT
  342.     POP    PSW    ; GET A
  343.     RET
  344.  
  345. *
  346. *  CHARACTER OUTPUT ROUTINE
  347. *    OUTPUT CHARACTER IN REG A TO CONSOLE
  348. *
  349. CHAR$OUT:
  350.     PUSH H ! PUSH D ! PUSH B ! PUSH PSW
  351.     MOV    E,A        ; CHAR IN E
  352.     MVI    C,2        ; OUTPUT TO CON:
  353.     CALL    BDOS
  354.     POP PSW ! POP B ! POP D ! POP H
  355.     RET
  356.  
  357. *
  358. *  CHARACTER INPUT ROUTINE
  359. *    CHARACTER IS RETURNED IN REG A
  360. *
  361. CHAR$IN:
  362.     PUSH H ! PUSH D ! PUSH B
  363.     LXI    H,CHAR$IN$RET    ; PLACE RETURN ADDRESS ON STACK
  364.     PUSH    H
  365.     LHLD    WBADR        ; INDEX INTO BIOS FOR NO ECHO
  366.     MOV    A,L        ; ADD 6 FOR CONSOLE INPUT ROUTINE
  367.     ADI    6
  368.     MOV    L,A
  369.     MOV    A,H
  370.     ACI    0
  371.     MOV    H,A        ; HL PTS TO ROUTINE
  372.     PCHL            ; "CALL" CONSOLE INPUT ROUTINE
  373. CHAR$IN$RET:
  374.     POP B ! POP D ! POP H
  375.     RET
  376.  
  377. *
  378. *  PRINT LINE PTED TO BY HL ON CONSOLE
  379. *
  380. PRINT$LINE:
  381.     PUSH    B        ; SAVE LINE COUNT
  382.     MVI    C,0        ; SET CHAR COUNT
  383.     LDA    NFLG        ; NUMBER LINE?
  384.     ORA    A        ; 0=NO
  385.     JZ    PRINT$LINE1
  386.     LDA    OVFL        ; OVERFLOW FROM PREVIOUS LINE?
  387.     ORA    A        ; 0=NO
  388.     JNZ    PRINT$LINE1
  389.     PUSH    H        ; SAVE PTR TO LINE
  390.     LHLD    LINE$NUMBER    ; FETCH AND INCREMENT LINE NUMBER
  391.     INX    H
  392.     SHLD    LINE$NUMBER
  393.     CALL    PRINT$NUMBER    ; PRINT LINE NUMBER
  394.     POP    H        ; RESTORE PTR TO LINE
  395. PRINT$LINE1:
  396.     XRA    A        ; TURN OFF OVERFLOW FLAG
  397.     STA    OVFL
  398.     LXI    D,BUFFER$LAST    ; IN LAST BLOCK?
  399.     MOV    A,H        ; CHECK AGAINST H
  400.     CMP    D 
  401.     JNZ    PRINT$LINE$LOOP
  402.     PUSH    H        ; SAVE PTR TO LINE (RELATIVE OFFSET IN L)
  403.     CALL    LOADER        ; LOAD NEXT 16K
  404.     LXI    H,BUFFER    ; PT TO 1ST BYTE OF BLOCK
  405.     POP    D        ; GET RELATIVE OFFSET IN E
  406.     MOV    L,E        ; RELATIVE OFFSET IN L -- CONTINUE
  407. PRINT$LINE$LOOP:
  408.     MOV    A,M        ; GET CHAR FROM FILE
  409.     INX    H        ; PT TO NEXT CHAR
  410.     ANI    7FH        ; MASK OUT MSB
  411.     CPI    CTRLZ        ; PROCESS EOF
  412.     JZ    PRINT$LINE$CR
  413.     CPI    BS        ; PROCESS <BS>
  414.     JZ    PRINT$LINE$BS
  415.     CPI    TAB        ; PRINT <TAB>
  416.     JZ    PRINT$LINE$TAB
  417.     CPI    CR        ; PROCESS EOL
  418.     JZ    PRINT$LINE$CR
  419.     CPI    ' '        ; DON'T OUTPUT LESS THAN <SP>
  420.     JC    PRINT$LINE$LOOP
  421.     CPI    7EH        ; DON'T OUTPUT IF GREATER THAN OR EQUAL TO 7EH
  422.     JNC    PRINT$LINE$LOOP
  423.     CALL    CHAR$OUT    ; PRINT CHAR
  424.     INR    C        ; INCREMENT CHAR COUNT
  425.     CALL    OVFL$TEST    ; CHECK FOR LINE OVERFLOW
  426.     JMP    PRINT$LINE$LOOP
  427. PRINT$LINE$BS:
  428.     MOV    A,C        ; POSSIBLE TO <BS>?
  429.     ORA    A        ; 0=NO
  430.     JZ    PRINT$LINE$LOOP
  431.     MVI    A,BS        ; PRINT <BS>
  432.     CALL    CHAR$OUT
  433.     DCR    C        ; COUNT DOWN
  434.     JMP    PRINT$LINE$LOOP
  435. PRINT$LINE$TAB:
  436.     MVI    A,' '        ; PRINT <SP>
  437.     CALL    CHAR$OUT
  438.     INR    C        ; INCREMENT COUNT
  439.     CALL    OVFL$TEST    ; CHECK FOR LINE OVERFLOW
  440.     MOV    A,C        ; MULTIPLE OF 8?
  441.     ANI    7        ; MASK FOR 3 LSB
  442.     JNZ    PRINT$LINE$TAB
  443.     JMP    PRINT$LINE$LOOP
  444. PRINT$LINE$CR:
  445.     MOV    A,M        ; GET POSSIBLE <LF>
  446.     POP    B        ; RESTORE LINE COUNT
  447.     RET
  448.  
  449. *
  450. *  TEST FOR LINE OVERFLOW AND PRINT OVERFLOW CHARS IF SO
  451. *
  452. OVFL$TEST:
  453.     LDA    NFLG        ; NUMBERING LINES?
  454.     ORA    A        ; 0=NO
  455.     JZ    OVFL$TEST1
  456.     LDA    OVFL        ; IN OVERFLOW?
  457.     ORA    A        ; 0=NO
  458.     JNZ    OVFL$TEST1
  459. *  WE ARE ON A NUMBERED LINE
  460.     MVI    A,LINE$LENGTH    ; GET LINE LENGTH
  461.     SUI    NUMBER$LENGTH    ; SUBTRACT LENGTH OF LEADING NUMBER
  462.     JMP    OVFL$TEST2
  463. *  WE ARE NOT ON A NUMBERED LINE
  464. OVFL$TEST1:
  465.     MVI    A,LINE$LENGTH    ; CHECK CHAR COUNT
  466. OVFL$TEST2:
  467.     CMP    C        ; OK?
  468.     RNZ
  469. *  CHECK TO SEE IF ONE OF NEXT 3 CHARS IS A <CR>
  470.     MOV    A,M        ; NEXT CHAR A <CR>?
  471.     ANI    7FH        ; MASK OUT MSB
  472.     CPI    CR
  473.     RZ
  474.     INX    H        ; NEXT CHAR A <CR>?
  475.     MOV    A,M
  476.     ANI    7FH
  477.     DCX    H
  478.     CPI    CR
  479.     RZ
  480.     INX    H        ; 3RD CHAR A <CR>?
  481.     INX    H
  482.     MOV    A,M
  483.     ANI    7FH
  484.     DCX    H
  485.     DCX    H
  486.     CPI    CR
  487.     RZ
  488. *  NONE OF THEM ARE, SO OVERFLOW
  489.     MVI    A,0FFH        ; SET OVERFLOW FLAG
  490.     STA    OVFL
  491.     MVI    A,' '        ; PRINT OVERFLOW CHARS
  492.     CALL    CHAR$OUT
  493.     MVI    A,'<'
  494.     CALL    CHAR$OUT
  495.     POP    D        ; CLEAR STACK
  496.     MVI    A,LF        ; FAKE A <LF>
  497.     DCX    H        ; BACK UP IN PREPARATION FOR <LF> ADVANCE
  498.     POP    B        ; RESTORE LINE COUNT
  499.     RET            ; RETURN TO MAIN LOOP
  500.  
  501. *
  502. *  PRINT NUMBER IN HL AS UP TO 5 DECIMAL DIGITS FOLLOWED BY A <SP>
  503. *    AFFECT NO REGISTERS
  504. *
  505. PRINT$NUMBER:
  506.     PUSH H ! PUSH D ! PUSH B ! PUSH PSW
  507.     MVI    A,0FFH 
  508.     STA    LDSP    ; TURN OFF LEADING <SP> FLAG
  509.     LXI    D,10000    ; DETERMINE 10,000'S COUNT
  510.     CALL    PNUM
  511.     LXI    D,1000    ; DETERMINE 1,000'S COUNT
  512.     CALL    PNUM
  513.     LXI    D,100    ; 100'S
  514.     CALL    PNUM
  515.     LXI    D,10    ; 10'S
  516.     CALL    PNUM
  517.     MOV    A,L    ; 1'S
  518.     ADI    '0'    ; CONVERT TO ASCII
  519.     CALL    CHAR$OUT    ; PRINT IT
  520.     MVI    A,':'    ; PRINT COLON
  521.     CALL    CHAR$OUT
  522.     MVI    A,' '    ; PRINT <SP>
  523.     CALL    CHAR$OUT
  524.     POP PSW ! POP B ! POP D ! POP H
  525.     RET
  526. *
  527. *  PNUM IS A UTILITY TO SUBTRACT DE FROM HL UNTIL HL<0; PRINT NUMBER OF TIMES
  528. *    SUBTRACTION WAS DONE; IF ZERO AND LEADING SPACE FLAG SET, PRINT <SP>;
  529. *    ELSE, PRINT DIGIT AND CLEAR LEADING SPACE FLAG
  530. *    ON EXIT, HL=HL-DE
  531. *
  532. PNUM:
  533.     MVI    C,'0'        ; SET DIGIT
  534. PNUM1:
  535.     MOV    A,L        ; GET NUMBER
  536.     SUB    E
  537.     MOV    L,A
  538.     MOV    A,H
  539.     SBB    D
  540.     MOV    H,A        ; HL=HL-DE
  541.     JC    PNUM2
  542.     INR    C        ; INCREMENT COUNT
  543.     JMP    PNUM1
  544. PNUM2:
  545.     MOV    A,L        ; ADD BACK IN SO HL IS AGAIN 0 OR POS
  546.     ADD    E
  547.     MOV    L,A
  548.     MOV    A,H
  549.     ADC    D
  550.     MOV    H,A        ; HL RESTORED
  551.     MOV    A,C        ; GET DIGIT
  552.     CPI    '0'        ; ZERO?
  553.     JNZ    PNUM3
  554.     LDA    LDSP        ; LEADING <SP>?
  555.     ORA    A        ; 0=NO
  556.     JZ    PNUM3
  557.     MVI    A,' '        ; PRINT <SP>
  558.     JMP    PNUM4
  559. PNUM3:
  560.     XRA    A        ; NO LEADING <SP>
  561.     STA    LDSP        ; TURN OFF FLAG
  562.     MOV    A,C        ; GET CHAR
  563. PNUM4:
  564.     CALL    CHAR$OUT
  565.     RET
  566.  
  567. *
  568. *
  569. *  Section 4:  Buffers
  570. *
  571.  
  572. COM$TYPE:
  573.     DB    'COM'        ; FOR COMPARISON AGAINST COM FILE TYPE
  574. OBJ$TYPE:
  575.     DB    'OBJ'        ; FOR COMPARISON AGAINST OBJ FILE TYPE
  576. LDSP:
  577.     DS    1        ; LEADING <SP> FLAG (0=NO)
  578. OVFL:
  579.     DS    1        ; LINE LENGTH OVERFLOW FLAG (0=NO)
  580. NFLG:
  581.     DS    1        ; LINE NUMBER FLAG (0=NO)
  582. LINE$NUMBER:
  583.     DS    2        ; LINE NUMBER STORAGE BUFFER
  584.  
  585.  
  586.     DS    60        ; STACK SPACE
  587. STACK    EQU    $
  588.  
  589.     ORG    $/256*256+256
  590. BUFFER:
  591.     DS    128*(16*8-2)    ; FILE BUFFER SPACE
  592. BUFFER$LAST:
  593.     DS    128*2        ; LAST BLOCK
  594.  
  595.     END
  596.