0001 ;=============================================================== 0002 ; 0003 ; TABBIT input-ref output-ref 0004 ; 0005 ; Replaces strings of blanks in an ASCII file with tabs, where 0006 ; possible. Assumes the standard CP/M tab increment of eight. 0007 ; This program should NOT be applied to a file whose data will 0008 ; be processed further before being printed or typed. 0009 ; 0010 ; input-ref :: [x:] inputname [.typ] 0011 ; 0012 ; If the drivecode x: is omitted the default drive is used. An 0013 ; input filename is required. A filetype is optional (or, to 0014 ; be precise, a filetype of 3 blanks is allowed). 0015 ; 0016 ; output-ref :: [y:] [outputname] [.typ] 0017 ; 0018 ; Each omitted part of the output fileref is supplied from the 0019 ; input-ref. Thus the default drive is the input drive, the 0020 ; default name is the input name, and the default type is the 0021 ; input type. If all are omitted, the output file replaces the 0022 ; input file. 0023 ; ***************************************************** 0024 ; * This program was originally published in * 0025 ; * A PROGRAMMER'S NOTEBOOK * 0026 ; * Utilities for CP/M-80 * 0027 ; * by David E. Cortesi * 0028 ; * Copyright (C) Reston Publishing Company Inc. 1983 * 0029 ; ***************************************************** 0030 *=============================================================== 0031 MACLIB CPMEQU 0032 MACLIB PROG 0033 PROLOG 0034 ;=============================================================== 0035 ; Variables equated to registers: 0036 Column equ D ; Column is in the DE pair 0037 Columnlo equ E ; low byte of Column 0038 T equ H ; 'T' is in register H 0039 Kseven equ L ; constant 0111B in reg. L 0040 ;=============================================================== 0041 ; Utility I/O variables... 0042 ; #include utilio.inc,IOVars 0043 ;=============================================================== 0044 ; the main program -- initialization 0045 Main: 0046 call SetUpInput ; open the input file 0047 lxi b,InFCB ; BC-->default fileref 0048 lxi d,OBspace ; DE-->start of buffer space 0049 ; prolog sets HL-->end of buffer space 0050 call SetUpOutput ; prepare the output stuff 0051 ;=============================================================== 0052 ; the main program -- main loop 0053 ; 0054 call Shift ; set up the B, C text window 0055 call Shift 0056 lxi Column,0 ; clear the column count 0057 mvi Kseven,0111b ; set up the handy constant 0058 ; 0059 MainWhile: 0060 mov a,b ; while (B<>EOF)... 0061 cpi CpmEof 0062 jz MainEnd 0063 ; 0064 ani AsciiDEL ; clear the high bit 0065 ; 0066 cpi AsciiDEL ; if (B=AsciiDEL) 0067 jz MainShout ; then nil. 0068 ; 0069 ; do a 3-way split between control characters, the blank, 0070 ; and the printable characters. 0071 ; 0072 cpi AsciiBlank 0073 jz IsBlank 0074 jnc IsPrintable 0075 ; else IsControl 0076 ; 0077 cpi AsciiTAB 0078 jnz IsCont2 ; if (B=AsciiTAB) then 0079 mov a,Columnlo ; Column := 1+(Column or 0111b) 0080 ora Kseven 0081 mov Columnlo,a 0082 inx Column 0083 jmp MainShout 0084 ; 0085 IsCont2: 0086 cpi AsciiCR 0087 jnz IsCont3 ; if (B=AsciiCR) then 0088 lxi Column,0 ; Column := 0 0089 jmp MainShout 0090 ; 0091 IsCont3: 0092 cpi AsciiBS 0093 jnz MainShout ; if (B=AsciiBS) then 0094 mov a,Column ; Column := max(Column-1,0) 0095 ora Columnlo 0096 jz MainShout 0097 dcx Column 0098 jmp MainShout 0099 ; 0100 ; Handle blanks. Treat a single blank, or a blank just before 0101 ; a tabstop, like any printable character. Test two blanks 0102 ; for possible tab substitution using a recursive procedure. 0103 ; 0104 IsBlank: 0105 cmp c ; if B<>C then C<>Blank 0106 jnz IsPrintable 0107 mov a,Columnlo 0108 ana Kseven ; A := Column mod 8 0109 mov T,a ; (save it) 0110 mov a,Kseven 0111 sub T 0112 mov T,a ; T := 7-(Column mod 8) 0113 jz IsPrintable ; do test only if T>0. 0114 call TesTab 0115 jnz IsPrintable ; test failed, print last blank 0116 mvi B,AsciiTAB ; test o.k., output a tab 0117 ; ...fall into IsPrintable to increment Column to 8 0118 ; 0119 ; Come here with Column correct for the character in B, to 0120 ; increment Column so it is correct for the character in C. 0121 ; 0122 IsPrintable: 0123 inx Column 0124 ; 0125 ; Come here with Column correct for the character in C, to 0126 ; write B and make C the current character. 0127 ; 0128 MainShout: 0129 call Shout 0130 jmp MainWhile ; ..end while 0131 ; 0132 MainEnd: 0133 call FinishOutput ; complete output file 0134 ret ; end main. 0135 ;--------------------------------------------------------------- 0136 ; Recursive procedure TesTab: swallow blanks until a tabstop is 0137 ; reached. If a nonblank turns up, regurgitate the swallowed 0138 ; blanks. Ends with Column correct for the character in B. 0139 ; Assumes that B is always a blank on entry. 0140 TesTab: 0141 inx Column 0142 call Shift 0143 dcr T 0144 rz ; if T=0, exit 0145 mov a,b 0146 cmp c ; if (T>0) and (C=Blank) then 0147 cz TesTab ; ...TesTab 0148 push psw ; (save TesTab result Zflag) 0149 mvi a,AsciiBlank ; if (T<>0) then 0150 cnz PutChar ; ...PutChar(AsciiBlank) 0151 pop psw ; (return Zflag of test) 0152 ret 0153 ;=============================================================== 0154 ; the included I/O subroutines -- GetChar, PutChar, DumpOutput 0155 ; #include utilio.inc,IOSubs 0156 ;=============================================================== 0157 ; the file preparation code -- SetUpInput, SetUp-, FinishOutput 0158 ; #include utilio.inc,IOSetup 0159 ;=============================================================== 0160 ; The end of the program, and the start of the buffer space. 0161 ; The technique of using all storage for buffer, used here, is 0162 ; a liability in MP/M. There, the entire output buffer should 0163 ; be defined in the program or obtained with XDOS service 129. 0164 ; 0165 OBspace equ $ 0166 END * CROSS-REFERENCE * def. val. symbol and uses * ---- 0020 ASCIIBLANK CPI-72 MVI-149 * ---- 0008 ASCIIBS CPI-92 * ---- 000D ASCIICR CPI-86 * ---- 007F ASCIIDEL ANI-64 CPI-66 * ---- 0009 ASCIITAB CPI-77 MVI-116 * 0036 0002 COLUMN LXI-56 INX-82 LXI-88 MOV-94 DCX-97 INX-123 -141 * 0037 0003 COLUMNLO MOV-79 -81 ORA-95 MOV-107 * ---- 001A CPMEOF CPI-61 * ---- 056E FINISHOUTPUT CALL-133 * ---- 0156 INFCB LXI-47 * 0104 02FA ISBLANK JZ-73 * 0085 02E1 ISCONT2 JNZ-78 * 0091 02EC ISCONT3 JNZ-87 * 0122 030F ISPRINTABLE JNC-74 JNZ-106 JZ-113 JNZ-115 * 0039 0005 KSEVEN MVI-57 ORA-80 ANA-108 MOV-110 * 0045 02A9 MAIN * 0132 0316 MAINEND JZ-62 * 0128 0310 MAINSHOUT JZ-67 JMP-83 -89 JNZ-93 JZ-96 JMP-98 * 0059 02C0 MAINWHILE JMP-130 * 0165 05DC OBSPACE LXI-48 * ---- 036A PUTCHAR CNZ-150 * ---- 03F4 SETUPINPUT CALL-46 * ---- 049A SETUPOUTPUT CALL-50 * ---- 0331 SHIFT CALL-54 -55 -142 * ---- 032D SHOUT CALL-129 * 0038 0004 T MOV-109 SUB-111 MOV-112 DCR-143 * 0140 031A TESTAB CALL-114 CZ-147 * CENSUS OF OPCODE USAGE * * ANA 1 ANI 1 CALL 8 * CMP 2 CNZ 1 CPI 6 * CZ 1 DCR 1 DCX 1 * END 1 EQU 5 INX 3 * JMP 4 JNC 1 JNZ 5 * JZ 5 LXI 4 MACLIB 2 * MOV 9 MVI 3 ORA 2 * POP 1 PROLOG 1 PUSH 1 * RET 2 RZ 1 SUB 1