0001 ;=============================================================== 0002 ; 0003 ; UNTAB input-ref output-ref /increment 0004 ; 0005 ; Removes tabs from an ASCII file, replacing them with blanks. 0006 ; The tabs in the file are assumed to be placed based on a 0007 ; fixed increment. The increment may be specified so that tabs 0008 ; can be removed from a file that was not prepared using the 0009 ; standard CP/M tab increment of 8. 0010 ; 0011 ; input-ref :: [x:] inputname [.typ] 0012 ; 0013 ; If the drivecode x: is omitted the default drive is used. An 0014 ; input filename is required. A filetype is optional (or, to 0015 ; be precise, a filetype of 3 blanks is allowed). 0016 ; 0017 ; output-ref :: [y:] [outputname] [.typ] 0018 ; 0019 ; Each omitted part of the output fileref is supplied from the 0020 ; input-ref. Thus the default drive is the input drive, the 0021 ; default name is the input name, and the default type is the 0022 ; input type. If all are omitted, the output file replaces the 0023 ; input file. 0024 ; 0025 ; /increment 0026 ; 0027 ; This operand may be omitted. If it is omitted, the increment 0028 ; is assumed to be 8. If given, it must be coded as /nnn where 0029 ; "nnn" is a positive integer less than 255. 0030 ; ***************************************************** 0031 ; * This program was originally published in * 0032 ; * A PROGRAMMER'S NOTEBOOK * 0033 ; * Utilities for CP/M-80 * 0034 ; * by David E. Cortesi * 0035 ; * Copyright (C) Reston Publishing Company Inc. 1983 * 0036 ; ***************************************************** 0037 *=============================================================== 0038 MACLIB CPMEQU 0039 MACLIB PROG 0040 PROLOG 0041 ;=============================================================== 0042 ; Variables equated to registers: 0043 Column equ H ; column counter in HL 0044 Columnhi equ Column 0045 Columnlo equ L 0046 TabInc equ D ; carry the increment in D 0047 T equ E ; use E for 'T' variable 0048 ;=============================================================== 0049 ; Utility I/O variables, and other messages 0050 ; #include utilio.inc,IOVars 0051 MsgBadInc db 'The increment option must be numeric.$' 0052 MsgWrongInc db 'The increment must be between 1 and 255.$' 0053 ;=============================================================== 0054 ; the main program -- initialization 0055 Main: 0056 call Increment ; A = tab increment from tail 0057 push psw ; (save that just in case) 0058 call SetUpInput ; open the input file 0059 lxi b,InFCB ; BC-->default fileref 0060 lxi d,OBspace ; DE-->start of buffer space 0061 ; prolog sets HL-->end of buffer space 0062 call SetUpOutput ; prepare the output stuff 0063 ;=============================================================== 0064 ; the main program -- main loop 0065 ; 0066 call Shift ; set up the B, C text window 0067 call Shift 0068 pop psw ; retrieve tab increment 0069 mov TabInc,a 0070 lxi Column,0 ; clear column count 0071 ; 0072 MainWhile: 0073 mov a,b ; while (B<>EOF)... 0074 cpi CpmEof 0075 jz MainEnd 0076 ; 0077 ani AsciiDEL ; clear the high bit 0078 cpi AsciiDEL 0079 jz MainShout ; if (B=DEL) then nil 0080 ; 0081 cpi AsciiBlank 0082 jc IsControl ; if (B>=Blank) then 0083 inx Column ; ...Column := Column+1 0084 jmp MainShout ; (and go write B) 0085 ; 0086 IsControl: 0087 cpi AsciiBS 0088 jnz IsCont2 ; if (B=backspace) then 0089 mov a,Columnlo ; ...Column := max(Column-1,0) 0090 ora Columnhi 0091 jz MainShout 0092 dcx Column 0093 jmp MainShout 0094 ; 0095 IsCont2: 0096 cpi AsciiCR 0097 jnz IsCont3 ; if (B=CR) then 0098 lxi Column,0 ; ...Column := 0 0099 jmp MainShout 0100 ; 0101 IsCont3: 0102 cpi AsciiTAB ; if (B<>Tab) then 0103 jnz MainShout ; ...nil 0104 ; 0105 ; Discover how many blanks this tab represents. Advance Column 0106 ; that far. Write T-1 blanks and leave the T-eth one in B for 0107 ; output at MainShout. 0108 ; 0109 push Column ; Div16by8 destroys HL 0110 mov a,TabInc ; ..and takes divisor in A 0111 call Div16by8 ; A=remainder of (Column/TabInc) 0112 mov T,a ; ..save that 0113 mov a,TabInc 0114 sub T 0115 mov T,a ; T := TabInc-(Column mod TabInc) 0116 pop Column ; recover Column 0117 ; 0118 push d ; save TabInc (D) and T (E) 0119 mvi d,0 ; make T a 16-bit number 0120 dad d ; ..and add to Column 0121 pop d 0122 ; 0123 mvi B,AsciiBlank 0124 BlankOut: 0125 dcr T ; do T-1 times... 0126 jz MainShout 0127 mvi a,AsciiBlank 0128 call PutChar 0129 jmp BlankOut 0130 ; 0131 MainShout: 0132 call Shout 0133 jmp MainWhile ; ..end while 0134 ; 0135 MainEnd: 0136 call FinishOutput ; complete output file 0137 ret ; end main. 0138 ;--------------------------------------------------------------- 0139 ; Increment gets the optional increment from the command tail, 0140 ; returning it in A. Most of the work is done by included 0141 ; subroutine CmdNumOpt, which searches for /nn and converts it. 0142 ;--------------------------------------------------------------- 0143 Increment: 0144 push h 0145 push d 0146 ; 0147 lxi h,CpmTail+1 ; set start of scan 0148 call CmdNumOpt ; DE gets integer value 0149 mvi a,8 ; assume default of 8 0150 JRNZ IncrExit ; Z false : no /option found 0151 JRC IncrBad ; Cy true : /non-numeric found 0152 mov a,d ; Z true, Cy false : /nn found 0153 ora a ; if /nn was over 255, 0154 JRNZ IncrWrong ; ..diagnose it 0155 mov a,e ; else return the value given 0156 ora a ; ..unless it is zero 0157 JRZ IncrWrong 0158 IncrExit: 0159 pop d 0160 pop h 0161 ret 0162 IncrBad: 0163 ABORT MsgBadInc 0164 IncrWrong: 0165 ABORT MsgWrongInc 0166 ;=============================================================== 0167 ; included subroutines for parsing the command tail 0168 ; #include cmdparse.inc,CmdNumOpt 0169 ;=============================================================== 0170 ; included subroutine for arithmetic 0171 ; #include arithlib.inc,Div16by8 0172 ;=============================================================== 0173 ; the included I/O subroutines -- GetChar, PutChar, DumpOutput 0174 ; #include utilio.inc,IOSubs 0175 ;=============================================================== 0176 ; the file preparation code -- SetUpInput, SetUp-, FinishOutput 0177 ; #include utilio.inc,IOSetup 0178 ;=============================================================== 0179 ; The end of the program, and the start of the buffer space. 0180 ; The technique of using all storage for buffer, used here, is 0181 ; a liability in MP/M. There, the entire output buffer should 0182 ; be defined in the program or obtained with XDOS service 129. 0183 ; 0184 OBspace equ $ 0185 END * CROSS-REFERENCE * def. val. symbol and uses * ---- 0020 ASCIIBLANK CPI-81 MVI-123 -127 * ---- 0008 ASCIIBS CPI-87 * ---- 000D ASCIICR CPI-96 * ---- 007F ASCIIDEL ANI-77 CPI-78 * ---- 0009 ASCIITAB CPI-102 * 0124 0358 BLANKOUT JMP-129 * ---- 039B CMDNUMOPT CALL-148 * 0043 0004 COLUMN EQU-44 LXI-70 INX-83 DCX-92 LXI-98 PUSH-109 * POP-116 * 0044 0004 COLUMNHI ORA-90 * 0045 0005 COLUMNLO MOV-89 * ---- 001A CPMEOF CPI-74 * ---- 0080 CPMTAIL LXI-147 * ---- 03F9 DIV16BY8 CALL-111 * ---- 064D FINISHOUTPUT CALL-136 * 0162 038B INCRBAD JRC-151 * 0143 036E INCREMENT CALL-56 * 0158 0388 INCREXIT JRNZ-150 * 0164 0393 INCRWRONG JRNZ-154 JRZ-157 * ---- 0156 INFCB LXI-59 * 0095 0337 ISCONT2 JNZ-88 * 0101 0342 ISCONT3 JNZ-97 * 0086 0329 ISCONTROL JC-82 * 0055 02F8 MAIN * 0135 036A MAINEND JZ-75 * 0131 0364 MAINSHOUT JZ-79 JMP-84 JZ-91 JMP-93 -99 JNZ-103 JZ-126 * 0072 0313 MAINWHILE JMP-133 * 0051 02A9 MSGBADINC ABORT-163 * 0052 02CF MSGWRONGINC ABORT-165 * 0184 06BB OBSPACE LXI-60 * ---- 0449 PUTCHAR CALL-128 * ---- 04D3 SETUPINPUT CALL-58 * ---- 0579 SETUPOUTPUT CALL-62 * ---- 0410 SHIFT CALL-66 -67 * ---- 040C SHOUT CALL-132 * 0047 0003 T MOV-112 SUB-114 MOV-115 DCR-125 * 0046 0002 TABINC MOV-69 -110 -113 * CENSUS OF OPCODE USAGE * * ABORT 2 ANI 1 CALL 10 * CPI 6 DAD 1 DB 2 * DCR 1 DCX 1 END 1 * EQU 6 INX 1 JC 1 * JMP 5 JNZ 3 JRC 1 * JRNZ 2 JRZ 1 JZ 4 * LXI 5 MACLIB 2 MOV 9 * MVI 4 ORA 3 POP 5 * PROLOG 1 PUSH 5 RET 2 * SUB 1