title NO TAB - Tabulator stripper name ('TABDEN') maclib base80 ; TABDEN replaces the tab characters (DETAB) in one or more files ; with spaces or replaces groups of spaces with tabs (ENTAB). ; ; To use the DETAB function, call it: ; ; TABDEN -D INFILE [OUTFILE] ; ; And to use the ENTAB function, call it: ; ; TABDEN -E INFILE [OUTFILE] ; ; Copyright (c) Werner Cirsovius ; Hohe Weide 44 ; 20253 Hamburg ; Phone:(+49)40/4223247 ; ; Version 1.2 August 1995 entry $memry ext cmdarg,comp3,wcard,adda,strcn0,fildrv ext add32,dout32,parse,srcfrs,srcnxt ext rdfcb,rdbuf,rdbfp,wrfcb,wrbuf,wrbfp,rename ext open,creatd,close,closef,delete,geteof,dskput $PRG$ macro db 'TABDEN' endm ARGMX equ 3 _PRGN equ 0 _STRG equ _PRGN+1 _PRFST equ _STRG+1 _PRFCB equ _PRFST+1 _PRDST equ _PRFCB+1 _PRSRC equ _PRDST+1 _EOT equ -1 _SF equ 0 dseg MAXL: ; Max columns db 80 ExeTab: dw ExePRGN,ExeSTRG,ExePRFST,ExePRFCB,ExePRDST,ExePRSRC illcallp: db _PRGN db _STRG dw $ILLCALL db _EOT illparsep: db _PRGN db _STRG dw $ILLPARSE db _EOT samenerrp: db _PRGN db _STRG dw $ILLSAME db _EOT illwildp: db _PRGN db _STRG dw $ILLWILD db _PRFST db _EOT illOptp: db _PRGN db _STRG dw $ILLOPT db _EOT nofile: db _PRGN db _STRG dw $ILLSRC db _PRSRC db _EOT illsrcp: db _PRGN db _STRG dw $ILLSRC db _PRFCB db _EOT illdstp: db _PRGN db _STRG dw $ILLDST db _PRFCB db _EOT wrerrp: db _PRGN db _STRG dw $WRERR db _PRDST db _EOT ClsErrp: db _PRGN db _STRG dw $CLSERR db _PRDST db _EOT $PRGNAM: db cr,lf $PRG$ db null $ILLCALL: ; TABDEN replaces the tab characters (DETAB) in one or more files ; with spaces or replaces groups of spaces with tabs (ENTAB). ; ; To use the DETAB function, call it: ; ; TABDEN -D INFILE [OUTFILE] ; ; And to use the ENTAB function, call it: ; ; TABDEN -E INFILE [OUTFILE] db ' replaces the tab characters (DETAB) in one or more files' db cr,lf db 'with spaces or replaces groups of spaces with tabs (ENTAB).' db cr,lf,lf db 'To use the DETAB function, call it:' db cr,lf,lf db tab $PRG$ db ' -D INFILE [OUTFILE]' db cr,lf,lf db 'And to use the ENTAB function, call it:' db cr,lf,lf db tab $PRG$ db ' -E INFILE [OUTFILE]' $CRLF: db cr,lf,null $ILLPARSE: db ': Invalid file specification' db cr,lf,null $ILLSAME: db ': Must be different files' db cr,lf,null $ILLWILD: db ': Invalid wildcard in file name ' db null $ILLOPT: db ': Invalid option -' ILL$OP: db '? detected' db cr,lf,null $ILLSRC: db ': Cannot find file ' db null $ILLDST: db ': Cannot create file ' db null $WRERR: db ': Write error on file ' db null $CLSERR: db ': Cannot close file ' db null $NOFILE: db 'No file created' db cr,lf,null $FRDY: db '[' $FSRC: db '12345678.123 -> ' $FDST: db '12345678.123',null $RDY: db '], conversion done with',null $NOCNV: db 'out changes' db cr,lf,null $WITH: db ' ',null RPL$RDY: db ' replacements',cr,lf,null $DONE: db cr,lf db 'Ready' db cr,lf,null TypeExec: ds 2 ARGV: ds 2*ARGMX $memry: ds 2 PB: ds 2+2 DecASCII: ds 2 HEAP: ds 2 CCPexe: dw illcall dw arg2 dw getopt $BUP: db '.$$$',null BUPlen equ $-$BUP ; ; Flag state: ; ; Bit 0 : Only one file selected ; Flag: ; \ db 00000000b ; | Drv: ; | ds 1 ; / cntint: db 0,0,0,0 one: db 0,0,0,1 FCNT: dw 0 FPTR: ds 2 TABASE: ds 2 col: ds 1 newcol: ds 1 ch: ds 1 cseg ; ; Print resulting number ; prnum: ld hl,cntint ; Point to number ld de,(DecASCII) push de ld b,null call dout32 ; Convert to ASCII pop de call strcn0 ; Print it ret ; ; Test result count zero ; iszero: ld iy,cntint ld a,(iy+0) or (iy+1) ; Simple test or (iy+2) or (iy+3) ret ; ; Increment character count ; incchr: push bc push de push hl ld bc,cntint ld de,one ld hl,cntint call add32 ; Add 1 to it pop hl pop de pop bc ret ; ; Initialize the program ; iniTABDEN: ld ix,Flag ; Point to flag call inimem ; Set up memory ld hl,ARGV ld de,CCP ld b,ARGMX call cmdarg jp c,illcall ; Invalid number of arguments call procccp ; Process CCP line ld hl,(ARGV) ; Get 1st argument ld de,(rdfcb) ; Get source FCB call getFCB ; Convert it ld hl,(ARGV+2) ; Get 2nd argument ld de,(wrfcb) ; Get destination FCB call getFCB ; Convert it ld hl,(rdfcb) ; Get source FCB ld de,(wrfcb) ; Get destination FCB ld c,.fdrv+.fname+.fext call comp3 ; Verify not same FCBs ret nz jp samenerr ; ; Initialize memory ; inimem: ld hl,($memry) ; Get first free address ld (rdbuf),hl ; Set for source buffer ld de,reclng add hl,de ld (wrbuf),hl ; Set for destination buffer add hl,de ld (rdfcb),hl ; Set for source FCB ld de,FCBlen add hl,de ld (wrfcb),hl ; Set for destination FCB add hl,de ld (DecASCII),hl add hl,de ld (HEAP),hl ; Set for heap ret ; ; Process command line ; procccp: ld hl,CCPexe-2 call idxtab ; Get address from table push hl ret ; Execute it ; ; Found two arguments - must be an option followed by one file name ; arg2: call getopt ; Get option ld hl,(ARGV) ; Get 1st argument ld de,(HEAP) ld (ARGV+2),de ; Put new into 2nd argument call cpy$$$ ; Unpack backup file ld (HEAP),de ret ; ; Found three arguments - must be an option followed by two file names ; getopt: ld hl,illOpt push hl ld iy,(ARGV) ; Get pointer to 1st argument ld a,(iy+0) cp '-' ; Verify option ret nz ld a,(iy+2) or a ret nz ld a,(iy+1) or a ; Maybe early end ret z ld (ILL$OP),a ; Save for error report cp 'D' ; Test DETAB ld hl,DETAB jr z,SetEXEC cp 'E' ; Verify ENTAB ret nz ld hl,ENTAB SetEXEC: ld (TypeExec),hl ; Set conversion type pop hl set 0,(ix) ; Set option ld hl,(ARGV+2) ; Get 2nd argument ld (ARGV),hl ; Unpack to 1st one ld hl,(ARGV+2+2) ; Get 3rd argument ld (ARGV+2),hl ; Unpack to 2nd one ret ; ; Copy main file ^HL to ^DE for .$$$ ; cpy$$$: ld a,(hl) or a ; Test end jr z,EndCpy ; Yeap cp '.' ; Test delimiter jr z,EndCpy ; Also end ld (de),a ; Unpack name inc hl inc de jr cpy$$$ EndCpy: ld hl,$BUP ld bc,BUPlen ldir ; Unpack .$$$ set _SF,(ix+0) ; Indicate single file ret ; ; Get FCB ^DE from name ^HL and exclude wild cards ; getFCB: ld (PB),hl ; Save name ld (PB+2),de ; Save FCB push de ld de,PB call parse ; Parse file pop de jp c,illparse ; Invalid file format bit _SF,(ix+0) ; Test single file call z,wcard ; Verify no wild card if not ret nz jp illwild ; ; Open existing file ; r.open: ld a,reclng ld (rdbfp),a ; Prepare read ld de,(rdfcb) ; Get FCB call open ; Open file ret nc jp illsrc ; ; Open new file ; w.open: xor a ld (wrbfp),a ; Prepare write ld de,(wrfcb) ; Get FCB call creatd ; Create file ret nc jp illdst ; ; Get character from file ; fget: call geteof ; Get it ret ; ; Put character to file ; fput: call dskput ; Put it ret nc jp wrerr ; Error ; ; Change file name if only one file was processed ; ; The destination file has to be renamed ; FixSingle: ld de,(rdfcb) call delete ; Delete old file - will be new one ld hl,(wrfcb) ; Get new file - will be renamed push hl ld a,(hl) ld (de),a ld bc,dirlen add hl,bc ex de,hl ldir pop de call rename ; Rename it ret ; ; %% ERROR ROUTINES %% ; NoFileFnd: ld ix,nofile jr Domess illcall: ld ix,illcallp jr Domess illparse: ld ix,illparsep jr Domess samenerr: ld ix,samenerrp jr Domess illwild: ld ix,illwildp jr Domess illOpt: ld ix,illOptp jr Domess illsrc: ld ix,illsrcp jr Domesst illdst: ld ix,illdstp Domesst: ld (PB+2),de jr Domess wrerr: ld ix,wrerrp jr Domess ClsErr: ld ix,ClsErrp ; ; Process complexe message output from control table ; Domess: ld a,(ix) ; Get control inc a ; Test end of table jp z,OS ; Yeap ld hl,ExeTab-2 call idxtab ; Get address from table inc ix call reg ; Execute routine jr Domess ; ; Get address from table ; idxtab: push de add a,a ; Double index call adda ; Point into table ld e,(hl) ; Fetch execution address inc hl ld d,(hl) ex de,hl pop de ret ; ; Simple subroutine jumps to ^HL ; reg: jp (hl) ; ; Control 0: Print name of program ; ExePRGN: ld de,$PRGNAM call strcn0 ret ; ; Control 1: Print string in table ; ExeSTRG: ld e,(ix+0) ; Fetch string pointer ld d,(ix+1) inc ix inc ix call strcn0 ret ; ; Control 2: Print name of file from string ; ExePRFST: ld de,(PB) ; Get name call strcn0 ; Print it jr crlf ; ; ; Control 5: Print name of file from read FCB ; ExePRSRC: ld de,(rdfcb) ; Get FCB jr prExec4 ; ; Control 3: Print name of file from parse FCB ; ExePRFCB: ld de,(PB+2) ; Get FCB prExec4: call fildrv ; Print it crlf: ld de,$CRLF call strcn0 ret ; ; Control 4: Print name of destination file from FC and delete it ; ExePRDST: ld de,(wrfcb) ; Get FCB call close ; Close it call delete ; Then delete it call prExec4 ; Finally print it ld de,$NOFILE call strcn0 ; Tell no success ret ; ; %%%%%%%%%%%%%%%%%%%%%%%% ; IllCPU: ld de,$ill.CPU ld c,.string call BDOS ; Print error message jp OS ; dseg $ill.CPU: $PRG$ db ' requires Z80 CPU',eot ; cseg ; ; %%%%%%%%%%%%%%%%%%%%%%%% ; %%% Entry of program %%% ; %%%%%%%%%%%%%%%%%%%%%%%% ; TABDEN: ld sp,(TPATOP) ; Get my stack call iniTABDEN ; Init program call settab ; Build column table call SampleFiles ; Build list of files ld hl,(FCNT) ; Get file count ld a,l or h ; Verify at leas one file jp z,NoFileFnd FileLoop: call ProcFile ; Process one file jr nc,FileLoop ; Go on ld de,$DONE call strcn0 ; Give final message jp OS ; ; Build column table ; settab: ld hl,MAXL ld b,(hl) ; Get max columns inc (hl) ; Fix for later compare ld c,1 ; Init count ld hl,(HEAP) ; Get top of memory ld (TABASE),hl ; Init table base set.loop: ld a,c and 00000111b dec a ; Test tab column sub 1 sbc a,a ld (hl),a ; Save it inc hl inc c djnz set.loop ld (HEAP),hl ; Set start of data ret ; ; Build list of files ; SampleFiles: ld hl,(HEAP) ld (FPTR),hl ; Init file pointer ld de,(rdfcb) ; Get FCB ld a,(de) ; Get drive ld (ix+1),a ; Save it push hl call srcfrs ; Find file SampleNext: pop de ld (HEAP),de ret c ; End of file ld a,(ix+1) ld (de),a ; Set drive inc de ld b,.fname call doCpy1 ; Unpack name and extension ld b,.fext call doCpy ld hl,(FCNT) inc hl ; Update count ld (FCNT),hl push de call srcnxt ; Find next jr SampleNext ; ; Copy name of file ; Cpname: ld hl,(rdfcb) ; Get source FCB ld de,(wrfcb) ; Get destination FCB ld bc,.fdrv+.fname ldir ; Unpack it ret ; ; Copy name and extension of file ; cpyFN: ld b,.fname call doCpy inc de ld b,.fext doCpy: inc hl doCpy1: ld a,(hl) and NoMSB ld (de),a inc de djnz doCpy ret ; ; Process one file ; ProcFile: ld hl,(FCNT) ld a,l or h scf ret z ; No more files dec hl ; Update count ld (FCNT),hl ld de,(rdfcb) ; Get FCB ld hl,(FPTR) ; Get search list ld bc,.fdrv+.fname+.fext ldir ; Unpack it ld (FPTR),hl bit _SF,(ix+0) ; Test wild card call nz,Cpname ; Copy name if so call r.open ; Open existing file call w.open ; Open new file ld hl,0 ld (cntint+0),hl ; Clear counter ld (cntint+2),hl ld a,1 ld (col),a ; Init column ld hl,EOFILE push hl ; Set return address ld hl,(TypeExec) ; Get execution jp (hl) ; ; Test tab position reached ; tabpos: ld hl,MAXL cp (hl) ; Test in range ccf ret c ; Out of range ld hl,(TABASE) call adda ld a,(hl) ; Get position flag rra ret ; ; Convert blanks to tab ; ENTAB: ld a,(col) ld (newcol),a ; Save columns ent.next: call fget ; Read character ret c ; End of file ld (ch),a ; Save character cp ' ' ; Test blank jr nz,ent.blnk ; Nope ld a,(newcol) inc a ; Advance column ld (newcol),a call tabpos ; Test tab position reached jr nc,ent.next ; Nope ld a,tab call fput ; Change against tab call incchr ; Increment count ld a,(newcol) ld (col),a ; Fix column jr ent.next ent.blnk: ld a,(col) ld hl,newcol cp (hl) ; Test position reached jr nc,ent.end ld a,' ' call fput ; Give blanks until match ld a,(col) inc a ld (col),a jr ent.blnk ent.end: ld a,(ch) call fput ; Putput last character ld hl,col ld a,(ch) cp cr ; Test end of line ld a,1 jr z,ent.col ; Reset column if so ld a,(hl) inc a ; If not bump column ent.col: ld (hl),a jr ENTAB ; ; Convert tab to blanks ; DETAB: call fget ; Read character ret c ; End of file cp tab ; Test tab jr nz,det.chr ; Nope det.blnk: ld a,' ' call fput call incchr ; Increment count ld a,(col) inc a ld (col),a call tabpos ; Test tab position reached jr nc,det.blnk jr DETAB det.chr: push af call fput ; Put character pop af cp cr ; Test end of line ld a,1 jr z,det.col ; Yeap, reset column ld a,(col) inc a ; Else bump it det.col: ld (col),a ; Store new column jr DETAB ; ; Job done, close file ; EOFILE: call closef ; Close file jp c,ClsErr ; Error closing file ld de,$FSRC ld hl,(rdfcb) call cpyFN ; Copy name of file bit _SF,(ix+0) ; Test single file jr z,MoreThanOne ld a,null ld (de),a ; Shorten line call FixSingle ; Process it jr TellFN MoreThanOne: ld de,$FDST ld hl,(wrfcb) call cpyFN ; Copy name of file TellFN: ld de,$FRDY call strcn0 ld de,$RDY call strcn0 ; Tell done call iszero ; Test zero conversion ld de,$NOCNV jr z,finalstr ; Yeap, tell it ld de,$WITH call strcn0 call prnum ; Give result ld de,RPL$RDY ; Print final message finalstr: call strcn0 xor a ; Mark success ret end TABDEN