; Fargo IDE header ;============================================================================= ; Last save: Wed Jan 20 14:50:17 1999 ; 845.8 249.17 572.0 614.0 614.0 614.0 ;============================================================================= /******************************************************************************* * FPL2.S - by David Kühling 1998 *--------------------------------------------------------------------------- * * This is the 2nd version of my Fargo Program Launcher. Now it also supports * execution of files that are stored compressed into string variables, that * where created by FSrhink.EXE. * * It needs to be preprocessed by the PreFargo preprocessor, at least version * 1.03. You can't get this programm from http://www.ticalc.org yet, so if you * need it, (e)mail me. * * Last modification: october 6th 1998 * * Contacting me: * Email: dkuehlin@hell1og.be.schule.de (don't mix up 'l' and '1') * - valid till june 2000 * Mail: * David Kühling * Lion-Feuchtwanger-Str. 44 * 12619 Berlin * GERMANY */ /***************************************************************************/ #include #include #include #include #include /***************************************************************************/ /***************************************************************************/ XDEF _main XDEF _comment /***************************************************************************/ /***************************************************************************/ #equ INFO_MASK1 %0000000111111111 #equ INFO_MASK2 %1111111111111000 // maximum number of handles, that can be checked #equ MAX_HANDLES 2048 // pointer to maximum number of handles in handle table #equ tios::MaxHandles tios::globals+$18EC #define STOROMREGS movem.l d0-d2/a0-a1, -(a7) #define RSTROMREGS movem.l (a7)+, d0-d2/a0-a1 /***************************************************************************/ /***************************************************************************/ /**************************************************************************** * Program launching routines ***************************************************************************/ /************** ** LaunchProgram * * Asks for yes or no, just by brwselib's message-box routine *** * Input: * a0.l = pointer to question-string (may only have 3 lines) * Output: * d1.b =-1: yes; =0: no */ AskYesNo: movem.l d0/d2/a0-a1/a4-a5, -(a7) // concatenate "$ [ENTER]=Yes [ESC]=No" to the question // int sprintf(char *buffer, char *format[, argument, ...]) pea (a0) // push Question pea QuestionFS(PC) // push format string lea TmpStr, a5 pea (a5) // push buffer jsr tios::sprintf // a5=pointer to resulting string lea 12(a7), a7 lea Question(PC), a4 // a4=pointer to title \Again: jsr brwselib::MessageBox // display the message box (a4=title;a5=content) // d0 = key cmpi.w #13, d0 // key==13: yes seq d1 beq \Ret cmpi.w #264, d0 // key==264: no beq \Ret bra \Again // else: ask again \Ret: movem.l (a7)+, d0/d2/a0-a1/a4-a5 rts /************** ** LaunchProgram * * Displays an error message, the errorcode given in d0 * If d0 == 0: no error ** * Input: * d0.w = errornum * Output: * d0.w = key ** * May use all registers. */ DisplayError: tst.w d0 // error-code == 0 ? beq \NoErr // -> there is no error! movem.l d0/a4/a5, -(a7) subq.w #1, d0 // calculate address of error message lsl.w #1, d0 move.w Errors(PC,d0.w), d0 lea Errors(PC,d0.w), a5 // a5 = address of error message lea Error(PC), a4 // a4 = address of title jsr brwselib::MessageBox movem.l (a7)+, d0/a4/a5 \NoErr: rts /************** ** LaunchProgram * * Error String List - consists of: * Pointer table - byte pointers, that point relative to the table's begin to the strings * String table - contains the strings, that are pointed to by the Pointer table */ /** Macros, to create it */ #define MKSTRINGLIST(LABEL,STRING,MORE...) { LABEL: dc.b STRING, 0 #ifdef MORE MKSTRINGLIST (MORE) #endif } #define CREATESTRINGLIST(DUMMY,STRINGLIST...) MKSTRINGLIST (STRINGLIST) #define ERRORLIST(ERRORS) { #equ ERRORSTRINGS dummy ERRORS CREATESTRINGLIST(ERRORSTRINGS) // filter out dummy, and create the list ds.w 0 // align data pointer at even address } #define ERROR(str) { #local errlabel dc.w errlabel-Errors // create relative pointer to `errlabel' // concatenate the string to the table #equ ERRORSTRINGS ERRORSTRINGS,errlabel,str #endlocal } // number of Fargo errors #define FARGOERRORS 9 Errors: ERRORLIST ({ /* 1 */ ERROR ("Out of memory") /* 2 */ ERROR ("Fargo too old") /* 3 */ ERROR ("Required library not$found or invalid") /* 4 */ ERROR ("Out-of-range library$import; a library$is probably too old") /* 5 */ ERROR ("File not executable") /* 6 */ ERROR ("Program quit due to$ER_throw") /* 7 */ ERROR ("Incompatible Fargo$version") /* 8 */ ERROR ("Incompatible ROM$version") /* 9 */ ERROR ("Unrecognized file$format") /* 10 */ ERROR ("ADDRESS ERROR!") /* 11 */ ERROR ("ILLEGAL INSTRUCTION!") /* 12 */ ERROR ("DIVISION BY ZERO!") /* 13 */ ERROR ("PRIVILEGE VIOLATION!") /* 15 */ ERROR ("LINE 1111 EMULATOR$TRIGGERED!") /* 16 */ ERROR ("PROGRAM ABORTED BY$[ON]+[ESC]!") /* 17 */ ERROR ("PROTECTED MEMORY$VIOLATION!") }) // number of redirections #equ REDIRECTIONS 12 /************** ** LaunchProgram * * Stores information about the handle table into `HandleBitField'. Each bit * represents one handle. If it is set, the corresponding handle is allocated, * else it isn't. ** * Used registers: a0.l a1.l d7.w d1.l */ #define STORE_HANDLE_INFO { #local \ClrLp, \SetLp, \_NotA, \_NoNB lea HandleInfo, a0 // a0 = pointer to handle-info-table // clear handle-info-table moveq #MAX_HANDLES/32-1, d7 movea.l a0, a1 \ClrLp: clr.l (a1)+ dbra d7, \ClrLp // set the handle-info-table move.w tios::MaxHandles, d7 // d7 = number of handles movea.l tios::Heap, a1 // a1 = pointer to handle table moveq #1, d1 // d1 = bit mask subq.w #1, d7 // d7 = counter (number of handles-1) /************* get-Handle-Info-Loop ************/ \SetLp: tst.l (a1)+ // this handle is allocated ? beq \_NotA or.b d1, (a0) // -> set corresponding bit within the info-table \_NotA: rol.b #1, d1 // go to next bit bcc \_NoNB // next bit is within the next byte ? addq.l #1, a0 // -> go to the next byte (info-table) \_NoNB: dbra d7, \SetLp /***********************************************/ #endlocal } /************** * Clear all handle-bits in the 'HandleInfo' Table, that are in use by the VAT table, * specified by the handle, given in d0 ** * Input: d0.w = handle of VAT table * a2.l = pointer to handle-bitfield * Doesn't destroy any registers! */ ClearVATHandleBits: movem.l d0-d2/d7/a0, -(a7) tios::DEREF d0, a0 //* a0 = pointer to VAT table addq.l #2, a0 move.w (a0)+, d7 //* d7 = number of entries subq.w #1, d7 //* d7 = counter bmi \Empty \Loop: move.w tios::SYM_ENTRY.hVal(a0), d0 //* d0 = used handle move.w d0, d1 // d1 = byte in handle-bitfield lsr.w #3, d1 move.w d0, d2 // d2 = number of bit andi.w #$7, d2 bset.b d2, 0(a2, d1.w) // set that bit (never free that handle) btst.b #7, tios::SYM_ENTRY.flags+1(a0) // is it a folder? beq \NoFld bsr ClearVATHandleBits // if it is one: recurse \NoFld: lea tios::SYM_ENTRY.hVal+2(a0), a0 // go to next entry dbra d7, \Loop \Empty: movem.l (a7)+, d0-d2/d7/a0 rts /************** ** LaunchProgram * * Checks, whether there are handles allocated, that weren't allocated when * STORE_HANDLE_INFO was executed. If such a handle is found, the user is asked, * whether these handles should be removed (freed). ** * Used registers: a0.l a1.l a2.l d0.w d1.l d2.w d3.w d7.w */ #define CHECK_HANDLE_TABLE { #local \ChkLp, \_HdOK, \_Free, \_NoNB, \DontFreeHandles lea HandleInfo, a2 // a2 = pointer to handle-info-table move.w FOLDER_LIST_HANDLE, d0 bsr ClearVATHandleBits // ignore bits that are in use by the VAT move.l tios::Heap, a1 // a1 = pointer to handle table move.w tios::MaxHandles, d7 // d7 = number of handles sf d1 // d1 = remove handles? clr.b d2 // d2 = bit number = 0 clr.w d3 // d3 = handle number = 0 subq.w #1, d7 // d7 = counter (number of handles-1) /************** check-handles-loop *************/ \ChkLp: tst.l (a1)+ // handle is allocated ? beq \_HdOK btst.b d2, (a2) // -> handle was not allocated before ? bne \_HdOK tst.b d1 // -> -> if d1 == 1: don't ask; remove the handle bne \_Free lea FreeMem(PC), a0 // -> -> else: ask the user about removing it bsr AskYesNo tst.b d1 // -> -> if it should not be removed: EXIT loop beq \DontFreeHandles \_Free: STOROMREGS // -> -> -> remove the handle move.w d3, -(a7) jsr tios::HeapFree addq.l #2, a7 RSTROMREGS \_HdOK: addq.w #1, d3 // increase handle number addq.b #1, d2 // increase bit number cmpi.b #8, d2 // bit number == 8 ? bne \_NoNB addq.l #1, a2 // -> go to next byte in handle-info-table clr.b d2 // -> go to first bit within this byte \_NoNB: dbra d7, \ChkLp /***********************************************/ \DontFreeHandles: #endlocal } /************** ** LaunchProgram * * Returns the program's entry point in a6, it's handle given by d0 */ #define GET_EP { #local \Fargo1, \End move.w d0, d1 // get address of program tios::DEREF d1, a6 cmpi.w #$0050, 2(a6) // is it a Fargo II programm ? beq \Fargo1 /****** Fargo II *******/ move.w $14(a6), d1 // get address of export table adda.w 2(a6, d1.w), a6 // get address of _main (Entry Point) bra \End \Fargo1: /***** Fargo 0.1.x *****/ addq.l #2, a6 // start of Fargo 0.1.x module adda.w $e(a6), a6 // get address of first public routine (Entry Point) \End: #endlocal } /************** ** LaunchProgram * * Prepares for interrupt redirection ** * Input: none * Output: d0.l = old SR */ PrepIntRedirection: bclr.b #2, $600001 // switch off protected memory violation move.w #$700, d0 // switch off interrupts trap #1 rts /************** ** LaunchProgram * * End of interrupt redirection ** * Input: d0.l = old SR * Output: d0.l = current SR */ IntRedirectionEnd: trap #1 // switch interrupts on bset.b #2, $600001 // switch protected memory violation on rts /************** ** LaunchProgram * * Returns one redirection address pair. ** * Input: a0.l = pointer to my redirectionlist * Output: a6.l = pointer to vector to be redirected * a5.l = poinnter to new routine * a0.l = pointer to next entry */ getRedirection: clr.l d6 move.b (a0)+, d6 // a6 = address of vector to be redirected movea.l d6, a6 move.b (a0)+, d6 // a5 = address of run-time-error routine lea 0(a0, d6.w), a5 rts /************** ** LaunchProgram * * Execute a program savely. * The run-time error vectors are redirected, and restored afterwards. * The vector table is checked for redirections, that were made by the * executed program, and the handle table is checked for newly created * handles. ** * Input: * d0.w = handle of program */ LaunchProgram: STORE_HANDLE_INFO // store, which handles are allocated /******* store vector table, SP, etc & redirect errors */ // store a copy of the vector table moveq #48-1, d7 // copy 48 longwords suba.l a0, a0 // from $000000 lea OldVectorTable, a1 // to `OldVectorTable' movea.l a1, a3 //a3 = pointer to `OldVectorTable' \CopyL: move.l (a0)+, (a1)+ dbra d7, \CopyL // Redirect all run-time error vectors lea RedirectList(PC), a0 // a0 points to redirection-list movea.l a0, a4 //a4 = pointer to redirection-list moveq #REDIRECTIONS-1, d7 // d7 = counter move.w d0, -(a7) // save handle bsr PrepIntRedirection // switches off ints and memory protection /************* Redirect-loop ***********/ \ReDLp: bsr getRedirection // returns: a6 = *vector; a5 = *new_routine move.l a5, (a6) // set the vector (a6) to the new routine (a5) dbra d7, \ReDLp /***************************************/ bsr IntRedirectionEnd // switches ints and memory protection on move.w (a7)+, d0 // restore handle of program // Store VideoRAM and SSP lea OldSSP, a5 trap #13 // store Supervisor Stack Pointer move.l d7, (a5)+ move.l #tios::main_lcd, d7 // store VideoRAM address (I/O format) lsr.l #3, d7 move.w d7, (a5) //a5 = pointer to OldVideoRAM /****** TRAP #12 ******************************* * Put trap #12 to the program entry point. This trap handler will store the USP, that is * required to return to kernel::exec */ GET_EP //a6 = pointer program entry point move.w (a6), OrigCommand // store the original first command move.w #$4E40+12, (a6) // and replace it by trap #12 /******* Execute program ***********************/ clr.w RunTimeError // set runtime error number = no runtime error movem.l a3-a6, -(a7) move.w d0, -(a7) jsr kernel::exec //d0 = returned error code addq.w #2, a7 movem.l (a7)+, a3-a6 move.w RunTimeError(PC), d1 // program returned, due to runtime error ? beq \NoRTE move.w d1, d0 // -> d0 = restored the runtime error number \NoRTE: // empty the keyboard buffer move.w #5000, d7 // wait until the tios read the keys \KeyLp: dbra d7, \KeyLp clr.w tios::kb_globals+$1C // and clear the keyboard buffer move.w (a5), $600010 // restore old VideoRAM address bsr DisplayError // display an error message, if d0 != 0 /******* restore vectors and check vector table */ move.w OrigCommand(PC), (a6) // restore TRAP #12 - command movea.l a4, a0 // a0 points to redirection-list // a3 points to the copy of the vector table moveq #REDIRECTIONS-1, d7 // d7 = counter bsr PrepIntRedirection // switches off ints and memory protection /* Note: Vectors that have been modified by the executed program won't be restored */ /******* Interrupt-restore-loop ********/ \RstLp: bsr getRedirection // returns: a6 = *vector; a5 = *new_routine cmpa.l (a6), a5 // if (vector) == run-time-error routine bne \_NRst move.l 0(a3,a6.w), (a6) // -> restore the vector \_NRst: dbra d7, \RstLp /***************************************/ bsr IntRedirectionEnd // switches ints and memory protection on // compare vector table with the older copy moveq #48-1, d7 // compare 48 longwords suba.l a2, a2 // of address $000000 with `OldVectorTable' \CmpLp: cmpm.l (a2)+, (a3)+ // vector modified? bne \Modified // -> branch to \Modified dbra d7, \CmpLp bra \End \Modified: // a vector has been modified! lea RestoreInts(PC), a0 // -> ask the user whether the vector table should bsr AskYesNo // be restored tst.b d1 beq \End // restore the modified vector and all following vectors bsr PrepIntRedirection // switches off ints and memory protection subq.l #4, a3 subq.l #4, a2 \IRsLp: move.l (a3)+, (a2)+ dbra d7, \IRsLp bsr IntRedirectionEnd // switches ints and memory protection on \End: CHECK_HANDLE_TABLE // check, whether the program created handles rts /** * Entry back to FPL from run time error routines (error code is in d0) */ RTError: move #$2700, SR // switch all interrupts off move.w d0, RunTimeError // set the runtime error number // restore the _hole_ vector table bsr PrepIntRedirection // switches off ints and memory protection moveq #48-1, d7 // copy 48 longwords lea OldVectorTable, a0 // from `OldVectorTable' suba.l a1, a1 // to $000000 \CopyL: move.l (a0)+, (a1)+ dbra d7, \CopyL // return to FPL lea OldSSP, a1 movea.l (a1), a7 // restore the Supervisor Stack Pointer move #$0000, SR movea.l -(a1), a7 // restore the User Stack Pointer rts // and return to the fargo kernel::exec routine /** Table of vector redirections */ #define REDIRECT(VECT,NEW) { dc.b VECT dc.b NEW-*-1 } RedirectList: REDIRECT ($0C, \Err1) /* Address Error */ REDIRECT ($10, \Err2) /* Illegal Instruction */ REDIRECT ($14, \Err3) /* Division By Zero */ REDIRECT ($20, \Err4) /* Privilege Violation */ REDIRECT ($28, \ErThrow) /* Line 1010 Emulator */ REDIRECT ($2C, \Err5) /* Line 1111 Emulator */ REDIRECT ($64, \ChkOnEsc1) /* Auto Int 1 (350 Hz Timer) */ REDIRECT ($74, \ChkOnEsc2) /* Auto Int 5 (18 Hz Timer) */ REDIRECT ($78, \ChkOnEsc3) /* Auto Int 6 (ON-key int) */ REDIRECT ($7C, \Err7) /* Auto Int 7 (Protected Memory Violation) */ REDIRECT ($B0, \getRSP) /* Trap #12 (gets the SP that returns to Fargo) */ REDIRECT ($B4, \getSSP) /* Trap #13 (to get the Supervisor Stackpointer)*/ /** New run-time error routines */ \Err1: moveq #FARGOERRORS+1, d0 /* Address Error */ bra RTError \Err2: moveq #FARGOERRORS+2, d0 /* Illegal Instruction */ bra RTError \Err3: moveq #FARGOERRORS+3, d0 /* Division by Zero */ bra RTError \Err4: moveq #FARGOERRORS+4, d0 /* Privilege Violation */ bra RTError \ErThrow: /* Line 1010 - Er_Throw interrupt */ moveq #6, d0 // set error = 6 (Program quit due to ER_thorw) bra RTError \Err5: moveq #FARGOERRORS+5, d0 /* Line 1111 Emulator */ bra RTError \ChkOnEsc1: /* Auto Int 1 (350 Hz Timer) */ move.l OldVectorTable+$64, -(a7) // address of original routine bra \CheckOnEsc // rts within `\CheckOnEsc' calls orig. routine \ChkOnEsc2: /* Auto Int 5 (18 Hz Timer) */ move.l OldVectorTable+$74, -(a7) // address of original routine bra \CheckOnEsc // rts within `\CheckOnEsc' calls orig. routine \ChkOnEsc3: /* Auto Int 6 (On-key int) */ move.l OldVectorTable+$78, -(a7) // address of original routine bra \CheckOnEsc // rts within `\CheckOnEsc' calls orig. routine /* Auto Int 7 (Protected Memory Violation) */ \Err7: moveq #FARGOERRORS+7, d0 bra RTError \getRSP: /* Trap #12 - is used to get the Stack Pointer that returns (in d7) */ move USP, a0 // Store the stack pointer to `OldUSP' move.l a0, OldUSP move.l 2(a7), a0 // restore the original command move.w OrigCommand(PC), -(a0) move.l a0, 2(a7) rte \getSSP: /* Trap #13 - is used to get the Supervisor Stack Pointer (in d7) */ move.l a7, d7 addq.l #6, d7 rte \CheckOnEsc: /* Check ON+ESC, and abort if both are pressed */ btst.b #1, $60001A // Check ON-key status bne \Cont move.w #$3FF-$100, $600018 // Check ESC-key (set the row mask) move.l (a7), (a7) // wait for the I/O to recover move.l (a7), (a7) move.l (a7), (a7) btst.b #6, $60001B // check the key (check column mask) bne \Cont moveq #FARGOERRORS+6, d0 // if ON+ESC: bra RTError // -> abort currently running program \Cont: rts /************** ** LaunchProgram - Archive * * Extract and execute an archived program * Input: * d0 = "handle" - the index of the section, the program is stored in * a5 = pointer to archive */ LaunchArcPrgm: move.w d0, -(a7) pea Extracting(PC) // display "Extracting..." jsr tios::ST_showHelp addq.l #4, a7 move.w (a7)+, d0 move.w d0, d1 //* d1 = index of section movea.l a5, a0 //* a0 = pointer to archive move.l a5, -(a7) // store the archive pointer jsr shrnklib::OpenArchive // -> d0 = archive descriptor handle tst.w d0 beq \Error // d0 = zero: error during extraction suba.l a0, a0 //* shrnklib::Extract has to allocate the dest memory jsr shrnklib::Extract //* d2 = handle jsr shrnklib::CloseArchive // close the archive specified by d0 move.l a0, d0 // check, whether a0 == 0 bne \NoError \Error: // extraction error lea Error(PC), a4 // display message box, title is "ERROR" lea ExtractError(PC), a5 jsr brwselib::MessageBox bra \Abort // launch the program \NoError: move.w d2, -(a7) // save handle of program move.w d2, d0 bsr LaunchProgram // execute the program jsr tios::HeapFree // free the program addq.l #2, a7 \Abort: movea.l (a7)+, a5 sf d4 // continue browsing rts /************** ** LaunchProgram - Archive * * Display the comment of an archived program * Input: * a0 = pointer to entry of that program. 8(a0) is the relative pointer to the comment! */ ArcInfo: adda.w 8(a0), a0 // a3 = pointer to comment movea.l a0, a3 move.w #1, -(a7) // normal font lea tios::FontSetSys, a6 jsr (a6) bsr InfoTitle addq.w #1, (a7) // font=2 = huge font jsr (a6) // jsr tios::FontSetSys addq.l #2, a7 lea Archive(PC), a0 // "* Archive *" moveq #INFO_WIDTH/2-4*11, d0 // x moveq #(INFO_HEIGHT-10)/2, d1 // y move.w #4, d2 // color jsr brwselib::InfoString bra DisplayFree // display the amount of free memory // rts in 'DisplayFree´ /**************************************************************************** * Callback routine that is called when the user presses enter on the * chosen archive/program * * Input: * d0.w = handle of program * Output: * d4 = continue browsing ? */ Enter: move.w d0, d1 tios::DEREF d1,a5 // a5 = pointer to program's begin addq.l #2, a5 cmpi.w #'AR', (a5) // check, whether it is an archive or a program beq \Archive // it is a program bsr LaunchProgram bra \End \Archive: // it is an archive lea 4(a5), a6 // a6 = pointer to file list adda.w (a6), a5 // a5 = pointer to shrink archive in the string var lea ArcInfo(PC), a2 // a2 = info callback routine lea LaunchArcPrgm(PC), a3 // a3 = enter-pressed callback routine lea Title(PC), a4 // a4 = pointer to title jsr brwselib::SurfList \End: sf d4 // continue browsing rts /**************************************************************************** * Filter callback routine * Input: d0.w = handle of variable * Output: d4.b = show this file in the list ? */ FargoFilter: tios::DEREF d0, a0 move.l a0, a1 // Check whether Fargo II prgm addq.l #4, a1 // check Fargo II signature 'EXE APPL' cmpi.l #'EXE ', (a1)+ bne \BadF2 cmpi.l #'APPL', (a1) bne \BadF2 move.w 22(a0), d0 // check, whether there is a comment beq \BadF2 // relative pointer = 0: No comment cmpi.b #16, 0(a0,d0.w) // check whether comment begins with char(16) beq \BadF2 // (that's why FPL can't launch itsself) \Ok: sf.b d4 // return: Add file to list rts // Check whether Fargo 0.1.x prgm \BadF2: addq.l #2, a0 cmpi.l #$00503130, (a0) // check Fargo 0.1.x signature '\x0P10' beq \Ok // Check whether Shrink Archive cmpi.l #'ARC'*256, (a0) // check Shrink Archive signature 'A' 'R' 'C' #0 sne d4 rts /*********************** ** FargoInfo * * Display the amount of free memory in the status bar * Destroyes d0-d3/a0-a2 */ DisplayFree: // Get the amount of free memory lea tios::globals, a2 move.l $18F6(a2), d0 // d0 = amount of free memory (if there wouldn't be any handles) subi.l #tios::globals+$3474, d0 moveq #0, d1 // d1 = size of curent block (has to be extended word->long) move.l tios::Heap, a0 // a0 = pointer after heap table move.w $18EC(a2), d2 // d2 = number of handles in heap table subq.w #1, d2 // d2 = loop counter \Loop: movea.l (a0)+, a1 // d3 = pointer to memory block move.l a1, d3 beq \Skip move.w -2(a1), d1 // d1 = size of memory block (words) lsl.w #1, d1 // = size of memory block (bytes) sub.l d1, d0 // substract it from the free memory subq.l #4, d0 // also substract memory for handle \Skip: dbra d2, \Loop move.l d0, -(a7) // value to be displayed pea MemFree(PC) // format string lea TmpStr, a2 // output buffer pea (a2) jsr tios::sprintf pea (a2) // tios::sprintf modifies the stack :-(( jsr tios::ST_showHelp // display the buffer lea 4*4(a7), a7 rts /*********************** ** FargoInfo * * Clear the info window of the browser and display a title bar with the title, given by a3. * Input: a3.l = pointer to title * Output: d0-d3/d5-d6/a0/a4 destroyed */ InfoTitle: jsr brwselib::ClearInfo moveq #INFO_WIDTH/2+3, d0 // -> get X-coordinate of centered title (d0) move.l a3, a0 \gXLp: subq.w #3, d0 tst.b (a3)+ bne \gXLp moveq #2, d1 // -> Y = 3 moveq #4, d2 // -> Color = black on white jsr brwselib::InfoString // Invert title lea tios::main_lcd+(INFO_Y1+1)*30+(INFO_X1)/8,a0 moveq #10-1, d5 // d5 = Y-counter \InvLp: move.l a0, a4 eor.w #INFO_MASK1, (a4)+ // invert beginning moveq #(INFO_WIDTH)/16-2, d6 // d6 = X-counter \_InvL: not.w (a4)+ // invert line dbra d6, \_InvL eor.w #INFO_MASK2, (a4) // invert end lea 30(a0), a0 // go to next row dbra d5, \InvLp rts /**************************************************************************** * Displays an info on the choosen Fargo Programm, in the Info-window of the * brwselib::Browse - browser. * (brwselib::Browse - callback) */ FargoInfo: tios::DEREF d0, a1 //* a1 = pointer to variable begin lea brwselib::InfoString, a6 //* a6 = brwselib::InfoString (often used) /***** Get Information *********/ cmpi.w #'2', 2(a1) // is it a Fargo II programm ? bne \NotFargo2 // Fargo II move.w $16(a1), d0 // get pointer to comment sne d4 //* d4 = Comment? lea 0(a1, d0.w), a3 //* a3 = Pointer to comment move.w $12(a1), d0 // get pointer to import table lea 0(a1, d0.w), a2 move.w (a2)+, d7 //* d7 = number of required libraries move.w (a2)+, d0 lea 0(a1, d0.w), a2 //* a2 = pointer to first lib name bra \Disp \NotFargo2: cmpi.w #'P', 2(a1) // is it a Fargo 0.1.x program ? bne \NotFargo1 // Fargo 0.1.x moveq #110, d0 // Print "Fargo 0.1.x" moveq #14, d1 moveq #2, d2 lea Fargo01xPrgm(PC), a0 jsr (a6) // jsr brwselib::InfoString move.w $0E(a1), d0 // get pointer to comment sne d4 //* d4 = Comment? lea 2(a1, d0.w), a3 //* a3 = Pointer to comment move.w $08(a1), d0 // get pointer to library linking table #1 lea 2(a1, d0.w), a2 move.w (a2)+, d7 //* d7 = number of required libraries //* a2 = pointer to first lib name // Shrink Archive \NotFargo1: lea Archive(PC), a3 //* a3 = Pointer to comment ("* Archive *") moveq #1, d4 //* d4 = Comment? = 1 means: archive /***** Display Information *****/ \Disp: // Print Comment tst.w d4 // is there a comment ? bne \Com suba.l a3, a3 // a3 = zero -- no comment \Com: bsr InfoTitle // Draw rectangle moveq #8, d0 // draw rectangle for the Library-display moveq #30, d1 move.w #INFO_WIDTH-8, d2 moveq #32+8*4+6, d3 jsr brwselib::InfoRect addq.w #6, d0 // print " Required Libraries " or " Files " subq.w #4, d1 // d0|d1 = position; d2 = color moveq #4, d2 moveq #4-1, d6 // d6 = row-counter moveq #3-1, d5 // d5 = colunmn-counter subq.w #1, d4 // if d4 == 1: we have an archive beq \ArchiveDisp // Print Required Libraries (a2 = *lib; d7 = #libs) lea RequiredLibs(PC), a0 // print " Required Libraries " jsr (a6) // jsr brwselib::InfoString moveq #12, d0 // arguments for InfoString moveq #36, d1 // (d2 is still the color) move.l a2, a0 // (a2 = pointer to first lib name) subq.w #1, d7 bmi \NoLib /**************** Print libraries **************/ \Loop2: jsr (a6) // jsr brwselib::InfoString dbra d7, \_NxLp // all libraries displayed ? bra \NoLib // -> exit loop \_NxLp: tst.b (a0)+ // get a0 = pointer to next lib name bne \_NxLp addq.w #8, d1 dbra d6, \_OK // last row ? moveq #36, d1 // -> goto first row moveq #4-1, d6 add.w #48+8, d0 // -> goto next column dbra d5, \_OK // last column ? bra \NoLib // -> display no more libraries \_OK: bra \Loop2 \NoLib: /***********************************************/ bra \DispSize \ArchiveDisp: // Print archive contents lea Files(PC), a0 // print " files " jsr (a6) // jsr brwselib::InfoString moveq #12, d0 // arguments for InfoString moveq #36, d1 // (d2 is still the color) lea 8(a1), a2 move.w (a2)+, d7 // d7 = number of files in archive, a0 = ptr to first file lea TmpStr, a0 // a0 = pointer to temporal, zero terminated string clr.b 8(a0) \Loop3: move.l (a2)+, (a0) // copy filename to zero terminated string move.l (a2)+, 4(a0) jsr (a6) // jsr brwselib::InfoString subq.w #1, d7 // decrease number of files to display beq \NoFiles // number of files = 0 -> exit loop lea 4(a2), a2 // go to next filename addq.w #8, d1 // go to next row dbra d6, \_ok // last row ? moveq #36, d1 // -> go to first row moveq #4-1, d6 add.w #48+8, d0 // -> go to next column dbra d5, \_ok // last column ? bra \NoFiles // -> display no more files \_ok: bra \Loop3 \NoFiles: /***********************************************/ \DispSize: // Draw "Size: xxxx" move.w (a1), -(a7) // push Program's/Archive's size addq.w #2, (a7) pea Size(PC) lea TmpStr, a2 // a2 = pointer to temporal string pea (a2) jsr tios::sprintf lea 10(a7), a7 moveq #8, d0 // arguments for InfoString moveq #84, d1 moveq #2, d2 movea.l a2, a0 jsr (a6) // jsr brwselib::InfoString bra DisplayFree // display the amount of free memory // rts in 'DisplayFree´ /*************************************************************************** * MAIN ***************************************************************************/ _main: lea FargoFilter(PC), a0 // Filter callback lea FargoInfo(PC), a1 // Info callback lea Enter(PC), a5 // Enter-pressed callback lea Title(PC), a4 // Title string jsr brwselib::Browse rts /*************************************************************************** * DATA ***************************************************************************/ _comment: dc.b 16, "Fargo Program Launcher", 0 Title: dc.b "FPL II - by David Kühling 1999", 0 Extracting: dc.b "Extracting...", 0 ExtractError: dc.b "Invalid archive or not$enough memory", 0 Fargo01xPrgm: dc.b "Fargo 0.1.x", 0 Archive: dc.b "* Archive *", 0 RequiredLibs: dc.b " Required Libraries ", 0 Files: dc.b " Files ", 0 MemFree: dc.b "Memory Free: %li bytes", 0 Size: dc.b "Size: %u bytes", 0 Error: dc.b "ERROR", 0 Question: dc.b "QUESTION", 0 QuestionFS: dc.b "%s$ [ENTER]=Yes [ESC]=No", 0 RestoreInts: dc.b "Vector table has been$modified. Restore it?$", 0 FreeMem: dc.b "Allocated memory left.$Set it free?$", 0 OrigCommand: dc.w 0 // stores the original command, that was replaced by trap #12 RunTimeError: dc.w 0 // stores the errornumber, if a runtime error occured BSS TmpStr: ds.b 30 OldUSP: ds.l 1 OldSSP: ds.l 1 OldVideoRAM: ds.w 1 OldVectorTable: ds.l 48 // for all vectors (to notice and restore modifications) HandleInfo: ds.b MAX_HANDLES/8 // each bit stores, whether a handle is allocated or not END