; file:FixFD.asm ;----------------------------- ; Fix FD ;----------------------------- ; A utility to convert FD files to EQU files. ; ; Copyright (c) 1988 by Peter Wyspianski ; ; Revision History ; ---------------- ; 30 Dec 88 created ; 01 Jan 89 changed to use the 'dos_lib.i' file ;---------------------------------------- ; Constants null equ $00 bs equ $08 tab equ $09 lf equ $0a ; amiga eoln cr equ $0d ; CR only esc equ $1b csi equ $9b ; control sequence introducer ; DOS Constants: MODE_OLDFILE equ 1005 MODE_NEWFILE equ 1006 SIGBREAKB_CTRL_C EQU $0C SIGBREAKB_CTRL_D EQU $0D SIGBREAKB_CTRL_E EQU $0E SIGBREAKB_CTRL_F EQU $0F SIGBREAKF_CTRL_C EQU $1000 SIGBREAKF_CTRL_D EQU $2000 SIGBREAKF_CTRL_E EQU $4000 SIGBREAKF_CTRL_F EQU $8000 ;**SIGBREAK_ANY equ $F000 SIGBREAK_ANY equ $1000 ; Exec Base Offsets: ThisTask EQU $114 ; Task Control Structure Offsets: TC_SIGRECVD EQU $1A TC_SIGALLOC EQU $12 ;---------------------------------------- ; Includes MACFILE "RAM:Std_Macs68k" INCLUDE "RAM:dos_lib.i" ;---------------------------------------- ; Publics XDEF _main XDEF Exit ;---------------------------------------- ; Externals: ; from std.startup: XREF _exit XREF _stdin,_stdout,_SysBase,_DOSBase ;---------------------------------------- ; The beginning SECTION Main,CODE ; just a little something to brighten some file-zapper's day: dc.b 'Be Happy!',null cnop 0,2 ;------------------------------- ; BCD_Left [18 Nov 88] ; ; - converts hex word to a string of one to five left justified BCD digits ; - string is null terminated ; ; Inputs : d0.w = hex word ; a0.l = starting address of string ; Outputs: all regs preserved ; ; Notes : - from 1 to five digits can be returned plus the zero termination ; for a total of up to six characters ; - starts by determining number of digits in the string BCD_Left pushm d0-d3/a0-a1 move.w #3,d2 ; # digits - 2 lea LBCDTAB,a1 ; point to ten thousands 1$ cmp.w (a1)+,d0 ; determine number of digits in result bcc.s 2$ ; (ubge) taken if right size dbra d2,1$ ; taken for 10K through 10 bra.s 6$ ; we have just a ones digit 2$ subq.l #2,a1 ; compensate for following pre-decrement 3$ move.w (a1)+,d1 ; d1=BCD digit weight move.b #'0',d3 ; init digit to ASCII '0' 4$ cmp.w d1,d0 ; digit weight ? remainder blt 5$ ; taken if done with this digit addq.b #1,d3 ; inc BCD digit result sub.w d1,d0 ; decrement total bnz.s 4$ ; go for more 5$ move.b d3,(a0)+ ; stash digit dbra d2,3$ ; next digit position 6$ or.b #'0',d0 ; form ones digit move.b d0,(a0)+ clr.b (a0) ; form zero terminator pullm d0-d3/a0-a1 rts LBCDTAB dc.w 10000,1000,100,10 ;---------------------------------------- ; GetDec [30 Dec 88] ; ; - converts a decimal string to a hex value ; ; Inputs : a0 = ^ string ; Outputs: d0.l = value ; ; Reg Use: d1,a0-a1 ; ; Calls : none ; Uses : none ; ; Notes : - Non-numeric input produces garbage (GIGO applies). ; - Excessively long strings cause wrap-around. GetDec: clr.l d0 ; result 1$ move.b (a0)+,d1 ; fetch next digit bz.s 2$ ; if 'digit' is a null then all done ; here the running result is multiplied by ten: asl.l #1,d0 ; x2 move.l d0,a1 ; save the x2 value (a1 = scratch) asl.l #2,d0 ; x4 x8 add.l a1,d0 ; x8 + x2 = x10 ; the latest 'units' digit is added to the result: sub.b #'0',d1 ; force digit to range 0-9 add.l d1,d0 ; splice into result bra.s 1$ ; and go for more! 2$ rts ;---------------------------------------- ; PrStr [31 Dec 88] _stdout ; FPrStr [31 Dec 88] a file ; ; - sends a null terminated string to a file (_stdout) ; ; Inputs : a0 = ^string ; a1 = file handle (FPrStr only) ; ; Outputs: none ; ; Calls : Write (DOS.Library) ; Uses : _DOSBase (library base) ; _stdout ; ; Notes : exits via the call to Write PrStr: move.l _stdout,a1 FPrStr: push.l a1 ; save file handle move.l a0,a1 ; find the string length 1$ tst.b (a1)+ bnz.s 1$ ; loop until end of string sub.l a0,a1 ; start-end+1 = len+1 sub.l #1,a1 ; fix the length pull.l d1 ; recover file handle move.l a0,d2 ; ^buffer move.l a1,d3 ; length move.l _DOSBase,a6 jmp _LVOWrite(a6) ; exit via this routine ;---------------------------------------- ; ReadLn [31 Dec 88] from _stdin ; FReadLn [31 Dec 88] from a file ; ; - reads a line from a file (_stdin) ; - terminator (lf) is NOT stored ; - string is returned null-terminated ; ; Inputs : a0 = ^string buffer ; a1 = file handle (FReadLn only) ; ; Outputs: d0 = result: 1 = ok, 0 = eof, -1 = error ; ; Reg Use: d0-d3/a0-a2 ; ; Calls : Read (DOS.Library) ; Uses : _DOSBase (library base) ReadLn: move.l _stdin,a1 FReadLn: move.l a0,a2 ; keep ^buffer safe move.l a1,a3 ; keep file handle safe 1$ move.l a3,d1 ; file handle move.l a2,d2 ; ^buffer move.l #1,d3 ; read one char CallDOS Read cmp.l #1,d0 ; what was returned? bne.s 2$ ; exit if error or eof move.b (a2)+,d1 ; fetch character and bump ^buffer cmp.b #lf,d1 ; end of line? bne.s 1$ ; taken if not 2$ move.b #null,-1(a2) ; null terminate the string rts ; and exit ;---------------------------------------- ; FileOpenError [31 Dec 88] ; ; - calls IoErr to get a specific error number for a failed file open. ; - prints an error message of the form: ; ; Error #xxx opening file "yyyy". ; ; ; Inputs : a0 = ^filename ; Outputs: none ; ; Reg Use: d0-d1/a0-a1 ; ; Calls : IoErr (DOS.Library) ; BCD_Left ; PrStr ; Uses : _DOSBase (library base) ; BCDBuff FileOpenError: push.l a0 ; save ^file name CallDOS IoErr ; must do this FIRST push.w d0 ; save the bad news lea BadOpenMsg,a0 jsr PrStr pull.w d0 ; recover error number lea BCDBuff,a0 jsr BCD_Left lea BCDBuff,a0 jsr PrStr ; show the number lea BadOpenMsg1,a0 ; second half of error message jsr PrStr pull.l a0 ; fetch ^file name jsr PrStr lea BadOpenMsg2,a0 ; third half of error message jsr PrStr rts *---------------------------------------- * Main [30 Dec 88] * * here is a picture of the entry stack: * * 12 --- not ours! * 8 ^argvArray pointer to argvArray * 4 argc argument count * sp 0 RA our return address _main: clr.l TheError ; default good return move.l sp,savesp ; to ensure that we clean up on exit pull.l ReturnAddr ; just in case we need it... ; make a pointer to our TC_SIGRECVD: move.l _SysBase,a0 ; base of the Exec library move.l ThisTask(a0),a0 ; ^Task Control Structure (that's us!) lea TC_SIGRECVD(a0),a0 ; ^the flags move.l a0,TaskSigs ; save the pointer for later ; and we're off: lea GreetMsg,a0 ; say hello jsr PrStr pull.l argc ; argc (argument count) pull.l argv ; ^argv (argument array) move.l argc,d0 ; argv format: cmp.l #3,d0 ; we need three arguments... blt.l Help ; ...taken if 'confused user' error! move.l argv,a0 ; fetch ^argv move.l 4(a0),a0 ; point to first argument move.l a0,SName ; save ^source file name move.l argv,a0 ; fetch ^argv move.l 8(a0),a0 ; point to second argument move.l a0,DName ; save ^dest file name ; open the input file: move.l SName,d1 move.l #MODE_OLDFILE,d2 ; must already exist CallDOS Open move.l d0,sfile ; save source file handle bnz.s 1$ ; taken if ok ; handle problems opening the input file: move.l SName,a0 jsr FileOpenError move.l #30,TheError bra.l Exit ; bye! ; open the output file: 1$ move.l DName,d1 move.l #MODE_NEWFILE,d2 CallDOS Open move.l d0,dfile ; save dest file handle bnz.s ScanFD ; taken if ok ; handle problems opening the output file: move.l DName,a0 jsr FileOpenError move.l #30,TheError bra.l Exit2 ; read lines of the input file until EOF is true: ScanFD: ; If the output file is acutally the tube then we don't want ; line numbers cluttering the display: move.l dfile,d1 ; output file handle CallDOS IsInteractive move.b d0,TubeOut ; -1 = yeah, 0 = nope lea HeaderMsg,a0 move.l dfile,a1 ; output file handle jsr FPrStr move.l DName,a0 move.l dfile,a1 ; output file handle jsr FPrStr lea HeaderMsg1,a0 move.l dfile,a1 ; output file handle jsr FPrStr tst.b TubeOut ; skip screen formatting if outfile... bnz.s 1$ ; ... is connected to the tube. lea StatusMsg,a0 jsr PrStr lea CursorOff,a0 jsr PrStr 1$ move.w line,d0 ; bump line number add.w #1,d0 move.w d0,line tst.b TubeOut ; gonna use the tube? bnz.s 8$ ; taken if not (being used by out file) lea BCDBuff,a0 ; convert line number to a dec string jsr BCD_Left lea BCDBuff,a0 ; show the line number jsr PrStr ; This gets REAL fancy by adding one 'bs' to StrBuff for every ; non-null char in BCDBuff: lea BCDBuff,a0 lea StrBuff,a1 2$ move.b #bs,(a1)+ ; put one in there tst.b (a0)+ ; check for a null bnz.s 2$ ; taken if not move.b #null,-1(a1) ; kill the last bs and null terminate lea StrBuff,a0 ; backup jsr PrStr 8$ move.l TaskSigs,a0 ; see if the user hit ctrl-c thru ctrl-f move.l (a0),d0 ; d0 = SigsRecvd and.l #SIGBREAK_ANY,d0 ; mask all but ours bnz.l Abort ; taken if we hit lea StrBuff,a0 ; fetch a line from the input file move.l sfile,a1 jsr FReadLn tst.l d0 ; see what's up! bz.l Exit0 ; taken if EOF bmi.l Exit0 ; taken if error ;---------------------------------------- ; determine what sort of line it is here: ; ; # = option (process further) ; A-Z,a-z,'_','.' = FD entry (strip) ; ; all others are ignored ('*',';', and anything else) move.b StrBuff,d0 ; fetch first char cmp.b #'#',d0 ; option? beq 6$ ; taken if so cmp.b #'.',d0 ; fd entry? beq.s 3$ ; taken if so cmp.b #'_',d0 ; fd entry? beq.s 3$ ; taken if so cmp.b #'A',d0 ; fd entry? blt.l 1$ ; taken if NOT (ignore) or.b #$20,d0 ; force to lowercase cmp.b #'z',d0 ; fd entry? bgt.l 1$ ; taken if NOT (ignore) ;--------------------------------------------------------------- ; strip the line (scan for a space, open paren, or end of line) ; there are NO blank lines here (eliminated above): ; 3$ lea LVOMsg,a0 ; prefix the routine name with '_LVO' move.l dfile,a1 jsr FPrStr lea StrBuff,a0 5$ move.b (a0)+,d0 ; fetch a char and bump pointer bz.s 4$ ; taken if end of line cmp.b #' ',d0 ; space? beq.s 4$ ; taken if so cmp.b #'(',d0 ; open paren? bne.s 5$ ; taken if so 4$ move.b #null,-1(a0) ; null-terminate right AT the 1st excess char pea -1(a0) ; save ^end of string (for later) lea StrBuff,a0 ; show the line move.l dfile,a1 ; output file handle jsr FPrStr lea StrBuff,a0 pull.l d0 ; fetch ^end of string ;*** sub.l a0,d0 ; d0 = string len ;*** lea EQU8Msg,a0 ; equ - ;*** cmp.l #8,d0 ; seven chars or less? ;*** blt.s 44$ ; taken if so (output extra tab) lea EQUMsg,a0 ; equ - 44$ move.l dfile,a1 ; output file handle jsr FPrStr move.w bias,d0 ; convert the bias to a decimal string lea BCDBuff,a0 jsr BCD_Left lea BCDBuff,a0 move.l dfile,a1 ; output file handle jsr FPrStr ; show the bias lea EQUMsg1,a0 ; finish the line off move.l dfile,a1 ; output file handle jsr FPrStr move.w #6,d0 ; bump bias add.w d0,bias bra.l 1$ ; and go again! ;---------------------------------------- ; check for the '##bias' option: 6$ move.l StrBuff+2,d0 ; fetch 4 chars (should be 'bias') or.l #$20202020,d0 ; force to lowercase cmp.l #'bias',d0 bne.l 1$ ; ignore if not the option ; scan for a space: lea StrBuff+6,a0 ; skip the '##bias' 7$ move.b (a0)+,d0 ; fetch a char and bump pointer bz.l 1$ ; taken if end of line (ignore) cmp.b #' ',d0 ; space? bne.s 7$ ; taken if not ; fetch and show the bias: jsr GetDec ; a0 should be pointing at the number move.w d0,bias ; save it ; show the 'bias = ' message: lea BiasMsg,a0 move.l dfile,a1 ; output file handle jsr FPrStr move.w bias,d0 ; convert the bias to a decimal string lea BCDBuff,a0 jsr BCD_Left lea BCDBuff,a0 move.l dfile,a1 ; output file handle jsr FPrStr ; show the bias lea BiasMsg1,a0 move.l dfile,a1 ; output file handle jsr FPrStr bra.l 1$ ; go for another line ;------------------------------------------- ; show the help message and exit: Help: lea HelpMsg,a0 jsr PrStr bra.s Exit ;------------------------------------------- ; show the 'break...' message and exit: Abort: lea BreakMsg,a0 jsr PrStr bra.s ExitA ;----------------------------- ; Exit routines [30 Dec 88] ; Exit0: lea DoneMsg,a0 jsr PrStr ExitA: lea CursorOn,a0 jsr PrStr Exit1: move.l dfile,d1 ; close the dest file CallDOS Close Exit2: move.l sfile,d1 ; close the source file CallDOS Close Exit: push.l TheError ; error code jsr _exit ; and wind it up ;---------------------------------------- ; constants SECTION Constants,DATA GreetMsg: dc.b lf dc.b csi,'0;33;40m' dc.b ' FixFD ' dc.b csi,'0;31;40m' dc.b 'v1.0 - Copyright ',$a9 dc.b ' 1988, Peter Wyspianski',lf,lf dc.b null HelpMsg dc.b ' This utility takes an ''.FD'' file and generates a set of',lf dc.b ' EQUates that can be used by an assembler.',lf,lf dc.b ' Parameters: source_file dest_file.',lf,lf dc.b ' See the docs for more info! -PW',lf,lf,null BadOpenMsg: dc.b csi,'0;33;40m' dc.b ' Error ' dc.b csi,'0;31;40m' dc.b '#' dc.b null BadOpenMsg1: dc.b ' opening file "',null BadOpenMsg2: dc.b '"',lf,lf,null CursorOff dc.b csi dc.b '0 p' dc.b null CursorOn dc.b csi dc.b ' p' dc.b null StatusMsg: dc.b ' Reading line ' dc.b null DoneMsg dc.b lf,lf dc.b csi,'0;33;40m' dc.b ' Finished.' dc.b csi,'0;31;40m' dc.b lf,lf,null BreakMsg dc.b lf,lf ;*** dc.b csi,'0;33;40m' dc.b '*** BREAK' ;*** dc.b csi,'0;31;40m' dc.b lf,lf,null HeaderMsg dc.b '; file:',null HeaderMsg1 dc.b lf dc.b ';',lf dc.b '; generated by FixFD v1.0',lf dc.b ';',lf dc.b null BiasMsg dc.b '; Bias = ',null BiasMsg1 dc.b lf dc.b ';',lf dc.b null LVOMsg dc.b '_LVO',null EQU8Msg dc.b tab EQUMsg dc.b tab dc.b 'equ -' dc.b null EQUMsg1 dc.b lf dc.b null ;---------------------------------------- ; Uninitialized storage SECTION Variables,BSS TaskSigs ds.l 1 ; pointer to our TC_SIGRECVD TheError ds.l 1 ; error return code SName ds.l 1 ; ^source file name DName ds.l 1 ; ^dest file name sfile ds.l 1 ; source file handle dfile ds.l 1 ; dest file handle savesp ds.l 1 ; entry stack pointer argc ds.l 1 ; argument count argv ds.l 1 ; argument array pointer ReturnAddr ds.l 1 ; program return address bias ds.w 1 ; library entry bias line ds.w 1 ; current line number TubeOut ds.b 1 ; -1 = yes, 0 = nope ds.b 1 ; alignment BCDBuff ds.b 6 ; bcd string buffer StrBuff ds.b 256 ; longest possible string