; 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.Canonical ; This file contains the routines to canonicalise a path: ; CanonicalisePath ; ObtainAbsoluteParts ; GetDiscFromPath ; GetAbsolute ; StitchAbsolutePartsTogether ; CanonicaliseSpecialAndDisc ; ReduceParents ; UnWildcardPath ; SkipToLeafEnd ; ResolveWildcard ; ResolveWildcardBySteam ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; ReduceParents ; ============= ; ; Given a complete file path from .$, .& or .%, reduce any ^s in it ; to their true value. ; ; In r2 = pointer to filepath to reduce, nul terminated ; The path is assumed kosha - this routine ; will break if it isn't. ; fscb ; ; Out filepath reduced. ReduceParents Entry "r0-r3" [ chopoffdollarfrompaths MOV r1, r2 ; Start of $ or .$ sequence LDRB r0, [r2], #1 TEQ r0, #0 EXIT EQ ; Check for .$ and chop it TEQ r0, #"." LDREQB r0, [r2], #1 LDRB lr, [r2], #1 TEQ lr, #0 BNE %FT05 ; Goes $ or .$ TEQ r0, #"$" LDREQ lr, [fscb, #fscb_info] TSTEQ lr, #fsinfo_handlesurdetc MOVEQ r0, #0 STREQB r0, [r1] EXIT 05 ; Reduce the $ if present and not on a handlesurdetc FS ; During the main loop: ; r2 points to the start of the path - no reduction ; to before this! ; r1 points to the destination position ; r3 points to the source position MOV r3, r2 TEQ r0, #"$" LDREQ lr, [fscb, #fscb_info] TSTEQ lr, #fsinfo_handlesurdetc SUBEQ r2, r2, #2 ; 1 for $ and 1 for . MOV r1, r2 | ; Skip over the .<absolute>., or <absolute>., or <absolute> ; and exit if reached end of string LDRB r0, [r2], #1 TEQ r0, #0 EXIT EQ TEQ r0, #"." LDREQB r0, [r2], #1 TEQ r0, #0 LDRNEB r0, [r2], #1 TEQNE r0, #0 EXIT EQ MOV r1, r2 MOV r3, r2 ] ; At this point: ; r3 points at source position ; r1 points at destination position ; r2 points at 'do not reduce parents to before here' position 10 ; At start of a path element - check it for being a ^ LDRB r0, [r3], #1 TEQ r0, #"^" BNE %FT40 ; Identified a ^ - skip back one element and skip forward over the ^. ; Don't go backwards to before the start position CMP r1, r2 BLS %FT30 ; Skip to the . before the start of this element SUB r1, r1, #1 ; Go back until we hit a . 20 LDRB r0, [r1, #-1]! TEQ r0, #"." BNE %BT20 ; Move forwards to start of element ADD r1, r1, #1 30 ; Now skip the . after the ^ LDRB r0, [r3], #1 TEQ r0, #0 BNE %BT10 ; Not end of path - go for another element STRB r0, [r1, #-1] ; End of path - terminate new path back one character to ; obliterate the . which is there EXIT 40 ; Path element which isn't a ^ - copy it down STRB r0, [r1], #1 ; Store next byte regardless TEQ r0, #0 EXIT EQ ; End of path - stop TEQ r0, #"." BEQ %BT10 ; End of path element - check next element LDRB r0, [r3], #1 B %BT40 ; Next byte of element - loop ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; CanonicaliseSpecialAndDisc ; ; In R1 = special field^ to be canonicalised ; R2 = disc name^ to be canonicalised ; fscb ; ; Out R1 = unchanged, RMAlloced special field^ or NULL ; R2 = unchanged, RMAlloced disc^ or NULL ; CanonicaliseSpecialAndDisc EntryS "r0,r3,r4,r5,r6,r7,r8", 4 [ debugcanonical DSTRING r1, "Canonicalise #",cc DSTRING r2, "::" ] ; Check whether this call is supported LDR r0, [fscb, #fscb_info] TST r0, #fsinfo_multifsextensions [ debugdontworryresourcefs EXIT EQ | BEQ %FT50 ] ; Preserve the source values MOV r7, r1 MOV r8, r2 ; Get the string lengths MOV r0, #fsfunc_CanonicaliseSpecialAndDisc MOV r3, #NULL MOV r4, #NULL [ debugcanonical DSTRING r1, "CallCanonical(",cc DSTRING r2, ",",cc DREG r3, ",",cc DREG r4, ",",cc DREG r5, ",",cc DREG r6, ",",cc DLINE ")->",cc ] BL CallFSFunc_Given [ debugcanonical DSTRING r1, "(",cc DSTRING r2, ",",cc DREG r3, ",",cc DREG r4, ",",cc DREG r5, ",",cc DREG r6, ",",cc DLINE ")" ] EXIT VS ; Get some memory for this ADD r3, r3, #1 BL SMustGetArea EXIT VS MOV r5, r3 MOV r1, r2 ADD r3, r4, #1 BL SMustGetArea BVS %FT99 ; Get the canonical values MOV r4, r2 ; Area for new disc -> r4 MOV r6, r3 ; size of disc name area -> r6 MOV r3, r1 ; Area for special field -> r3 Push "r3,r4" MOV r1, r7 MOV r2, r8 MOV r0, #fsfunc_CanonicaliseSpecialAndDisc [ debugcanonical DSTRING r1, "CallCanonical(",cc DSTRING r2, ",",cc DREG r3, ",",cc DREG r4, ",",cc DREG r5, ",",cc DREG r6, ",",cc DLINE ")->",cc ] BL CallFSFunc_Given [ debugcanonical DSTRING r1, "(",cc DSTRING r2, ",",cc DREG r3, ",",cc DREG r4, ",",cc DREG r5, ",",cc DREG r6, ",",cc DLINE ")" ] Pull "r3,r4" MOVVS r1, r3 BVS %FT98 [ debugcanonical DSTRING r1, "....after canonicalisation #",cc DSTRING r2, "::" ] ; Some filing systems don't bother with the bit of the ; FS spec which says they have to copy r3 to r1 and ; r4 to r2 on exit from that FS entry point. NFS, for ; example. This is what causes the System Heap to fill ; up with literally thousands of blocks saying "Printer" ; whenever you are using an NFS printer (although it ; does remember to update R2 so you don't get the disc ; name leaking too) (sbrodie 17/01/1999) TEQ r2, #NULL ; was disc name returned as zero? MOVNE r2, r4 ; no - so update R2 based on what it *should* be TEQ r1, #NULL ; was special field returned as zero? MOVNE r1, r3 ; no - so update R1 based on what it *should* be ; Free the unwanted areas Push "r2" TEQ r2, #NULL MOVEQ r2, r4 BLEQ SFreeArea TEQ r1, #NULL MOVEQ r2, r3 BLEQ SFreeArea Pull "r2" EXIT 50 ; Stupid filing system can't canonicalise a special and disc! ; Nowt we can do with a special field, but we can try to do something ; with a disc. [ debugcanonical DLINE "Stupid filing system to canonicalise..." ] ; In order to placate ArcFS only *Dir to @ if special field is null TEQ r1,#NULL EXIT NE ; Exit if special field supplied ; We've got a disc name, so let's *Dir to that MOV r5, r1 MOV r4, r2 TEQ r2, #0 MOVEQ r1, #'@' ; store "@" onto stack as it's going to get mangled STREQ r1, [sp] MOVEQ r1, sp MOVEQ r3, #0 BEQ %FT60 ; Generate ":Discname" on the stack MOV r1, r2 BL strlen ADD r3, r3, #1+1+3 BIC r3, r3, #3 SUB sp, sp, r3 MOV r1, sp MOV r0, #":" STRB r0, [r1], #1 BL strcpy MOV r1, sp 60 Push "r0-r5" MOV r0, #fsfunc_Dir [ debugcanonical DSTRING r1, "*Dir to " ] BL CallFSFunc_Given [ debugcanonical BVC %FT00 ADD r0, r0, #4 DSTRING r0, "*Dir failed with error " 00 ] Pull "r0-r5" ADD sp, sp, r3 MOV r1, r5 ; Restore special/discname pointers MOV r2, r4 MOVVS r3, #0 STRVS r3, globalerror EXITS VS ; Exit if error, don't canonicalise disc name ; This fixes problem with ArcFS ; Find name of selected disc Push "r1-r2" SUB sp, sp, #64 ; Somewhere to read the discname MOV r0, #&ff STRB r0, [sp] ; Stack the length just in case the FS is stupid MOV r0, #fsfunc_ReadDiscName MOV r2, sp BL CallFSFunc_Given LDRVCB r3, [sp] MOVVS r3, #0 ; On error length=0 and cancel globalerror STRVS r3, globalerror MOVVS r3, #&ff CLRV ; Check for non-filled in block ; Check for 0 length name TEQ r3, #&ff TEQNE r3, #0 BEQ %FT80 [ debugcanonical ADD r0, sp, #1 DSTRING r0, "Disc name is " ] ; Check for "Unset" TEQ r3, #7 LDREQB r0, [sp, #1] TEQEQ r0, #"""" LDREQB r0, [sp, #2] TEQEQ r0, #"U" LDREQB r0, [sp, #3] TEQEQ r0, #"n" LDREQB r0, [sp, #4] TEQEQ r0, #"s" LDREQB r0, [sp, #5] TEQEQ r0, #"e" LDREQB r0, [sp, #6] TEQEQ r0, #"t" LDREQB r0, [sp, #7] TEQEQ r0, #"""" BEQ %FT80 ADD r3, r3, #1 BL SMustGetArea BVS %FT80 TEQ r2, #Nowt MOVEQ r1, #NULL BEQ %FT75 MOV r1, r2 ADD r2, sp, #1 MOV r0, #0 LDRB r3, [sp] STRB r0, [r2, r3] ; Ensure disc name null terminated BL strcpy ; dest = r1, src = r2 75 [ debugcanonical DSTRING r1, "Stored disc name is " ] STR r1, [sp, #64+1*4] ; Update disc name ptr ; Restore stack 80 ADD sp, sp, #64 Pull "r1-r2" [ debugcanonical DSTRING r2, "Returned disc name is " DSTRING r1, "Returned special field is " ] EXIT 98 ; Error exit with both strings allocated: ; r1 - special field ; r4 - disc name STR r0, [sp] MOV r2, r4 BL SFreeArea LDR r0, [sp] 99 ; Error exit with only the new special field allocated: ; r1 - special field STR r0, [sp] MOV r2, r1 BL SFreeArea EXIT ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; GetDiscFromPath ; ; In r1 = path^ ; ; Out r1 = path^ after disc and . ; r2 = disc^ or NULL GetDiscFromPath Entry ; Check for the presence of a disc name LDRB r14, [r1] TEQ r14, #":" MOVNE r2, #NULL EXIT NE ; The start of the disc name ADD r2, r1, #1 ; Advance to the disc name's end 10 LDRB r14, [r1], #1 TEQ r14, #"." TEQNE r14, #0 BNE %BT10 ; If there's more, terminate the disc name, else move the ; rover (r1) back to the terminating nul TEQ r14, #"." SUBNE r1, r1, #1 MOVEQ r14, #0 STREQB r14, [r1, #-1] EXIT ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; GetAbsolute ; ; In r1 = path^ (path without disc or special field) ; ; Out r0 = Absolute char in path or 0 if none there ; r1 = path^ (path without disc, special field or absolute) ; GetAbsolute Entry "r2" LDRB r0, [r1] BL IsAbsolute MOVNE r0, #0 EXIT NE LDRB r2, [r1, #1]! TEQ r2, #"." ADDEQ r1, r1, #1 EXIT ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; ObtainAbsoluteParts ; ; In r1 = Path^ ; r3 = @/% relativity indicator (0 for @, not 0 for %) ; r6 = special field^ ; fscb ; ; Out r0 = special field^ (SNewStringed string) ; r1 = user's path^ (part of original user's path) ; r2 = disc^ (SNewStringed string) ; r3 = Abs's path^ (SNewStringed string) ; ; The path gets analysed, the disc split off, the absolute chosen ; and the parts for reconstruction into a path returned. ; ObtainAbsoluteParts Entry "r0-r5,r7", 4 [ debugcanonical DSTRING r1,"Obtain absolute parts of " DREG r3, "Relativity is " DSTRING r6, "Special is " ] ; No strings allocated yet MOV r0, #NULL STR r0, [sp, #Proc_LocalStack + 0*4] STR r0, [sp, #Proc_LocalStack + 2*4] STR r0, [sp, #Proc_LocalStack + 3*4] STR r0, [sp] ; Get the disc and the absolute BL GetDiscFromPath BL GetAbsolute STR r1, [sp, #Proc_LocalStack + 1*4] ; Is there a disc name? TEQ r2, #NULL BNE %FT70 ; There is no disc name ; Is there a special field? TEQ r6, #NULL BNE %FT40 ; There is no disc and no special field - substitute an absolute reference TEQ r0, #"$" BNE %FT05 MOV r4, #Dir_Current B %FT10 05 BL %FT90 10 ; Post-processing to obtain strings for special, disc and path ; r4 -> part of SysVar indicating directory MOV r7, r0 ; For later ; Read the directory string MOV r0, sp MOV r2, r4 BL ReadDir EXIT VS 11 LDR r1, [sp] LDRB r14, [r1] TEQ r14, #"#" MOVNE r0, #NULL BNE %FT15 ; Police the special field ADD r1, r1, #1 BL PoliceSpecial BVS %FT20 [ debugcanonical DSTRING r1,"Special accepted" ] ; Skip past special field MOV r0, #":" BL strchr BNE %FT50 ; Not found [ debugcanonical DSTRING r1, "strchr gives " ] ADD r1, r1, #1 ; Reconstruct pointer to special LDR r0, [sp] ADD r0, r0, #1 15 [ debugcanonical DSTRING r1,"name being checked is " ] ; Check the name BL PoliceName BVC %FT30 ; Bad name means use default disc and path 20 [ debugcanonical DLINE "Name from dirstore due to being bad" ] CLRV B %FT50 30 [ debugcanonical DLINE "Dirstore accepted" ] ; Split into disc and path BL GetDiscFromPath TEQ r7, #"$" MOVNE r3, r1 ; The path as part of the dirpath addr r3, Default_RootD_Path, EQ ; Exit for 'no special field and no disc' B %FT80 40 ; ; Special field and no disc specified ; ; r0 = Absolute char ; r1 = user's path^ ; r2 = disc^ = NULL ; r3 = relativity indicator ; r4 unused ; r5 unused ; r6 = user's special field^ ; ; Possible actions: ; a) Construct path from path's <sp>, NULL and Default_RootD_Path ("$") ; b) Construct path from <abs>'s <sp>, <abs>'s disc and <abs>'s path ; c) Construct path from path's <sp>, NULL and default <abs>'s path for FS type ; ; if $ in path: ; (a) ; else ; if no abs specified ; set <abs> to default start dir ; if <special>=<abs>'s special ; (b) ; else ; (c) ; Is it #<special>:$ TEQ r0, #"$" MOVEQ r0, r6 addr r3, Default_RootD_Path, EQ BEQ %FT80 ; Convert absolute to fsw_dirspart string BL %FT90 MOV r7, r0 ; For later (absolute) ; Get the <abs>'s special field MOV r0, sp MOV r2, r4 BL ReadDir EXIT VS LDR r1, [sp] [ debugcanonical DSTRING r1, "Name from dirstore is " ] LDRB r14, [r1] TEQ r14, #"#" MOVNE r1, #NULL BNE %FT45 MOV r0, #":" BL strchr MOVNE r1, #NULL BNE %FT45 MOV r0, #0 STRB r0, [r1] MOV r5, r1 45 ; Compare with the user's special field MOV r2, r6 BL strcmp BNE %FT50 ; Re-terminate the special field TEQ r1, #NULL MOVNE r0, #":" STRNEB r0, [r5] B %BT11 50 ; ReadDir dir string now rejected [ debugcanonical DLINE "Name from dirstore rejected" ] ; Use the user's special MOV r0, r6 ; and copy default disc (NULL), and default path MOV r2, #NULL LDR r1, [fscb, #fscb_info] TST r1, #fsinfo_handlesurdetc BNE %FT60 TEQ r7, #"@" addr r3, Default_CSD_Path, EQ TEQ r7, #"%" addr r3, Default_LibD_Path, EQ TEQ r7, #"\\" addr r3, Default_PSD_Path, EQ TEQ r7, #"&" addr r3, Default_URD_Path, EQ B %FT80 60 TEQ r7, #"@" addr r3, Default_CSD_Whan_Path, EQ TEQ r7, #"%" addr r3, Default_LibD_Whan_Path, EQ TEQ r7, #"\\" addr r3, Default_PSD_Whan_Path, EQ TEQ r7, #"&" addr r3, Default_URD_Whan_Path, EQ B %FT80 70 ; Disc name present - must be relative to $ ; In r0 = Absolute char from path, or 0 if none ; r1 = Path without disc or absolute char ; r2 = disc ; r3 = @/% relativity indicator (0 for @, not 0 for %) ; r6 = special field^ ; r7 = original path^ ; ; Two cases: ; non-handlesurdetc flavour filing system: ; Check :<disc> isn't followed by <abs> where <abs> != $ ; If ok construct #<user's sp>::<user's disc>.$ ; handlesurdetc flavour filing system: ; :<disc>.& construct #<user's sp>::<user's disc>.& ; :<disc> or :<disc>.$ construct #<user's sp>::<user's disc>.$ ; :<disc>.% construct #<user's sp>::<user's disc>.% ; :<disc>.<abs other than $, & or %> give error ; LDR lr, [fscb, #fscb_info] TST lr, #fsinfo_handlesurdetc BNE %FT75 TEQ r0, #"$" TEQNE r0, #0 ADRNEL r0, ErrorBlock_WasntDollarAfterDisc BLNE CopyError EXIT VS MOV r0, r6 ; Use user's special field addr r3, Default_RootD_Path MOV r5, #0 B %FT80 75 TEQ r0, #"$" TEQNE r0, #"&" TEQNE r0, #"%" TEQNE r0, #0 ADRNEL r0, ErrorBlock_WasntDollarAfterDisc BLNE CopyError EXIT VS TEQ r0, #"%" addr r3, Default_LibD_Whan_Path, EQ TEQ r0, #"&" addr r3, Default_URD_Whan_Path, EQ TEQ r0, #"$" TEQNE r0, #0 addr r3, Default_RootD_Path, EQ MOV r0, r6 ; Use user's special field MOV r5, #0 80 ; Claim strings exit ; ; r0 = special to copy ; r2 = disc to copy ; r3 = path to copy ; r5 = stack adjust once finished [ debugcanonical DSTRING r0, "Claiming SP=",cc DSTRING r2, " dsc=",cc DSTRING r3, " path=" ] MOV r1, r0 ; Map NULL, Nowt or '' special fields to NULL TEQ r1, #NULL TEQNE r1, #Nowt LDRNEB r0, [r1] TEQNE r0, #0 MOVEQ r1, #NULL ; Ensure special field terminated TEQ r1, #NULL BEQ %FT82 Push "r1" MOV r0, #":" BL strchr MOVEQ r0, #0 STREQB r0, [r1] Pull "r1" 82 ADD r0, sp, #Proc_LocalStack + 0*4 BL SNewString ADDVC r0, sp, #Proc_LocalStack + 2*4 MOVVC r1, r2 BLVC SNewString ADDVC r0, sp, #Proc_LocalStack + 3*4 MOVVC r1, r3 BLVC SNewString ; Free the dir string MOV r0, sp BL SFreeLinkedString EXIT VC ; Error exit - free the strings LDR r2, [sp, #Proc_LocalStack + 0*4] TEQ r2, #NULL BLNE SFreeArea LDR r2, [sp, #Proc_LocalStack + 2*4] TEQ r2, #NULL BLNE SFreeArea EXIT 90 ; Subroutine to convert (r0,r3)=(absolute, default absolute) ; into r4=Dir_Blah number TEQ r0, #0 BNE %FT95 TEQ r3, #0 MOVEQ r0, #"@" MOVNE r0, #"%" 95 TEQ r0, #"@" MOVEQ r4, #Dir_Current TEQ r0, #"\\" MOVEQ r4, #Dir_Previous TEQ r0, #"&" MOVEQ r4, #Dir_UserRoot TEQ r0, #"%" MOVEQ r4, #Dir_Library MOV pc, lr ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; StitchAbsolutePartsTogether ; ; In r0 = special field^ ; r1 = user's path^ ; r2 = disc^ ; r3 = Abs's path ; r6 = Special field^^ to replace ; r7 = path^^ to replace ; fscb ; ; Out parts joined and replace old values ; ; The disc and special field get canonicalised before being used. ; Path gets parents reduced. ; StitchAbsolutePartsTogether Entry "r0,r1,r2,r3,r4,r5,r6,r7,r8,r9" [ debugcanonical DSTRING r0,"Constructing new path from ",cc DSTRING r2," ",cc DSTRING r3," ",cc DSTRING r1," " ] ; Preserve user's path^ in r8 MOV r8, r1 ; Preserve the original special field and disc ; to test whether the new values should be freed afterwards or not MOV r4, r0 MOV r5, r2 MOV r1, r0 BL CanonicaliseSpecialAndDisc EXIT VS ; Preserve caned disc in r9 MOV r9, r2 ; ; Replace the special field ; SUB sp, sp, #4 MOV r2, r1 TEQ r1, #NULL STREQ r1, [sp] MOVNE r0, sp BLNE SGetLinkedString ADDVS sp, sp, #4 BVS %FT98 MOV r0, r6 BL SFreeLinkedString Pull "r0" STR r0, [r6] BVS %FT98 ; Free the RMA special field TEQ r2, r4 BLNE SFreeArea BVS %FT99 10 ; Construct a new path ; ; r0 = unused ; r1 = unused ; r2 = unused ; r3 = Abs's path^ ; r4 = unused ; r5 = original disc^ ; r6 = unused ; r7 = orig. path^^ ; r8 = user's path^ ; r9 = use this disc^ MOV r4, r3 ; Get the length into r3 MOV r3, #0 ; The disc MOVS r1, r9 BLNE strlen_accumulate ADDNE r3, r3, #2 ; for the : and the . ; The Abs's path MOV r1, r4 ; Abs's path never NULL BL strlen_accumulate ; The user's path LDRB r1, [r8] TEQ r1, #0 ADDNE r3, r3, #1 ; For the . if the user's path is non-empty MOV r1, r8 BL strlen_accumulate ADD r3, r3, #1+:LEN:".!Run" ; Add one for the terminator and ".!Run" ; Allocate a new area for the path and replace the old ; r1 holds the user's path during this SUB sp, sp, #4 MOV r0, sp [ debugheap DLINE "StitchAbsolutePartsTogether:",cc ] BL SGetLinkedArea ADD sp, sp, #4 BVS %FT99 MOV r6, r2 ; Hold original new path start in r6 ; Copy the various parts to make up the name ; Copy the disc name, if present MOV r1, r2 TEQ r9, #NULL MOVNE r2, #":" STRNEB r2, [r1], #1 MOVNE r2, r9 BLNE strcpy_advance ; Hold position in new path after disc for ReduceParents later MOV r3, r1 LDRNEB r2, [r4] TEQNE r2, #0 MOVNE r2, #"." STRNEB r2, [r1], #1 ; Copy the Abs's path MOV r2, r4 BL strcpy_advance ; Copy the user's path LDRB r2, [r8] TEQ r2, #0 MOVNE r2, #"." STRNEB r2, [r1], #1 MOV r2, r8 BL strcpy_advance ; Replace the old path MOV r0, r7 BL SFreeLinkedString STR r6, [r7] BVS %FT99 ; Reduce the parents now using position after disc saved earlier MOV r2, r3 BL ReduceParents ; Free the disc name if necessary TEQ r5, r9 EXIT EQ MOVS r2, r9 BLNE SFreeArea EXIT 98 ; Error exit - free both special field and disc if necessary ; r1 = new special field^ ; r4 = original special field^ ; r5 = original disc^ ; r9 = new disc^ TEQ r1, r4 BEQ %FT99 MOVS r2, r1 BLNE SFreeArea 99 ; Error exit - free disc if necessary ; r5 = original disc^ ; r9 = new disc^ TEQ r5, r9 EXIT EQ MOVS r2, r9 BLNE SFreeArea EXIT ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; CanonicalisePath ; ; In r1 = path^^ ; r3 = Relativity indicator ; r6 = special field^^ ; fscb ; ; Out Path canonicalised ; CanonicalisePath Entry "r0,r1,r2,r3,r6,r7" MOV r7, r1 LDR r1, [r1] LDR r6, [r6] BL ObtainAbsoluteParts EXIT VS LDR r6, [sp, #4*4] [ debugheap DREG r0, "Special into stitch absolute parts is " ] BL StitchAbsolutePartsTogether ; Free the strings generated by ObtainAbsoluteParts BL SFreeArea ; free disc MOV r2, r0 BL SFreeArea ; free special MOV r2, r3 BL SFreeArea ; free abs's path MOVVC r1, r7 LDRVC r6, [r6] BLVC UnWildcardPath EXIT ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; ResolveWildcardBySteam ; ; In r0 = objecttype of directory ; r1 = path^ of directory in which wildcard resides ; r2 = wildcard^ to resolve ; r6 = special field^ or scb^ ; fscb ; ; Out r0 corrupt ; r2 = RMAlloced resolved wildcard, or NULL if not found ; MinWildCardSpace * &10 MaxWildCardSpace * &400 ResolveWildcardBySteam Entry "r1,r3,r4,r5,r6,r7" ; Hold wildcard for later MOV r7, r2 GetLumpOfStack r5, #MinWildCardSpace, #MaxWildCardSpace, #2048, %FA70 ; Start at start of directory MOV r4, #0 10 ; Read some more dir entries MOV r0, #fsfunc_ReadDirEntries MOV r2, sp MOV r3, #MaxWildCardSpace ; A big number Push "r1,r5,r6" BL CallFSFunc_Given Pull "r1,r5,r6" ADDVS sp, sp, r5 EXIT VS ; No entries read at all? TEQ r3, #0 BEQ %FT60 ; Got some entries, lets wildmatch through them MOV r2, r7 MOV r1, sp 20 ; Have we found a match? BL WildMatch BEQ %FT50 ; Skip over unmatched name 30 LDRB lr, [r1], #1 TEQ lr, #0 BNE %BT30 ; Decrement names count and loop if non-zero SUBS r3, r3, #1 BNE %BT20 ; More entries? CMP r4, #-1 ADDNE lr, sp, r5 LDRNE r1, [lr, #0*4] BNE %BT10 40 ; No more entries, hence no match ADD sp, sp, r5 MOV r2, #NULL EXIT 50 ; Found a match pointed to by r1 BL strlen ADD r3, r3, #1 BL SMustGetArea ; Bad fail ADDVS sp, sp, r5 EXIT VS ; Copy the string into the new piece of memory Swap r1, r2 BL strcpy ; Drop the stack frame ADD sp, sp, r5 ; Result in r2 MOV r2, r1 EXIT 60 ; No entries read this time CMP r4, #-1 BEQ %BT40 ; No more entries because we've reached the end ADD sp, sp, r5 ; Drop the stack frame 70 ; Not enough stack error exit - and no stack frame claimed ADRL r0, ErrorBlock_NotEnoughStackForWildcardResolution BL CopyError EXIT ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; ResolveWildcard ; ; In r1 = path^ of directory in which wildcard resides. ; This must be canonical. ; r2 = wildcard^ to resolve ; r6 = special field^/scb^ ; fscb (not a MultiFS) ; ; Out r2 = RMAlloced resolved wildcard, or NULL if not found ; ResolveWildcard Entry "r0,r1,r2,r3,r4,r5,fscb" ; Ensure the directory exists, but don't care about it's attributes BL EnsureCanonicalObject BLVC AssessDestinationForPathTailForDirRead EXIT VS ; Get the wildcard back LDR r2, [sp, #2*4] ; Is the fscb a MultiFS fscb? LDR r14, [fscb, #fscb_info] ; Wish to get full fsinfo word TST r14, #&ff BEQ %FT20 ; Does the non-MultiFS fscb support the MultiFS extensions? TST r14, #fsinfo_multifsextensions BEQ %FT20 ; We've got a non-MultiFS filing system supporting MultiFS extensions ; including fsfunc_ResolveWildcard ; ; In: ; r0 = fsfunc_ResolveWildcard ; r1 = directory in which Wildcard sits ; r2 = destination to place result, or 0 if just want length of result given ; r3 = Wildcard to resolve ; r5 = size of destination ; r6 = Special field ; ; Out: ; r2 = unchanged or -1 if not found ; r4 = overhang of result, 0 if fitted, or < 0 if FS wants resolution done by steam ; MOV r0, #fsfunc_ResolveWildcard MOV r3, r2 GetLumpOfStack r5, #MinWildCardSpace, #MaxWildCardSpace, #2048, %FA40 MOV r2, sp Push "r1,r5" BL CallFSFunc_Given Pull "r1,r5" ; Error? BVS %FT50 ; Is the filing system asking me to do it by steam? CMP r4, #0 MOVLT r2, r3 BLT %FT10 ; Signed < ; Not found? CMP r2, #-1 ADDEQ sp, sp, r5 MOVEQ r2, #NULL STREQ r2, [sp, #2*4] EXIT EQ ; Was there enough room for the name (did we overflow)? CMP r4, #0 BGT %FT30 ; The name's on the stack - give it some RMA MOV r1, sp BL strlen ADD r3, r3, #1 BL SMustGetArea BVS %FT50 ; Got the memory - copy the string Swap r1, r2 BL strcpy ; Drop the stack chunk and set return value ADD sp, sp, r5 STR r1, [sp, #2*4] EXIT 10 ; Do it by steam because we were asked to - drop the stack frame ADD sp, sp, r5 20 ; Do it by steam because the filing system can't cope BL ResolveWildcardBySteam STRVC r2, [sp, #2*4] STRVS r0, [sp] EXIT 30 ; Not enough stack... and drop the stack frame ADD sp, sp, r5 40 ADRL r0, ErrorBlock_NotEnoughStackForWildcardResolution BL CopyError STR r0, [sp] EXIT 50 ; VS exit - drop the stack frame ADD sp, sp, r5 STR r0, [sp] EXIT ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; SkipToLeafEnd ; ; In r2 = path^ ; ; Out r2 advanced to next . or terminator ; SkipToLeafEnd Entry 10 LDRB r14, [r2], #1 TEQ r14, #"." TEQNE r14, #0 BNE %BT10 SUB r2, r2, #1 EXIT ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; UnWildcardPath ; ; In r1 = linked semi-canonical (:<disc>.<abs><rest of path>) path^^ ; r6 = Special field^ ; fscb (not image filing system) ; ; Out Path has resolvable wildcards resolved ; UnWildcardPath Entry "r0,r1,r2,r3,r4,r5,r7" [ debugcanonical Push r1 LDR r1,[r1] DSTRING r1,"UnWildcarding " Pull r1 ] ; r7 = path^^ ; r1 = start of element being checked ; r2 = end of element being checked MOV r7, r1 LDR r1, [r7] MOV r2, r1 ; Skip the disc name (if present) LDRB r14, [r2] TEQ r14, #":" BNE %FT10 BL SkipToLeafEnd LDRB r0, [r2] TEQ r0, #"." [ debugcanonical BEQ %FT01 DLINE "Path has no leaves - no unwildcarding to do" 01 ] EXIT NE ; Start is after separator ADD r2, r2, #1 10 MOV r1, r2 BL SkipToLeafEnd ; Check for this leaf being wildcarded ; Patch in a terminator whilst we do the check LDRB r0, [r2] MOV r14, #0 STRB r14, [r2] BL Util_CheckWildName STRB r0, [r2] BEQ %FT20 ; Is that all? TEQ r0, #0 [ debugcanonical BNE %FT01 LDR r1,[r7] DSTRING r1,"Result is " 01 ] EXIT EQ ; There's more - move to next leaf ADD r2, r2, #1 B %BT10 20 ; It is wildcarded - resolve it ; Temporarily terminate the dirpath and the wildleaf LDR r14, [r7] CMP r1, r14 MOV r14, #0 LDRB r0, [r2] STRB r14, [r2] STRHIB r14, [r1, #-1] ; Save the ends of the leaf MOV r4, r1 MOV r5, r2 ; Set up the ResolveWildcard parameters MOV r2, r1 LDRHI r1, [r7] MOVLS r1, r2 ; A nul string for dir if first leaf is wildcarded BL ResolveWildcard [ debugcanonical BVC %FT01 DLINE "Wildcard resolution error" 01 ] EXIT VS ; Put the . or nul back STRB r0, [r5] ; Was a match found - if not tidy up and give up! TEQ r2, #NULL BNE %FT30 LDR r14, [r7] CMP r4, r14 MOV r14, #"." STRHIB r14, [r4, #-1] [ debugcanonical BNE %FT01 Push r1 LDR r1,[sp, #1*4] LDR r1,[r1] DSTRING r1,"Element not found - result is " Pull r1 01 ] EXIT 30 ; Found a match - reconstruct the path ; Hold start of path (which may be a nul string, and not [r7]) MOV r4, r1 ; accumulate the path length MOV r3, #0 BL strlen_accumulate ; 1st half of path MOV r1, r2 BL strlen_accumulate ; Resolved wildcard LDRB r1, [r5] TEQ r1, #0 ADDNE r1, r5, #1 BLNE strlen_accumulate ; 2nd half of path ADD r3, r3, #1+1+:LEN:".!Run"+1 ; 2 .s, ".!Run" and the terminator ; Get some linked memory MOV r1, r2 ; Save Wilcard over SGetLinkedArea SUB sp, sp, #4 MOV r0, sp [ debugheap DLINE "UnWildcardPath:",cc ] BL SGetLinkedArea ADD sp, sp, #4 BVS %FT99 ; Copy the various parts to join them together MOV r0, r1 MOV r1, r2 MOV r3, r2 [ debugcanonical DSTRING r4,"Reconstructing path from: ",cc DSTRING r0, " ",cc DSTRING r5, " " ] MOV r2, r4 BL strcpy_advance ; First half of path MOV r2, #"." STRB r2, [r1], #1 ; . MOV r2, r0 BL strcpy_advance ; Resolved wildcard LDRB r2, [r5] TEQ r2, #0 MOVNE r2, #"." STRNEB r2, [r1], #1 ; . ADDNE r2, r5, #1 BLNE strcpy ; Second half of path ; (not strcpy_advance as we want r1 to point at the start ; of the remainder of the path - the unchecked bit) ; Junk the wildcard, which we've now copied MOV r2, r0 BL SFreeArea ; Junk the original path MOV r0, r7 BL SFreeLinkedString ; Replace with the new string STR r3, [r7] [ debugcanonical BVC %FT01 DLINE "Error return releasing strings" 01 ] EXIT VS MOV r2, r1 B %BT10 99 ; Error allocating area for new path - free wildcard in r1 MOV r2, r1 BL SFreeArea [ debugcanonical DLINE "Error exit" ] EXIT END