title LF2CRLF - LF/CR stripper name ('LF2CRLF') maclib base80 ; LF2CRLF performs a conversion between UNIX files (LF only to ; terminate lines) and CP/M text files (CR/LF to terminate lines). ; ; The default operation is to convert to CP/M format, so: ; ; LF2CRLF UNIX_FILE [CPM_FILE] ; ; will convert the file, using CR/LF as the line terminator. ; ; For reverse conversion use option -U. The output will be in ; UNIX format, with LF only to separate lines, so: ; ; LF2CRLF -U CPM_FILE [UNIX_FILE] ; ; will delete the CR's from CPM_FILE. ; ; Copyright (c) Werner Cirsovius ; Hohe Weide 44 ; 20253 Hamburg ; Phone:(+49)40/4223247 ; ; Version 2.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 'LF2CRLF' 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 _O equ 1 _NL equ 2 dseg 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: db ' performs a conversion between UNIX files (LF only to' db cr,lf db 'terminate lines) and CP/M text files (CR/LF to terminate lines).' db cr,lf,lf db 'The default operation is to convert to CP/M format, so:' db cr,lf,lf db tab $PRG$ db ' UNIX_FILE [CPM_FILE]' db cr,lf,lf db 'will convert the file, using CR/LF as the line terminator.' db cr,lf,lf db 'For reverse conversion use option -U. The output will be in' db cr,lf db 'UNIX format, with LF only to separate lines, so:' db cr,lf,lf db tab $PRG$ db ' -U CPM_FILE [UNIX_FILE]' db cr,lf,lf db 'will delete the CR''s from CPM_FILE.' $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 C$RDY: db ' insertions',cr,lf,null U$RDY: db ' deletions',cr,lf,null $DONE: db cr,lf db 'Ready' db cr,lf,null TypeMsg: dw C$RDY ARGV: ds 2*ARGMX $memry: ds 2 PB: ds 2+2 DecASCII: ds 2 HEAP: ds 2 CCPexe: dw arg1 dw arg2 dw getopt $BUP: db '.$$$',null BUPlen equ $-$BUP ; ; Flag state: ; ; Bit 0 : Only one file selected ; Bit 1 : Option -U selected ; Bit 2 : Previous CR found ; Flag: ; \ db 00000000b ; | Drv: ; | ds 1 ; / cntint: db 0,0,0,0 one: db 0,0,0,1 FCNT: dw 0 FPTR: ds 2 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 ; iniLF2CRLF: 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 ; ; Test first parameter an option - Z set if indicator found ; isopt: ld iy,(ARGV) ; Get pointer to 1st argument ld a,(iy+0) cp '-' ; Test possible option ret ; ; Found two arguments - must be an option followed by one file name ; or two file names ; arg2: call isopt ; Test possible option ret nz ; Nope call getopt ; Get option ; Then get 2nd file name ; ; Found one argument - must be a file name ; arg1: call isopt ; Test possible option jp z,illcall ; Invalid here 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 ; ; Get and verify option ; getopt: ld hl,illOpt push hl ld iy,(ARGV) ; Get pointer to 1st argument ld a,(iy+1) or a ; Maybe early end ret z ld (ILL$OP),a cp 'U' ret nz call isopt ; Verify correct syntax ret nz ld a,(iy+2) or a ret nz pop hl set _O,(ix+0) ; 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 ld hl,U$RDY ld (TypeMsg),hl ; Change message 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 %%% ; %%%%%%%%%%%%%%%%%%%%%%%% ; LF2CRLF: sub a ; Verify Z80 CPU jp pe,IllCPU ; Must be ld sp,(TPATOP) ; Get my stack call iniLF2CRLF ; Init program 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 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 CNVLOOP: call fget ; Read character jr c,EOFILE ; Test end cp cr ; Test return jr nz,tstLF ; ; Found CR ; If UNIX throw it away ; If CP/M get it ; bit _O,(ix+0) ; Test option -U jr z,markCR ; Nope, so process it call incchr ; Increment count jr CNVLOOP ; Ignore it markCR: set _NL,(ix+0) ; Mark it doput: call fput ; Put character jr CNVLOOP ; Loop till end ; ; Found LF ; If UNIX get it ; IF CP/M expand to CR LF if not previous CR found ; tstLF: cp lf ; Test it jr z,LFmode delCR: res _NL,(ix+0) ; Release it jr doput LFmode: bit _O,(ix+0) ; Test option -U jr nz,doput ; Yeap, do not expand bit _NL,(ix+0) ; Test previous CR jr nz,delCR inc hl call incchr ; Increment count ld a,cr call fput ; Expand ld a,lf jr doput ; ; 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,(TypeMsg) ; Print final message finalstr: call strcn0 xor a ; Mark success ret end LF2CRLF