; Copyright 1996 Acorn Computers Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; SUBT > Sources.FSControl ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; + + ; + F S C O N T R O L S W I + ; + + ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; FSControlEntry. Vectored SWI level entry ; ============== ; ; Perform various actions in FileSwitch analogous to JMI (FSCV) on BBC micro ; Filename parameters are all GSTRANSed in the standard Filing System way ; In r0 = action requested, various parms (NB. Not r0b) ; Out VC: Action performed, r0 preserved (frequently) ; VS: Something terrible has happened, r0 -> error block FSControlEntry ROUT [ debugcontrolentry DREG r0,"Doing FSControl ",cc DREG r1," arg1 ",cc DREG sp,", sp = " ] CMP r0, #FSControl_Max JTAB r0, LO, FSControl ; Good rc if LO B FSControl_BadReason ; Check reason codes against &.Hdr.File JTE DirEntry, FSControl_Dir JTE LibEntry, FSControl_Lib JTE StartApplicEntry, FSControl_StartApplication JTE RunTypeEntry, FSControl_RunType JTE RunEntry, FSControl_Run JTE CatEntry, FSControl_Cat JTE CatEntry, FSControl_Ex ; Same as Cat JTE CatEntry, FSControl_LCat JTE CatEntry, FSControl_LEx JTE InfoEntry, FSControl_Info ; Same as Cat JTE OptEntry, FSControl_Opt JTE SetFromNameEntry, FSControl_StarMinus JTE AddFSEntry, FSControl_AddFS JTE LookupFSEntry, FSControl_LookupFS JTE SelectFSEntry, FSControl_SelectFS JTE BootupFSEntry, FSControl_BootupFS JTE RemoveFSEntry, FSControl_RemoveFS JTE AddSecondaryFSEntry, FSControl_AddSecondaryFS JTE ReadFileTypeEntry, FSControl_ReadFileType JTE RestoreCurrEntry, FSControl_RestoreCurrent JTE ReadTempModEntry, FSControl_ReadModuleBase JTE ReadFSHandle, FSControl_ReadFSHandle JTE ShutFilesEntry, FSControl_Shut JTE ShutDownEntry, FSControl_ShutDown JTE AccessEntry, FSControl_Access JTE RenameEntry, FSControl_Rename [ hascopy JTE CopyEntry, FSControl_Copy | JTE FSControl_BadReason ] [ haswipe JTE WipeEntry, FSControl_Wipe | JTE FSControl_BadReason ] [ hascount JTE CountEntry, FSControl_Count | JTE FSControl_BadReason ] JTE FSControl_BadReason, FSControl_CreateHandle JTE ReadSecModEntry, FSControl_ReadSecondaryModuleBase JTE FileTypeFromStringEntry, FSControl_FileTypeFromString JTE InfoEntry, FSControl_FileInfo JTE ReadFSNameEntry, FSControl_ReadFSName JTE FSControl_BadReason, FSControl_SetContexts ; New reason codes introduced since 1.70 JTE AddImageFSEntry, FSControl_RegisterImageFS JTE RemoveImageFSEntry, FSControl_DeRegisterImageFS JTE CanonicalisePathEntry, FSControl_CanonicalisePath JTE InfoToFileTypeEntry, FSControl_InfoToFileType JTE URDEntry, FSControl_URD JTE BackEntry, FSControl_Back JTE DefectListEntry, FSControl_DefectList JTE AddDefectEntry, FSControl_AddDefect JTE NoDirEntry, FSControl_NoDir JTE NoURDEntry, FSControl_NoURD JTE NoLibEntry, FSControl_NoLib JTE UsedSpaceMapEntry, FSControl_UsedSpaceMap JTE ReadBootOptionEntry, FSControl_ReadBootOption JTE WriteBootOptionEntry, FSControl_WriteBootOption JTE ReadFreeSpaceEntry, FSControl_ReadFreeSpace JTE NameDiscEntry, FSControl_NameDisc JTE StampImageEntry, FSControl_StampImage JTE ObjectAtOffsetEntry, FSControl_ObjectAtOffset JTE SetDirEntry, FSControl_SetDir JTE ReadDirEntry, FSControl_ReadDir JTE ReadFreeSpace64Entry, FSControl_ReadFreeSpace64 JTE DefectList64Entry, FSControl_DefectList64 JTE AddDefect64Entry, FSControl_AddDefect64 ; New reason code introduced since 2.73 JTE EnumerateHandlesEntry, FSControl_EnumerateHandles FSControl_Max * (.-$JumpTableName) :SHR: 2 FSControl_BadReason addr r0, ErrorBlock_BadFSControlReason BL copy_error [ No26bitCode Pull pc ; copy_error sets V | Pull lr ORRS pc, lr, #V_bit ] ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; RunEntry. Top level FSControl entry ; ======== ; ; Run a file from the temporary Filing System ; In r1 -> filename (space, CtrlChar term) and command line (CtrlChar term) ; Out if it doesn't return: ; current FS restored, program running or aborted ; if it does return: ; VC: file has been run ok (eg. *EXECed OR PIC transient) ; VS: error in running or file returned badly RunTypeEntry ; for the mo. RunEntry NewSwiEntry "r0-r3" [ debugrun DREG sp,"run sp in = " ] BL FS_SkipSpaces ; Saves code to have this here ; Allows */ fred etc. BCC %FA99 ; [*/ with no arg] ADR r0, CommandLine BL SGetLinkedString ; May have spaces in it, so watch out ! BVS %FA98 ; Nothing to deallocate [ debugrun DSTRING r1,"Trying to run " ] BL SkipOverNameAndSpaces STR r1, commandtailptr LDR r1, CommandLine BL TryRunningFile BL SFreeCommandLine 98 SwiExit 99 addr r0, ErrorBlock_BadCommand BL CopyError B %BT98 ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; TryRunningFile ; ============== ; ; Split off from main RUN entry for ease of error handling / exiting ; In r1 -> filename (space, CtrlChar term) and command line (CtrlChar term) ; Out if it doesn't return: ; current FS restored, program running or aborted ; if it does return: ; VS: error has been set ; VC: file has been run ok (eg. *EXECed OR PIC transient) TryRunningFile Entry "r0-r6,fscb" ; Try not to keep too much stacked for RUN [ debugrun DSTRING r1, "tryrunning " ] ; Process the path. ; Result is definitely a pure file. BL TopPath_DoBusinessToPathForRun BVS RunExit [ debugrun DREG r0, "ft after business is " ] ; Translate L=0or-1 and E=-1 to L=&fffffeff and E=-1 for old style command files CMP r2, #0 CMPNE r2, #-1 CMPEQ r3, #-1 LDREQ r2, =&FFFFFE00+&FF ; Is the file typed? BL IsFileTyped BNE Run_UndatedFile MOV r0, r2, ASR #8 ; File type now in the lowest 12 bits CMP r0, #&FFFFFFF8 ; Type FF8 ? BEQ Run_Absolute8000File CMP r0, #&FFFFFFFC ; Type FFC ? BEQ Run_TransientFile ; ............................................................................. ; In r2 = load address to decode ; If a temporary filing system was specified, ; and [FullFilename] doesn't contain a filing system prefix, ; then prefix FullFilename with the temporary filing system name. Run_UnrecognisedFile LDR r3, commandtailptr ; Can supply a command tail to append ADR r4, RunActionPrefix addr r5, ErrorBlock_UnknownRunAction BL ReadActionVariable ; Leaves r0 -> action vbl (pushed) BVS RunExit_FF [ debugrun DSTRING r0, "OS_CLI on " LDR r14, globalerror TEQ r14, #0 BEQ %FT01 DLINE "Error given before OS_CLI" B %FT02 01 DLINE "No error before OS_CLI" 02 ] SWI XOS_CLI BLVS CopyErrorExternal [ debugrun LDR r14, globalerror TEQ r14, #0 BEQ %FT01 DLINE "Error given after OS_CLI" B %FT02 01 DLINE "No error after OS_CLI" 02 ] ADR r0, ActionVariable BL SFreeLinkedArea ; Accumulate V ; ............................................................................. Run_Common_NoCopy CMPVC r0, r0 ; EQ -> file run ok ; ............................................................................. ; In CommandLine, PassedFilename, FullFilename and SpecialField ; to be deallocated RunExit_FF BL JunkFileStrings RunExit EXIT RunActionPrefix DCB "Alias$@RunType_" ; Shared zero with ... 66 DCB 0 ALIGN ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Type FF8 Run_Absolute8000File MOV r2, #&8000 ; Load at &8000 MOV r3, r2 ; And execute it there ; ............................................................................. Run_UndatedFile [ debugrun DREG r3,"Running file at &" ] CMP r2, #&8000 ; Can't load anything below 32K now BLO %FA92 ; BIC r3, r3, #ARM_CC_Mask ; Form sensible ARM address for exec ADD r5, r2, r4 ; Does exec address live in the code ? SUB r14, r5, #1 ; Stops zero length files running too CMP r3, r2 ; ie. start <= exec < (start+length) RSBGES r14, r3, r14 BLT %FA93 ; LT -> not in range (ie. not in code) BL ValidateR2R5_WriteToCoreCodeLoad BVS RunExit_FF MOV r7, r4 MOV r4, r2 LDR r5, PassedFilename addr r0, anull ; Null command tail fudge MOV r2, r3 ; CAO address := entry point of file LDR r3, CommandLine BL StartUpTheApplication ; Which restores current FS BVS RunExit_FF [ AssemblingArthur LDR r0, =EnvString ; r0 -> copy of run string | LDR r0, EnvStringAddr ; r0 -> copy of run string ] MOV r1, r0 ; NB. Our strings are all dead now BL SkipOverNameAndSpaces ; r1 -> copy of command tail LDR r10, SVCSTK ; remember top of stack ;Check whether it's a squeezed app. CMP r2, #&8000 BNE %FT77 ;Not an 'APP' (type FF8) [ StrongARM LDR lr, [r2] ;To save unnecessary hassle, weed out the uncompressed cases... MOV r3, #&E1000000 ORR r3, r3, #&00A00000 ; Gives us 'MOV R0,R0' in R5 TEQ lr, #&FB000000 ; BLNV 0 at &8000? If so, it's C rel 5 vintage. TEQNE lr, R3 ; MOV R0,R0? MOVEQ r3, r7 ; Bung the code size in R3. BEQ %FT76 ; Not compressed, so skip the pre-decompression call [ debugsarm DLINE "It's a compressed App" ] [ {FALSE} ; leave this up to client module(s) ;Are we on a StrongARM? MOV r0, #0 SWI XOS_PlatformFeatures TST r0, #1 ; Is the 'synchronise code areas' bit set? ;If so, turn the caches & WB off... MOVNE r2, #&FFFFFFF9 ; Caches/WB off MOVEQ r2, #-1 ; Leave 'em as-is MOV r0, #0 MOV r1, #0 SWI XOS_MMUControl Push "r1" ; Remember the old cache setting ] ; Check memory before decompression, since decompression code is dumb MOV r2, #&8000 BL CheckAIFMemoryLimit ; Ignore any returned error since nonstandard compression may confuse our memory usage calculations MOV r0, #0 ; Pre-decompression service call MOV r1, #Service_UKCompression MOV r3, r7 MOV r4, #&8000 SWI XOS_ServiceCall ; A claimant of this does the decompression [ {FALSE} ; leave this up to client module(s) ;Switch the caches back to the previous state and fire off another service call. Pull "r1" MOV r0, #0 MOV r2, #0 SWI XOS_MMUControl ] 76 MOV r0, #1 ; Post-decompression service call MOV r1, #Service_UKCompression MOV r2, #&8000 SWI XOS_ServiceCall ;unsqueezer or patcher(s) are responsible for any code synchronising which ;is neccessary for internal code/poking handling, but we do a Synchronise here ;to sync with the finally unsqueezed and patched up code MOV r0, #0 SWI XOS_SynchroniseCodeAreas ] BL CheckAIFMemoryLimit BVC %FT71 ; /* dead here - need to generate an error */ addr r0, ErrorBlock_CoreNotWriteable MOV r1, #0 SWI XMessageTrans_ErrorLookup SWI OS_GenerateError 71 [ StrongARM ;Finally, prepare to run the thing! MOV r2, r4 ; We're gonna jump in where we're told!. ] 77 MOV sp, r10 ; Flatten superstack, we don't return WritePSRc 0, r12 ; USR mode, all ints on MOV r12, #&80000000 ; Cause address extinction if used MOV r13, #&80000000 ; (keep 1.20 compat capable) ADR lr, ReturnFromAbsoluteCode MOV pc, r2 ; Go to it ! ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Type FFC ; Offsets in transient PIC RMA block ^ 0 transient_savearea # 4*6 ; SaveArea for r6-r9, r13_usr, r14_usr transient_code # 0 transient_ws * &0400 Run_TransientFile ; Claim a RMA block for the transient ADD r5, r4, #transient_code ; Need length of file + my block size ADD r5, r5, #3 ; Word align for wp,sp_usr below BIC r5, r5, #3 ; Remember r5: used for ws below ! ADD r3, r5, #transient_ws ; Plus some workspace for it BL SGetLinkedTransientArea BVS RunExit_FF BEQ %FA94 ; No room ? ; Need to preserve any registers that haven't been saved for EXIT so that ; transients may call other transients, preserving all registers + state ; Use a save area on the front of the code block for these. ; r10-r12 assumed to be preserved by the main SWI handler. ASSERT transient_savearea = 0 [ SASTMhatbroken STMIA r2!,{r6-r9} STMIA r2, {r13,r14}^ ; Must preserve r13_usr and r14_usr SUB r2, r2, #4*4 ; r0-r5 already stacked | STMIA r2, {r6-r9, r13-r14}^ ; Must preserve r13_usr and r14_usr ; r0-r5 already stacked ] ; Load the code after the info block MOV r0, #object_file ADD r3, r2, #transient_code [ StrongARM [ debugsarm DLINE "Loading a StrongARM transient" ] MOV r2, #1 STRB r2, codeflag ] LDR r2, PassedFilename BL int_DoLoadFile BVS %FT88 LDR r0, CommandLine addr r1, %BA66 ; Null command tail fudge (shared) BL CopyCommandLineAndReadTime ; Don't flatten superstack for PIC objects as they return to me ! Push "fp, wp" ; Need to remember these for return LDR r0, CommandLine LDR r1, commandtailptr WritePSRc 0, wp ; USR mode, all ints on ADD r5, r3, r5 ; r12 -> transient workspace. Not bank SUB wp, r5, #transient_code ; Must correct as r5 = info + code ; and r2 = code^ ADD sp, wp, #transient_ws ; r13 -> small stack in the above ws ADR lr, ReturnFromPIC ; No point in having mode bits set MOV pc, r3 ; Go to it ! ; Failed to load transient after allocating space 88 LDR r0, globalerror ; fp is valid, of course ... MOV r1, #V_bit B DeleteTransient ; ***************************************************************************** ; Foulup time during runs 92 addr r0, ErrorBlock_ExecAddrTooLow B %FT98 93 addr r0, ErrorBlock_ExecAddrNotInCode B %FT98 94 addr r0, ErrorBlock_NoRoomForTransient 98 BL CopyError ; VSet too B RunExit_FF LTORG CheckAIFMemoryLimit ROUT Entry "r5" ; Check absolute AIF memory limits ; R2 = &8000 ; R0-R1 corruptible ; V set/clear on exit for bad/good LDR lr, [r2, #&0C] AND lr, lr, #&FF000000 TEQ lr, #&EB000000 ; is this instruction a branch BNE %FT90 ; nope - not executable AIF then LDR lr, [r2, #&10]! ; should be SWI OS_Exit (&EF000011 for AIF), R2 := R2 + 16 SUB lr, lr, #&EF000000 TEQ lr, #&00000011 ; OS_Exit check worked? LDMEQIB r2, {r0,r1,r5,lr} ; load RO size, RW size, Debug size, ZI size MOV r2, #&8000 ; R2 := &8000 like it was before BNE %FT90 ; not AIF then ADD lr, lr, r5 ; lr := debug + zero init ADD r0, r0, r1 ; R0 := read only + read write ADD r0, r0, lr ; R0 := read only + read write + debug + zero init ADD r0, r0, #&2000 ; 8K extra to avoid "Not enough memoy for C library" from silly C stubs ADD r5, r2, r0 ; R5 := base address + size required BL ValidateR2R5_WriteToCoreCodeLoad EXIT 90 CLRV EXIT ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; This is where position independent code will return to if it does MOV pc, lr ; Error may be in transient's workspace, so copy before deleting block ReturnFromPIC SavePSR r1 ; Remember V, you whalley (SWI clears) SWI XOS_EnterOS ; Get back to superstate in all cases Pull "fp, wp" ; Sanity slowly restoring ... ; ............................................................................. ; In fp, wp valid ; r1 = psr ; r0 -> error block if r1 has V set DeleteTransient ; Delink this block from the transient list now that it has returned ; Restore saved registers from the block LDR r2, TransientBlock LDMIA r2, {r6-r9, r13-r14}^ ; Writing to r13,r14_usr TST r1, #V_bit ; Did it report error ? BLNE CopyErrorExternal ADR r0, TransientBlock BL SFreeLinkedArea ; Accumulates V B Run_Common_NoCopy ; Lots of deallocation there ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; This is where absolute code will return to if it does MOV pc, lr ; If it did an Exit then the guy with the exit handler has it ! ; We'd better do the SWI Exit for it; as the superstack is flat we can't return ; ; In r0-r2 optionally set such that a return code may be set by called code ReturnFromAbsoluteCode SWI OS_Exit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; ReadActionVariable ; ================== ; ; Reads Alias$@xxxType_ttt for given ttt and substitutes filename and cmdline ; into the variable as read. ; In r1 = path tail ; r2 = load address to decode (000ttt00) ; r3 -> command tail to append after FullFilename ; r4 -> variable prefix, eg 'Alias$@LoadType_' ; r5 -> bit of text to put in error if variable unset ; r6 = special/scb ; fscb^ set ; filename plugged in is canonical form ; Out VC: r0 -> string to do with as you wish ; string is in ActionVariable, just dying to be freed ReadActionVariable Entry "r1-r4, r6" ; r0 result [ debugcontrol :LOR: debugrun DREG r2, "Action variable for load=",cc DSTRING r3, " with command tail ",cc DSTRING r4, " onto variable with prefix ",cc DSTRING r5, " with error text " ] ^ 0, sp rav_varname # 32 ; Variable name is small ; as it might be a macro variable rav_size * :INDEX: @ SUB sp, sp, #rav_size ; Room for the variable string + result ADR r3, rav_varname 05 LDRB r14, [r4], #1 ; Copy variable name in TEQ r14, #0 STRNEB r14, [r3], #1 ; No terminator; leave r3 -> next byte BNE %BT05 MOV r2, r2, LSR #8 ; Shift -> 00000ttt for common code BL ConvertHex3 ; Get alias$@runtype_xxx filename commandline in a buffer ADR r0, rav_varname ; Point at string again MOV r3, #0 20 MOV r2, #-1 SWI XOS_ReadVarVal ; Does it exist ? VSet misleading CMP r4, #VarType_Number ; Set if it's a number (that's silly) BEQ %BT20 ; Loop if so (maybe others) MOVS r2, r2 ; -ve -> exists BPL %FA90 ; [nope, -> Unknown run type] ; Variable exists, so copy RunType_xxx filename commandline to buffer LDR r1, =ScratchSpace ADR r2, rav_varname + (:LEN: "Alias$") BL strcpy_advance ADR r2, s_space BL strcpy_advance RSB r3, r1, #ScratchSpace + ?ScratchSpace MOV r2, r1 LDR r1, [sp, #rav_size + 0*4] ; r1 in BL int_ConstructFullPathWithError BVS %FT88 MOV r1, #ScratchSpace LDR r2, [sp, #rav_size+4*2] ; Rest of line from caller r3 BL AppendStringIfNotNull [ debugrun DSTRING r1, "Substituted string is " ] ADR r0, ActionVariable ; Wop this into a string BL SGetLinkedString ; May have spaces in it LDRVC r0, ActionVariable ; And return a pointer to it. Phew ! 88 ADD sp, sp, #rav_size EXIT s_space DCB " ", 0 ; insert before filing system name s_colon DCB ":", 0 ; insert after filing system name s_hash DCB "#", 0 ; Inserted before special field ALIGN 90 MOV r0, r5 ; Stick the appropriate bit in BL CopyError B %BT88 ; Get out ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; In r2 = number ; r3 -> core ; Out r2, r3 preserved ; core contains 'abc', 0 ConvertHex3 Entry "r1" MOV r1, #8 ; MSN at base bit 8 BL NibbleToText STRB r1, [r3, #0] MOV r1, #4 ; CSN at base bit 4 BL NibbleToText STRB r1, [r3, #1] MOV r1, #0 ; LSN at base bit 0 STRB r1, [r3, #3] ; Terminate string too BL NibbleToText STRB r1, [r3, #2] EXIT ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; In r1 = bitfield base ; r2 = number ; Out r1 = nibble at bitfield converted to base 16 NibbleToText Entry MOV r1, r2, ROR r1 AND r1, r1, #15 CMP r1, #10 ADDLO r1, r1, #"0" ADDHS r1, r1, #"A"-10 EXIT ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; StartApplicEntry. Top level FSControl entry ; ================ ; In r1 -> command tail to append to EnvString ; r2 = CAO ptr to write ; r3 -> command name (first bit) to copy to EnvString StartApplicEntry NewSwiEntry "r0" [ debugrun DLINE "StartApplicEntry" ] MOV r0, r1 MOV r1, #0 BL StartUpTheApplication [ debugrun LDR r14, globalerror TEQ r14, #0 BEQ %FT01 DLINE "Globalerror at end of startapplicentry" B %FT02 01 DLINE "No error after startapplicentry" 02 ] SwiExit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; StartUpTheApplication ; ===================== ; In r0 -> command tail to append to EnvString ; r1 -> file to load (at fileblock_load) if non zero ; r2 = CAO ptr to write ; r3 -> command name (first bit) to copy to EnvString ; r4 = address to load file to if r1!=0 ; r5 -> filename to quote on error if r1!=0 ; r6 = file handle/special field^ if r1!=0 ; r7 = length of file if r1!=0 ; fscb^ if r1!=0 ; Out VC: all ready to go ; else error raised with OS_GenerateError as application destroyed ; All linked areas in this domain freed ; Current FS restored StartUpTheApplication Entry "r0-r7,fscb" ; Copy command line *before* UpCalling etc to ensure it ; doesn't get destroyed before needed MOV r1, r0 MOV r0, r3 BL CopyCommandLineAndReadTime [ debugrun DREG r2,"StartUpTheApplication: CAO ",cc DSTRING r1, ", filename ",cc DSTRING r3, ", ComName ",cc DSTRING r0, ", ComTail " ] MOV r0, #UpCall_NewApplication SWI XOS_UpCall ; After application gets called CMP r0, #UpCall_Claimed ; to release handlers we can't give BEQ %FA95 ; it a VSet return - it's not there MOV r1, #Service_NewApplication SWI XOS_ServiceCall ; Can never give error CMP r1, #Service_Serviced BEQ %FA96 ; Must give serious exception type err ; try out the pervy scheme for removing handlers Push "r0-r5" MOV r0, #MemoryLimit MOV r1, #0 SWI XOS_ChangeEnvironment MOV r5, r1 MOV r0, #ExitHandler MOV r1, #0 MOV r2, #0 MOV r3, #0 SWI XOS_ChangeEnvironment CMP r1, r5 BLT application_is_shelling MOV r0, #UndefinedHandler remove_naff_handlers MOV r1, #0 MOV r2, #0 MOV r3, #0 SWI XOS_ChangeEnvironment CMP r1, r5 SWILT XOS_ReadDefaultHandler SWILT XOS_ChangeEnvironment ADD r0, r0, #1 CMP r0, #ExceptionDumpArea MOVEQ r0, #UpCallHandler CMP r0, #UpCallHandler BLS remove_naff_handlers ASSERT UpCallHandler+1=MaxEnvNumber ; any added handlers need consideration application_is_shelling Pull "r0-r5" LDR r1, [sp, #4] ; Use passed name as flag CMP r1, #0 ; Sam calling ? VClear BEQ %FT10 ; Load file as requested ADD r14, sp, #4*4 LDMIA r14, {r3,r5-r7,fscb} MOV r0, #object_file MOV r2, r5 [ StrongARM [ debugsarm DLINE "Loading a StrongARM app" ] MOV r4, #1 STRB r4, codeflag ] MOV r4, r7 BL int_DoLoadFile BVS %FT97 ; Restore r2,r3 afterwards ADD r14, sp, #2*4 LDMIA r14, {r2,r3} 10 ; Can now set CAO, copy the string + read time for GetEnv MOV r0, #CAOPointer MOV r1, r2 [ debugrun DREG r2, "Setting CAO pointer to " ] SWI XOS_ChangeEnvironment BL SFreeAllLinkedAreas ; Only in the current domain ; Restore TempFS to be CurrentFS BL ReadCurrentFS MOVVC r2, r0 BL SetTempFS EXIT 95 addr r0, ErrorBlock_CantStartApplication ; UpCall claimed BL CopyError EXIT 96 addr r0, ErrorBlock_CantStartApplication ; Service claimed BL CopyError 97 BL SFreeAllLinkedAreas ; Only in the current domain ; Restore TempFS to be CurrentFS BL ReadCurrentFS MOVVC r2, r0 BL SetTempFS LDR r0, globalerror ; Must explode as application has SWI OS_GenerateError ; got its hooks out ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; In r0 -> command first bit ; r1 -> command tail to append CopyCommandLineAndReadTime Entry "r0-r2" [ debugrun DSTRING r0, "CopyCommandLineAndReadTime: First bit ",cc DSTRING r1, ", command tail " ] [ AssemblingArthur LDR r1, =EnvString | LDR r1, EnvStringAddr ] MOV r2, r0 ; Command name^ BL strcpy LDR r2, [sp, #4] ; Append command tail to that BL AppendStringIfNotNull [ debugrun DSTRING r1, "EnvString now " ] MOV r0, #14 [ AssemblingArthur LDR r1, =EnvTime | LDR r1, EnvTimeAddr ] MOV r14, #3 STR r14, [r1] SWI XOS_Word ; ReadTime shouldn't give error CLRV ; So make like it didn't ! EXIT LTORG ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; In r2 -> string (CtrlChar term) to append to r1 string AppendStringIfNotNull Entry "r2" [ debugrun DSTRING r2, "AppendStringIfNotNull: " ] CMP r2, #1 LDRHSB r14, [r2] ; Is string empty ? CMPHS r14, #space ADRHS r2, %FT90 ; space BLHS strcat LDRHS r2, [sp] ; string BLHS strcat EXIT 90 DCB space, 0 ALIGN ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Ones that can be commoned up ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; LibEntry. Top level FSControl entry ; ======== ; In r1 -> command tail LibEntry NewSwiEntry "r0,r2,r7,fscb" ; FSFunc only preserves r6 up ; LibD = user's request MOV r2, #Dir_Library BL ChangeDirectory SwiExit ; ............................................................................. ; ; CatEntry. Top level FSControl entry ; ======== ; In r1 -> command tail (for Cat, Ex, Info) CatEntry NewSwiEntry "r0-r7,fscb" ; Set up a mask for Cat/Ex TEQ r0, #FSControl_Cat TEQNE r0, #FSControl_LCat MOVEQ r7, #fsextra_FSDoesCat MOVNE r7, #fsextra_FSDoesEx TEQ r0, #FSControl_Cat TEQNE r0, #FSControl_Ex MOVEQ r5, #0 ; Relative to @ (default) MOVNE r5, #TopPath_RelativeToLib ; Relative to % MOV r2, #NULL addr r3, anull BL TopPath_DoBusinessForDirectoryRead BVS %FT90 LDR lr, [fscb, #fscb_extra] TST lr, r7 BNE %FT20 BL int_CatExTitle BVS %FT80 ; Set up the parameters TEQ r7, #fsextra_FSDoesCat MOVEQ r0, #0 ; Cat-style body MOVNE r0, #1 ; Ex-style body addr r2, fsw_wildstar BL int_CatExBody B %FT80 20 ; FS does the operation - send it through TEQ r7, #fsextra_FSDoesCat MOVEQ r0, #fsfunc_Cat MOVNE r0, #fsfunc_Ex BL CallFSFunc_Given 80 BL JunkFileStrings 90 SwiExit ; ............................................................................. ; ; InfoEntry. Top level FSControl entry ; ========== ; In r1 -> command tail ; Performs *Info or *FileInfo InfoEntry NewSwiEntry "r0-r8,fscb" BL Process_WildPathnameMustExist BVS %FT97 TEQ r7, #NULL BEQ %FT10 ; Wildcard enumeration required MOV r2, r7 LDR r14, [fp, #0] TEQ r14, #FSControl_Info MOVEQ r0, #1 ; Ex-style body MOVNE r0, #2 ; FileInfo-style body BL int_CatExBody BL JunkFileStrings B %FT97 10 ; Check for FileInfo on filing systems which do it themselves LDR r14, [fp, #0] TEQ r14, #FSControl_Info LDRNE r14, [fscb, #fscb_info] TSTNE r14, #fsinfo_fileinfo BEQ %FT15 MOV r0, #fsfunc_FileInfo BL CallFSFunc_Given B %FT95 15 ; It's an absolute or non-wildcard which needs Infoing, so ; let's do it by hand GetLumpOfStack r8, #CatStringSpace, #CatStringSpace, #2048, %FA80 ; Find the last . in the tail to get a leaf name MOV r6, r1 20 LDRB r14, [r6], #1 TEQ r14, #"." MOVEQ r1, r6 TEQ r14, #0 BNE %BT20 ; Construct the cat and FileInfo parts in the stack buffer MOV r6, sp ADD r7, r6, r8 [ CatExLong Push "r8,r10" Push "r0-r4" SUB sp, sp, #16 MOV r2, #15 MOV r1, sp MOV r3, #0 MOV r4, #3 ; we want to convert it to a string (so that Macros will be sorted) ADRL r0, CatExMaxWidthStr ; variable name SWI XOS_ReadVarVal ; get the variable back [ debugcontrol DREG r1, "ptr: " ] MOVVS r2, #255 ; maximum limit BVS %FT30 ; variable not found or too long - ignore it CMPS r4, #1 LDREQ r2, [sp] BEQ %FT30 ; convert its value MOV r0, #0 ; terminate the string STRB r0, [sp, r2] ; MOV r0, #10+(1<<30) ; base 10, restrict range 0-255 MOV r1, sp [ debugcontrol DSTRING r1, "string: " ] SWI XOS_ReadUnsigned ; get the value [ debugcontrol DREG r2, "converted to: " ] MOVVS r2, #255 30 ; here, r2 should contain the max width, or zero ADD sp, sp, #16 CMPS r2, #255 MOVHI r2, #255 MOVS r2, r2 MOVMI r2, #12 [ debugcontrol DREG r2, "init width: " ] ; now compare screen with and entry width SUB sp, sp, #4 ADRL r0, CatExBody_WindBlock MOV r1, sp SWI XOS_ReadVduVariables LDRVC r0, [sp] ADD sp, sp, #4 STRVS r0, [sp] BVS %FT40 LDR r14, [fp, #0] TEQ r14, #FSControl_Info SUBEQ r0, r0, #63-12 TEQ r14, #FSControl_FileInfo SUBEQ r0, r0, #68-12 [ debugcontrol DREG r0, "width available from screen " ] LDR r1, [sp, #4] BL strlen CMPS r3, r0 MOVGT r3, r0 CMPS r3, r2 ; set the min width MOVGT r3, r2 CMPS r3, #CatExMinWidth ; and if it's <12, make it 12 MOVLT r3, #CatExMinWidth MOV r10, R3 ; and now we have a width! CLRV 40 STRVS r0, [sp] Pull "r0-r4" BVS %FT60 | Push "R8" ] LDR r14, [fp, #0] TEQ r14, #FSControl_Info MOVEQ r8, #1 ; Ex item TEQ r14, #FSControl_FileInfo MOVEQ r8, #2 ; FileInfo item BL int_CatExItem [ CatExLong 60 Pull "r8,r10" | Pull "r8" ] ; output them MOVVC r0, sp SWIVC XOS_Write0 SWIVC XOS_NewLine ADD sp, sp, r8 B %FT85 80 addr r0, ErrorBlock_NotEnoughStackForFSEntry BL CopyError B %FT95 85 BLVS CopyErrorExternal 95 BL JunkFileStrings 97 SwiExit ; ............................................................................. ; ; AccessEntry. Top level FSControl entry ; =========== ; ; The attribute string is not checked and may contain any old junk, and should ; be assumed to be space or CtrlChar terminated ; In r1 -> filename ; r2 -> attribute string (space terminated) AccessEntry NewSwiEntry "r0-r9,fscb" [ debugcontrol DSTRING r1, "Access ",cc DSTRING r2, " to " ] MOV r9, r2 ; Find the file(s) BL Process_WildPathnameMustExist SwiExit VS [ debugcontrol DSTRING r1, "Tail from process etc is " DSTRING r7, "Leaf from .. is�" ] LDR lr, [fscb, #fscb_info] TST lr, #fsinfo_giveaccessstring MOVNE r8, r9 BNE %FT30 ; Process the access string syntax: [lLwWrR]*/[wWrR]* MOV r8, #0 10 LDRB r14, [r9], #1 CMP r14, #space TEQHI r14, #delete BLS %FT30 TEQ r14, #"l" TEQNE r14, #"L" ORREQ r8, r8, #locked_attribute BEQ %BT10 TEQ r14, #"w" TEQNE r14, #"W" ORREQ r8, r8, #write_attribute BEQ %BT10 TEQ r14, #"r" TEQNE r14, #"R" ORREQ r8, r8, #read_attribute BEQ %BT10 TEQ r14, #"/" BNE %FT95 20 LDRB r14, [r9], #1 CMP r14, #space TEQHI r14, #delete BLS %FT30 TEQ r14, #"w" TEQNE r14, #"W" ORREQ r8, r8, #public_write_attribute BEQ %BT20 TEQ r14, #"r" TEQNE r14, #"R" ORREQ r8, r8, #public_read_attribute BEQ %BT20 B %FT95 30 [ debugcontrol DREG r8, "Access value calculated is " ] TEQ r7, #NULL BNE %FT40 LDR lr, [fscb, #fscb_info] TST lr, #fsinfo_giveaccessstring BNE %FT35 ; Set access, single object, using fsfile_WriteInfo MOV r5, r8 MOV r0, #fsfile_WriteInfo BL CallFSFile_Given B %FT72 35 ; Set access, single object, using *Access entry MOV r2, r8 MOV r0, #fsfunc_Access BL CallFSFunc_Given B %FT72 40 ; Wildcard operation GetLumpOfStack r5, #CatSpace, #CatSpace, #2048, %FA90 MOV r4, #0 50 ADD r14, sp, r5 MOV r0, #fsfunc_ReadDirEntriesInfo MOV r2, sp MOV r3, #CatSpace + CatSpaceAdjustForNFS Push "r1,r5" MOV r5, #CatSpace + CatSpaceAdjustForNFS BL CallFSFunc_Given Pull "r1,r5" BVS %FT85 [ debugcontrol DSTRING r1, "Tail after read entries is " DSTRING r7, "Leaf after read entries is�" ] TEQ r3, #0 BEQ %FT75 Push "r1,r3,r4,r5" ADD r1, sp, #4*4 55 ; Fill the buffer on the stack ; pick out load, execute, length, Attributes, objecttype, advancing r1 to the object name LDMIA r1!, {r2,r3,r4,r5,r14} MOV r0, r2 MOV r2, r7 BL WildMatch BNE %FT60 MOV r2, r0 ; Construct <Tail>.<leaf> on a new piece of linked string SUB sp, sp, #4 Push "r1,r2,r3" [ debugcontrol DSTRING r1, "leaf for strlen is " ] BL strlen ; <leaf> LDR r1, [sp, #3*4 + 4 + 0*4] [ debugcontrol DSTRING r1, "tail for strlen is " ] BL strlen_accumulate ; <Tail> ADD r3, r3, #1 + 1 ; 1 for the ., and one for the terminator ADD r0, sp, #3*4 [ debugheap DLINE "AccessEntry:",cc ] BL SGetLinkedArea ADDVS sp, sp, #3*4 + 4 BVS %FT65 Swap r1, r2 [ debugcontrol DSTRING r2, "tail for strcpy is " ] ; If in root dir of partition then tail will be nul LDRB r14, [r2] TEQ r14, #0 BLNE strcpy_advance ; <Tail> MOVNE r2, #"." STRNEB r2, [r1], #1 ; . LDR r2, [sp, #0*4] [ debugcontrol DSTRING r2, "leaf for strcpy is " ] BL strcpy ; <Leaf> Pull "r1,r2,r3" ; Having constructed <Tail>.<Leaf> change its access. Push "r1" LDR r1, [sp, #1*4] ; <Tail>.<Leaf> LDR lr, [fscb, #fscb_info] TST lr, #fsinfo_giveaccessstring BNE %FT56 MOV r0, #fsfile_WriteInfo [ debugcontrol DSTRING r1, "Path for WriteInfo is " ] MOV r5, r8 BL CallFSFile_Given B %FT58 56 MOV r0, #fsfunc_Access MOV r2, r8 BL CallFSFunc_Given 58 Pull "r1" MOV r0, sp BL SFreeLinkedArea ADD sp, sp, #4 BVS %FT65 60 ; Advance to the next item (skip over the name and round up to a word) ADD r3, r1, #1 + 3 ; 1 for the nul terminator, 3 for the rounding BL strlen_accumulate BIC r1, r3, #3 ; Any more items in this batch? LDR r3, [sp, #1*4] SUBS r3, r3, #1 STR r3, [sp, #1*4] BNE %BT55 65 ; General end of Push - BVS for those error branches Pull "r1,r3,r4,r5" BVS %FT85 CMP r4, #-1 BNE %BT50 70 ; Drop the stack chunk used for reading the entries ADD sp, sp, r5 72 ; No more items to read BL JunkFileStrings SwiExit 75 ; No items read ; Was it the end? CMP r4, #-1 BEQ %BT70 ; Wasn't end, so must be buffer overflow addr r0, ErrorBlock_BuffOverflow 80 BL CopyError 85 B %BT70 90 ; Not enough stack for *Access addr r0, ErrorBlock_NotEnoughStackForFSEntry BL CopyError B %BT72 95 ; Bad access attributes addr r0, MagicErrorBlock_BadAccessAttributes LDR r1, [fp, #2*4] ; r2 in BL MagicCopyError SwiExit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; DirEntry. Top level FSControl entry ; ======== ; In r1 -> command tail PSDPath DCB "\\", 0 ALIGN BackEntry ADR r1, PSDPath DirEntry NewSwiEntry "r0,r2,r7,fscb" [ debugcontrol DSTRING r1, "Setting CSD to " ] MOV r2, #Dir_Current BL ChangeDirectory SwiExit VS TEQ r7, #0 SwiExit EQ MOV r2, fscb BL SetCurrentFS BL SetTempFS SwiExit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; CanonicalisePathEntry. Top level FSControl entry ; ===================== ; ; In r1 -> filename to be canonicalised ; r2 = pointer to buffer to be filled in ; r3 = Pointer to system variable name of path to use, or 0 if none ; r4 = Pointer to default path to use if no system variable is specified ; or if that variable doesn't exist, or 0 if no path is the default ; r5 = buffer length ; ; Out r5 = space left in buffer including the ; terminator. ; CanonicalisePathEntry NewSwiEntry "r0-r6,fscb" [ debugcontrolentry DSTRING r1, "CanonicalisePath(",cc DREG r2, ",",cc DSTRING r3, ",",cc DSTRING r4, ",",cc DREG r5, ",",cc DLINE "" ] ADR r0, PassedFilename MOV r2, r3 MOVS r3, r4 addr r3, anull, EQ ADR r4, FullFilename MOV r5, #TopPath_Canonicalise ADR r6, SpecialField BL TopPath_DoBusinessToPath SwiExit VS LDR r2, [fp, #2*4] LDR r3, [fp, #5*4] BL int_ConstructFullPath STR r3, [fp, #5*4] BL JunkFileStrings SwiExit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; InfoToFileTypeEntry. Top level FSControl entry ; =================== ; ; In r1 -> filename ; r2 = load address ; r3 = execute address ; r4 = length ; r5 = attributes ; r6 = objecttype ; ; Out r2 = filetype ; Special file types: ; -1 untyped ; &1000 directory ; &2000 application ; InfoToFileTypeEntry NewSwiEntry BL InfoToFileType SwiExit ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; InfoToFileType ; ; In r1 -> filename ; r2 = load address ; r3 = execute address ; r4 = length ; r5 = attributes ; r6 = objecttype ; ; Out r2 = filetype ; Special file types: ; -1 untyped ; &1000 directory ; &2000 application ; InfoToFileType Entry "r3" TEQ r6, #object_file BNE %FT10 ; It's a file BL IsFileTyped BLEQ ExtractFileType MOVNE r2, #-1 EXIT 10 ; It's not a file TST r6, #object_directory MOVEQ r2, #-1 ; Not a directory BEQ %FT20 ; It's a directory, check leaf for starting with a ! BL strlen 12 LDRB r14, [r1, r3] TEQ r14, #"." BEQ %FT15 SUBS r3, r3, #1 BPL %BT12 15 ADD r3, r3, #1 LDRB r14, [r1, r3] TEQ r14, #"!" MOVEQ r2, #&2000 MOVNE r2, #&1000 20 EXIT ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; URDEntry. Top level FSControl entry ; ======== ; In r1 -> command tail URDEntry NewSwiEntry "r2,r7,fscb" MOV r2, #Dir_UserRoot BL ChangeDirectory SwiExit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; NoURDEntry. Top level FSControl entry ; ========== ; NoLibEntry. Top level FSControl entry ; ========== ; NoDirEntry. Top level FSControl entry ; ========== ; In r1 -> command tail NoURDEntry NoLibEntry NoDirEntry NewSwiEntry "r0,r2,fscb" TEQ r0, #FSControl_NoDir MOVEQ r2, #Dir_Current TEQ r0, #FSControl_NoURD MOVEQ r2, #Dir_UserRoot TEQ r0, #FSControl_NoLib MOVEQ r2, #Dir_Library BL ReadTempFS TEQVS r0, r0 ; set EQ if VS TEQVC r0, #Nowt MOVNE fscb, r0 BLNE UnsetDir ; If VC and NE SwiExit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Ones that can't really be commoned up ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; OptEntry. Top level FSControl entry ; ======== ; ; Filing System action control ; In r1 = first parm, r2 = second parm OptEntry NewSwiEntry "r0-r5, r6, fscb" ; FSFunc only preserves r6 up BL ReadTempFS BVS %FA90 MOV fscb, r0 TEQ fscb, #Nowt ; Give 'No sel FS' error lower down BEQ %FT10 CMP r1, #1 ; Keep a note of OPT 1 setting ? MOVLO r2, #0 ; Default setting is 0 / CMOS ? STRLSB r2, [fscb, #fscb_opt1] ; Keep a note of/Reset OPT 1 setting ? BEQ %FA90 ; SwiExit ; Don't tell Filing System EVER 10 MOV r0, #fsfunc_Opt ; Numeric arguments MOV r6, #0 ; Use current context BL CallFSFunc_Given ; Use fscb^ 90 SwiExit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; RenameEntry. Top level FSControl entry ; =========== ; In r1 -> path to rename ; r2 -> new name for file(s) RenameEntry NewSwiEntry "r0-r8,scb,fscb" [ debugcontrol DSTRING r1, "source pathname: " DSTRING r2, "new pathname: " ] ; Do business to source and check it exists ADR r0, PassedFilename MOV r2, #NULL addr r3, anull ADR r4, FullFilename MOV r5, #TopPath_NoMultiParts ADR r6, SpecialField BL TopPath_DoBusinessToPath SwiExit VS TEQ r0, #object_nothing BEQ %FT90 ; Hold source fscb, special and path tail for a while MOV r7, r6 MOV r8, fscb MOV r9, r1 ; r9 is also scb which isn't needed yet ; Do business to destination and check it doesn't exist LDR r1, [fp, #2*4] ; r2 in ADR r0, PassedFilename2 MOV r2, #NULL addr r3, anull ADR r4, FullFilename2 MOV r5, #TopPath_NoMultiParts ADR r6, SpecialField2 BL TopPath_DoBusinessToPath BVS %FT95 ; Check the fscbs match TEQ r8, fscb BNE %FT75 ; r8 now freed as its the same as fscb ; Hold destination path tail in r8 MOV r8, r1 ; Check the special fields match LDRB r14, [fscb, #fscb_info] TEQ r14, #0 BEQ %FT10 ; Check special fields on ordinary filing systems MOV r1, r6 MOV r2, r7 BL strcmp B %FT20 10 ; Check special fields on MultiFS filing systems TEQ r6, r7 20 BNE %FT75 ; Branch on special field mismatch ; As the special fields match there is no need to worry about their order ; In fact, at the moment the special fields are the wrong way round! ; Now we know the fscb and special fields match, check for rename to existing, different ; object MOV r1, r9 ; source path tail MOV r2, r8 ; Destination path tail TEQ r0, #object_nothing BLNE strcmp BNE %FT85 ; Branch if destination exists and it isn't the source BL TryGetFileClosed BVS %FT94 ; Filing systems and special fields match - do the rename MOV r0, #fsfunc_Rename Push "r2-r5" BL CallFSFunc_Given Pull "r2-r5" BVS %FT94 ; Check if FS managed it TEQ r1, #0 BNE %FT75 ; The rename has worked - sort out the carnage to the internals of FileSwitch! ; Move source and destination tail down to r1 and r2 MOV r1, r9 ; source path tail MOV r2, r8 ; Destination path tail BL SortOutRenameCarnage B %FT94 75 ; Special fields don't match ; Filing systems don't match addr r0, ErrorBlock_BadRename BL CopyError B %FT94 85 ; Destination is found addr r0, MagicErrorBlock_RenameDestinationFound LDR r1, PassedFilename2 BL MagicCopyError 94 ; Exit if both sets of path strings are still allocated ADR r0, SpecialField2 BL SFreeLinkedString ADR r0, FullFilename2 BL SFreeLinkedString ADR r0, PassedFilename2 BL SFreeLinkedString B %FT95 90 ; Source not found LDR r1, PassedFilename BL SetMagicPlainNotFound 95 BL JunkFileStrings SwiExit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; SortOutRenameCarnage ; ==================== ; ; Sorts out the carnage to FileSwitch's internals after a rename has happened. ; Used by Rename and NameDisc. ; In ; r1 = source path tail ; r2 = destination path tail ; r6 = special of renamed ; fscb = fscb of renamed ; ; Out ; FileSwitch's internals updated to keep up-to-date with the change SortOutRenameCarnage Entry "r0,r3,r4,scb" ; For each open file check whether it's one that's been renamed, and change its name if it is MOV r0, #MaxHandle ; Allocate handles from MaxHandle..1 ADRL r3, UnallocatedStream ; Indicator of unused stream ADR r4, streamtable 10 LDR scb, [r4, r0, LSL #2] ; Empty slot found ? TEQ scb, r3 BLNE SortOutRenameCarnage_OneFile ; BVS %FT30 IGNORE ERRORS WE WANT TO PROCESS ALL FILES SUBS r0, r0, #1 BNE %BT10 ; If reached handle 0 that's all ; For each of the relevant directory system variables check whether it needs changing BL SortOutRenameCarnage_TheDirs EXIT ; SortOutRenameCarnage_OneFile ; ============================ ; ; Subroutine of SortOutRenameCarnage which deals with a single file ; ; In r1 = source tail of renamed ; r2 = destination tail of renamed ; r6 = special of renamed ; scb -> candidate renamee ; fscb = fscb of renamed ; ; Out If has been renamed, then contents of scb have been updated ; SortOutRenameCarnage_OneFile Entry "r0-r3" ; Check fscb LDR r14, scb_fscb TEQ r14, fscb EXIT NE ; Exit if fscb mismatches [ debugcontrol DREG scb, "scb ",cc DLINE " matched fscb" ] ; Check special field LDR r2, scb_special ; Don't care if we trample r1 & r2 - they're on the stack LDRB r14, [fscb, #fscb_info] TEQ r14, #0 BEQ %FT10 ; Special field check for non-MultiFS MOV r1, r6 [ debugcontrol DSTRING r1, "Comparing special ",cc DSTRING r2, " against " ] BL strcmp B %FT50 10 ; Special field check for a MultiFS [ debugcontrol DREG r1, "Comparing special ",cc DREG r2, " against " ] TEQ r2, r6 50 EXIT NE ; Exit if special mismatches ; It's an fscb and special field match - now check the names LDR r1, [sp, #1*4] ; Source path tail LDR r2, scb_path [ debugcontrol DSTRING r1, "Comparing path ",cc DSTRING r2, " against " ] BL IsAChild_advance EXIT NE ; Exit if rename source path mismatches file's name ; It's been renamed - change the path MOV r1, r2 [ debugcontrol DSTRING r1, "Accumulating path tail " ] BL strlen ; Length of scb's name's tail LDR r1, [sp, #2*4] ; Destination path tail [ debugcontrol DSTRING r1, "Accumulating rename destination " ] BL strlen_accumulate ; + length of destination ADD r3, r3, #1 ; + 1 for the terminator MOV r0, r2 ; preserve path tail BL SMustGetArea EXIT VS ; failed to get new area [ debugcontrol DREG r2, "Got area " ] MOV r1, r2 ; Start of new area for copying into MOV r3, r2 ; for storing as a replacement LDR r2, [sp, #2*4] ; destination path tail [ debugcontrol DSTRING r2, "Appending " ] BL strcpy_advance ; Copy destination name MOV r2, r0 [ debugcontrol DSTRING r2, "Appending " ] BL strcpy_advance ; Copy path tail LDR r2, scb_path [ debugcontrol DREG r2, "Freeing old path " ] BL SFreeArea ; free the old tail MOVVS r2, r3 BLVS SFreeArea ; if error free the new tail [ debugcontrol BVS %FT01 DREG r3, "Storing new path " 01 ] STRVC r3, scb_path ; if no error store the new tail EXIT ; return ; SortOutRenameCarnage_TheDirs ; ============================ ; ; Subroutine of SortOutRenameCarnage which deals with the dirs ; ; In r1 = source tail of renamed ; r2 = destination tail of renamed ; r6 = special of renamed ; fscb = fscb of renamed ; ; Out If has been renamed, then dirs updated ; SortOutRenameCarnage_TheDirs Entry "r0-r4,r8" MOV r8, sp ; Construct on the stack a suitable prefix MOV r2, #Nowt MOV r3, #0 BL int_ConstructPathWithoutFS RSB r3, r3, #3 + 1 BIC r3, r3, #3 SUB sp, sp, r3 MOV r2, sp BL int_ConstructPathWithoutFS MOV r0, sp ; Construct on the stack a new prefix LDR r1, [r8, #2*4] MOV r2, #Nowt MOV r3, #0 BL int_ConstructPathWithoutFS RSB r3, r3, #3 + 1 BIC r3, r3, #3 SUB sp, sp, r3 MOV r2, sp BL int_ConstructPathWithoutFS MOV r1, r0 MOV r2, sp ADD r3, fscb, #fscb_name BL AlterMatchingDirs MOV sp, r8 EXIT ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ LTORG ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; DefectListEntry. Top level FSControl entry ; =============== ; In r1 -> path for defect list to assessed ; r2 -> buffer to fill ; r5 = buffer length ; Out regs preserved ; AddDefectEntry. Top level FSControl entry ; ============== ; In r1 = path for defect ; r2 = defect address ; Out regs preserved ; ReadFreeSpaceEntry. Top level FSControl entry ; ================== ; In r0 = 49 ; r1 = pointer to nul-terminated name of object on thing whose free space is to be read ; Out r0 = free space ; r1 = biggest creatable object ; r2 = disc size ; ReadFreeSpace64Entry. Top level FSControl entry ; ==================== ; In r0 = 55 ; r1 = pointer to nul-terminated name of object on thing whose free space is to be read ; Out r0 = free space (low) ; r1 = free space (high) ; r2 = largest creatable object ; r3 = disc size (low) ; r4 = disc size (high) ; DefectList64Entry. Top level FSControl entry ; ================== ; In r0 = 56 ; r1 -> path for defect list ; r2 -> buffer to fill ; r5 = buffer length ; Out r1 = number of defects returned ; AddDefect64Entry. Top level FSControl entry ; ================= ; In r0 = 57 ; r1 -> path for defect ; r2 = ls word of byte offset to defect ; r3 = ms word of byte offset to defect ; Out all preserved ; UsedSpaceMapEntry. Top level FSControl entry ; ================= ; In r0 = 46 ; r1 = pointer to nul-terminated name of image ; r2 = start of buffer in memory ; r5 = buffer length ; Out regs preserved ; StampImageEntry. Top level FSControl entry ; =============== ; In r1 = path of file on disc to be image-stamped ; r2 = sub-reason: ; 0 Stamp on next update ; 1 Stamp now ; Out regs preserved ; ObjectAtOffsetEntry. Top level FSControl entry ; =================== ; In r1 = path of file on disc to be searched ; r2 = offset into image ; r3 = pointer to buffer for name ; r4 = buffer length ; Out r2 = kind of thing found: ; 0 free/defect/off end of image ; 1 allocated, not a file or directory ; 2 found, unique owner ; 3 found, shared ; buffer filled with found file/directory name DefectListEntry AddDefectEntry ReadFreeSpaceEntry UsedSpaceMapEntry StampImageEntry ObjectAtOffsetEntry ReadFreeSpace64Entry DefectList64Entry AddDefect64Entry NewSwiEntry "r0-r6,fscb" MOV r2, #0 addr r3, anull MOV r5, #TopPath_WantPartition BL TopPath_DoBusinessForDirectoryRead SwiExit VS LDR r0, [fscb, #fscb_info] TST r0, #&ff BEQ %FT10 TST r0, #fsinfo_multifsextensions BNE %FT10 addr r0, ErrorBlock_UnsupportedFSEntry BL CopyError B %FT90 10 LDR r2, [fp, #2*4] ; buffer/defect address LDR r3, [fp, #3*4] ; top32 of defect addr for AddDefect64 LDR r5, [fp, #5*4] ; buffer size LDR lr, [fp, #0*4] ; Op TEQ lr, #FSControl_DefectList MOVEQ r0, #fsfunc_DefectList TEQ lr, #FSControl_AddDefect MOVEQ r0, #fsfunc_AddDefect TEQ lr, #FSControl_ReadFreeSpace MOVEQ r0, #fsfunc_ReadFreeSpace TEQ lr, #FSControl_ReadFreeSpace64 MOVEQ r0, #fsfunc_ReadFreeSpace64 TEQ lr, #FSControl_StampImage MOVEQ r0, #fsfunc_StampImage TEQ lr, #FSControl_UsedSpaceMap MOVEQ r0, #fsfunc_UsedSpaceMap TEQ lr, #FSControl_ObjectAtOffset MOVEQ r0, #fsfunc_ObjectAtOffset TEQ lr, #FSControl_DefectList64 MOVEQ r0, #fsfunc_DefectList64 TEQ lr, #FSControl_AddDefect64 MOVEQ r0, #fsfunc_AddDefect64 TEQ r0, #fsfunc_UsedSpaceMap BNE %FT20 ; Zero out the buffer for UsedSpaceMap MOV lr, #0 MOV r4, #0 15 STRB r4, [r2, lr] ADD lr, lr, #1 CMP lr, r5 BLO %BT15 20 TEQ r0, #fsfunc_ObjectAtOffset BNE %FT60 LDR r3, [fp, #3*4] ; buffer LDR r4, [fp, #4*4] ; length ; Push into the buffer the path prefix Push "r2" BL fscbscbTofscb ADD r2, r2, #fscb_name 25 SUBS r4, r4, #1 ADDLS sp, sp, #1*4 BLS %FT55 LDRB lr, [r2], #1 STRB lr, [r3], #1 TEQ lr, #0 BNE %BT25 Pull "r2" SUBS r4, r4, #1 BLS %FT55 MOV lr, #":" STRB lr, [r3, #-1] LDRB lr, [fscb, #fscb_info] TEQ lr, #0 BEQ %FT45 [ debugcontrol DLINE "Prefix for non-MultiFS" ] ; Ordinary filing system Push "r0,r1" ; Copy prefix up to absolute 40 SUBS r4, r4, #1 ADDLS sp, sp, #2*4 BLS %FT55 LDRB r0, [r1], #1 STRB r0, [r3], #1 TEQ r0, #0 BLNE IsAbsolute BNE %BT40 Pull "r0,r1" [ debugcontrol MOV lr, #0 STRB lr, [r3] Push "r3" LDR r3, [fp, #3*4] DSTRING r3, "String prefix is " Pull "r3" ] B %FT60 45 [ debugcontrol DLINE "Prefix for MultiFS" ] ; Processing for a MultiFS Push "r1,r2,r3" MOV r2, r3 LDR lr, FullFilename SUB r3, r1, lr LDRB r1, [r1] TEQ r1, #0 SUBNE r3, r3, #1 MOV r1, lr SUBS r4, r4, r3 ADDLS sp, sp, #3*4 BLS %FT55 LDR lr, [sp, #2*4] ADD lr, lr, r3 STR lr, [sp, #2*4] BL MoveBytes MOV r0, #fsfunc_ObjectAtOffset 50 Pull "r1,r2,r3" [ debugcontrol MOV lr, #0 STRB lr, [r3] Push "r3" LDR r3, [sp, #3*4 + 1*4] DSTRING r3, "String prefix is " Pull "r3" ] B %FT60 55 addr r0, ErrorBlock_BuffOverflow BL CopyError B %FT90 60 BL CallFSFunc_Given BVS %FT90 ; Return parameters in ReadFreeSpace LDR lr, [fp, #0*4] ; Op TEQ lr, #FSControl_ReadFreeSpace STMEQIA fp, {r0,r1,r2} TEQ lr, #FSControl_ReadFreeSpace64 STMEQIA fp, {r0-r4} TEQ lr, #FSControl_ObjectAtOffset STREQ r2, [fp, #2*4] TEQ lr, #FSControl_DefectList64 STREQ r1, [fp, #1*4] 90 BL JunkFileStrings SwiExit ; EnumerateHandlesEntry. Top level FSControl entry ; ===================== ; In r0 = 58 ; r1 = last handle enumerated, or -1 to start ; Out r0 = stream status word ; r1 = handle number, or -1 for no more ; r2 = filing system info word EnumerateHandlesEntry NewSwiEntry "scb" 10 ADD r1, r1, #1 CMP r1, #MaxHandle MOVHI r1, #-1 BHI %FT90 ADR r14, streamtable LDR scb, [r14, r1, LSL #2] ADRL r14, UnallocatedStream CMP scb, r14 BEQ %BT10 LDR r0, scb_status LDR r14, scb_fscb LDR r2, [r14, #fscb_info] 90 SwiExit ; NameDiscEntry. Top level FSControl entry ; ============= ; In r1 = path of file on disc to be renamed ; r2 = new name for disc ; Out regs preserved NameDiscEntry NewSwiEntry "r0-r6,fscb" ; Check new disc name is OK MOV r3, r2 B %FT07 05 BL IsBad BEQ %FT95 07 LDRB r0, [r3], #1 TEQ r0, #0 BNE %BT05 ; Check name isn't too short or long ; Length allowed: 2 to 10 SUB r14, r3, r2 CMP r14, #10+1 RSBLSS r14, r14, #2+1 BHI %FT95 ; Find the destination MOV r2, #0 addr r3, anull MOV r5, #TopPath_WantPartition BL TopPath_DoBusinessForDirectoryRead SwiExit VS LDR r0, [fscb, #fscb_info] TST r0, #&ff BEQ %FT10 TST r0, #fsinfo_multifsextensions BNE %FT10 addr r0, ErrorBlock_UnsupportedFSEntry BL CopyError B %FT90 10 LDR r2, [fp, #2*4] ; new disc name MOV r0, #fsfunc_NameDisc [ debugmultifs DSTRING r1, "Calling namedisc from ",cc DSTRING r2, " to ",cc DREG r1, " r1=",cc DREG r2, " r2=",cc ] ; Save regs as some filing systems (DOSFS) trash them!! Push "r1,r2,r6,fscb" BL CallFSFunc_Given Pull "r1,r2,r6,fscb" [ debugmultifs DLINE "return from namedisc ",cc DREG r1, " r1=",cc DREG r2, " r2=",cc ] BVS %FT90 20 ; Now check if we've just renamed the root object MultiFS-style in which ; case we want to inform the 'parent' filing system too. ; Whilst we doing these sort of checks sort out FileSwitch's internals too. LDRB lr, [fscb, #fscb_info] TEQ lr, #0 BLNE NameDiscSortOutCarnage BNE %FT90 ; Reject if path tail is non-nul LDRB lr, [r1] TEQ lr, #0 BNE %FT90 Push "r1,r6,fscb" [ debugmultifs DLINE "Considering informing parent" ] ; ToParent LDR r1, [r6, #:INDEX:scb_path] LDR fscb, [r6, #:INDEX:scb_fscb] LDR r6, [r6, #:INDEX:scb_special] ; reject if parent is a MultiFS or an ordinary FS which can't handle MultiFS stuff LDR lr, [fscb, #fscb_info] TST lr, #&ff TSTNE lr, #fsinfo_multifsextensions BEQ %FT80 ; reject if parent path doesn't end in "$" BL strlen SUB r3, r3, #1 LDRB lr, [r1, r3] TEQ lr, #"$" BNE %FT80 ; OK, parent is a MultiFS-handling ordinary filing system and the ; path ended in $, so lets tell the parent about the rename. ; Make a copy of the path which will get freed in NameDiscSortOutCarnage ADD r3, r3, #1 + 1 + 3 ; 1 for the SUB above, 1 for \0 and 3 for round-up BIC r3, r3, #3 SUB sp, sp, r3 MOV r0, r2 MOV r2, r1 MOV r1, sp BL strcpy MOV r2, r0 BL NameDiscSortOutCarnage [ debugmultifs DSTRING r1, "Informing parent of namedisc from ",cc DSTRING r2, " to " ] MOV r0, #fsfunc_NameDisc Push "r3" BL CallFSFunc_Given Pull "r3" ADD sp, sp, r3 80 Pull "r1,r6,fscb" 90 BL JunkFileStrings SwiExit 95 MOV r1, r2 addr r0, MagicErrorBlock_BadDiscName BL MagicCopyError SwiExit ; NameDiscSortOutCarnage ; ====================== ; ; In ; r1 = path tail on non-MultiFS where namedisc worked ; r2 = new disc name ; r6 = special ; fscb set ; ; Out ; NameDiscSortOutCarnage Entry "r1,r2,r3,r4,r5" [ debugmultifs DSTRING r1, "NameDiscSortOutCarnage from ",cc DSTRING r2, " to " ] ; Construct new name on stack MOV r1, r2 BL strlen ADD r3, r3, #4+3 ; 4 for : prefix and .$\0 postfile BIC r3, r3, #3 SUB sp, sp, r3 MOV r1, sp MOV lr, #":" STRB lr, [r1], #1 BL strcpy_advance MOV lr, #"." STRB lr, [r1], #1 MOV lr, #"$" STRB lr, [r1], #1 MOV lr, #0 STRB lr, [r1], #1 ; Terminate the source after the .$ LDR r1, [sp, r3] MOV r4, r1 10 LDRB lr, [r4], #1 TEQ lr, #0 MOVEQ r4, #0 BEQ %FT20 TEQ lr, #"$" BNE %BT10 LDRB r5, [r4] MOV lr, #0 STRB lr, [r4] 20 MOV r2, sp [ debugmultifs DSTRING r1, "SortOutRenameCarnage on ",cc DSTRING r2, " to ",cc DREG r1, " r1=",cc DREG r2, " r2=" DREG r4, " r4=",cc DREG r5, " r5=" ] BL SortOutRenameCarnage [ debugmultifs DSTRING r1, "return from SortOutRenameCarnage on ",cc DSTRING r2, " to ",cc DREG r1, " r1=",cc DREG r2, " r2=" DREG r4, " r4=",cc DREG r5, " r5=" ] ; Restore the rest of the path tail to the source TEQ r4, #0 STRNEB r5, [r4] ADD sp, sp, r3 EXIT ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; ReadBootOptionEntry. Top level FSControl entry ; =================== ; In r1 = path for boot option ; Out regs preserved, except ; r2 = boot option ReadBootOptionEntry NewSwiEntry "r0,r1,r3-r6,fscb" BL faff_boot_option_startup BVS %FT95 BL int_ReadBootOptionGiven BL JunkFileStrings 95 SwiExit ; ======================= ; int_ReadBootOptionGiven ; ======================= ; In r0 <> 0 means FS which understands fsfunc_ReadBootOption ; r1 = path tail ; r6 = special ; fscb ; Out regs preserved, except ; r2 = boot option int_ReadBootOptionGiven Entry "r0,r1,r3-r5" ; Don't trust the lower layers AT ALL TEQ r0, #0 BEQ %FT50 [ debugcontrol DSTRING r1, "Read boot option new style using tail " ] ; Fs understands sensible FSControls MOV r0, #fsfunc_ReadBootOption BL CallFSFunc_Given B %FT90 50 [ debugcontrol DLINE "Reading boot option old style" ] ; Fs old style brain damaged ; Carve stack chunk for name and boot option of disc SUB sp, sp, #64 ; should be enough MOV r0, #fsfunc_ReadDiscName MOV r2, sp BL CallFSFunc_Given LDRVCB r2, [sp, #0] ADDVC r2, r2, #1 LDRVCB r2, [sp, r2] MOVVS r2, #0 ; Discard any error MOV lr, #0 STR lr, globalerror CLRV ADD sp, sp, #64 90 [ debugcontrol DREG r2, "Boot option is " ] STRVS r0, [sp] ; SBP: 02-Mar-95 pass back error ptr to avoid mess EXIT ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; WriteBootOptionEntry. Top level FSControl entry ; ==================== ; In r1 = path for boot option ; r2 = boot option ; Out regs preserved WriteBootOptionEntry NewSwiEntry "r0-r6,fscb" BL faff_boot_option_startup BVS %FT95 LDR r2, [fp, #2*4] TEQ r0, #0 BEQ %FT50 ; Fs understands sensible FSControls MOV r0, #fsfunc_WriteBootOption B %FT90 50 ; Fs old style brain damaged ; Use *OPT 4,n to set boot option MOV r0, #fsfunc_Opt MOV r1, #4 90 BL CallFSFunc_Given BL JunkFileStrings 95 SwiExit ; ======================== ; faff_boot_option_startup ; ======================== ; In r1 = path for boot option ; Out r0 <> 0 for good FSs and =0 for bad FSs ; r1 = path to send to FS ; r6 = special ; fscb faff_boot_option_startup Entry "r2-r5" ; Standard PathMunge sequence MOV r2, #0 addr r3, anull MOV r5, #TopPath_WantPartition BL TopPath_DoBusinessForDirectoryRead EXIT VS BL faff_boot_option_startup_given BLVS JunkFileStrings EXIT ; ============================== ; faff_boot_option_startup_given ; ============================== ; In r1 = path tail for directory ; r6 = special ; fscb ; Out r0 <> 0 for good FSs and =0 for bad FSs faff_boot_option_startup_given Entry "r2,r3" ; Check if FS supports the entry LDR r0, [fscb, #fscb_info] TST r0, #&ff MOVEQ r0, #1 ; not bad old FS BEQ %FT90 TST r0, #fsinfo_multifsextensions BNE %FT90 ; Duff old FS [ debugcontrol DLINE "Duff old FS" ] ; Truncate after the absolute ; The path *will* contain an absolute MOV r2, r1 10 LDRB r0, [r2], #1 BL IsAbsolute BNE %BT10 MOV r0, #0 LDRB r3, [r2] STRB r0, [r2] [ debugcontrol DSTRING r1, "Setting dir to " ] ; Now set the directory to that MOV r0, #fsfunc_Dir Push "r0-r5" BL CallFSFunc_Given Pull "r0-r5" STRB r3, [r2] ; Ignore any error - it probably doesn't matter MOV r3, #0 STR r3, globalerror CLRV ; Duff FS indicator, and the opt interfaces allow no context MOV r0, #0 90 [ debugcontrol DLINE "Finished initial faff" ] EXIT ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; SetDirEntry Top level FSControl entry ; =========== ; On entry ; r0 = 53 ; r1 = pointer to rest of path ; r2 = which directory to set ; r3 = filing system ; r6 = pointer to special field ; On exit ; registers preserved SetDirEntry NewSwiEntry "r0-r6,fscb" ; Sanity check the directory specified TEQ r2, #Dir_Current TEQNE r2, #Dir_Previous TEQNE r2, #Dir_UserRoot TEQNE r2, #Dir_Library addr r0, ErrorBlock_BadSetDirDir, NE BLNE CopyError BVS %FT95 ; Check the filing system name MOV r0, #1 MOV r1, r3 BL LookupFSName BVS %FT95 TEQ fscb, #Nowt LDREQ r1, [fp, #3*4] BLEQ SetMagicFSDoesntExist BVS %FT95 LDR r1, [fp, #1*4] TEQ r1, #0 BEQ %FT80 BL SetDirFromObject B %FT95 80 BL int_UnsetDir 95 SwiExit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; ReadDirEntry Top level FSControl entry ; ============ ; On entry ; r0 = 54 ; r1 = pointer to buffer ; r2 = which directory to read ; r3 = filing system ; r5 = size of buffer ; ;On exit ; r1 = 0 if directory unset, else points to start of rest of path if managed ; to be placed into buffer. ; r5 reduced by length total size of directory string including terminator ; r6 = pointer to special field or 0 if not present ReadDirEntry NewSwiEntry "r0-r6,fscb" ; Sanity check the directory specified TEQ r2, #Dir_Current TEQNE r2, #Dir_Previous TEQNE r2, #Dir_UserRoot TEQNE r2, #Dir_Library addr r0, ErrorBlock_BadSetDirDir, NE BLNE CopyError BVS %FT95 ; Check the filing system name MOV r0, #1 MOV r1, r3 BL LookupFSName BVS %FT95 TEQ fscb, #Nowt LDREQ r1, [fp, #3*4] BLEQ SetMagicFSDoesntExist BVS %FT95 LDR r1, [fp, #1*4] BL SimpleReadDir BVS %FT95 STR r5, [fp, #5*4] CMP r5, #0 BLT %FT95 TEQ r1, #0 BEQ %FT80 LDRB lr, [r1] TEQ lr, #"#" MOVNE r6, #0 BNE %FT70 ADD r6, r1, #1 20 LDRB lr, [r1, #1]! TEQ lr, #":" TEQNE lr, #0 BNE %BT20 TEQ lr, #0 MOVNE lr, #0 STRNEB lr, [r1], #1 70 STR r6, [fp, #6*4] 80 STR r1, [fp, #1*4] 95 SwiExit END