home *** CD-ROM | disk | FTP | other *** search
Text File | 1985-08-16 | 5.6 KB | 247 lines | [TEXT/MACA] |
- ; File SortMenu.TXT
- ;--------------------------------------------------------------------
- ;
- ; This program installs code in the system heap that patches out
- ; AddResMenu so it returns with the added names sorted in alphabetical
- ; order. It works internationally, since it uses Pack6 for the
- ; string compare.
- ;
- ; written by Andy Hertzfeld 04-Aug-85 (in the big Apple)
- ;
- ;--------------------------------------------------------------------
-
- INCLUDE MacTraps.D
-
- XDEF START
-
- START
- BRA InstallIt
-
- AddResPatch
- LEA theMenuHandle,A0 ;get locals address
- MOVE.L 8(SP),A1 ;get menu handle
- MOVE.L A1,(A0)+ ;remember menu handle
- MOVE.L (SP)+,(A0) ;remember return address
-
- SUBQ #2,SP
- MOVE.L A1,-(SP) ;push the menu handle
- _CountMItems ;count the items
- LEA baseItem,A0
- MOVE.W (SP)+,(A0) ;remember # of items
-
- ; now run the old routine
-
- MOVE.L OldARMenu,A0 ;get old routine
- JSR (A0) ;invoke it
-
- ; allocate work space and save registers
-
- LINK A6,#-260 ;space for string plus 4
- MOVEM.L D3-D6/A2-A4,-(SP) ;save some work registers
-
- ; load Pack6 into memory
-
- SUBQ #4,SP
- MOVE.L #$5041434B,-(SP) ;push PACK
- MOVE #6,-(SP) ;pack 6
- _GetResource ;load it in
- ADDQ #4,SP
-
- ; now count the # of items now in the menu and compute how many were added
-
- SUBQ #2,SP ;reserve space for result
- MOVE.L theMenuHandle,A2 ;keep menuHandle in A2
- MOVE.L A2,-(SP) ;push it
- _CountMItems ;count em up
- MOVE.W (SP)+,D3 ;keep # of items in D3
- MOVE.W BaseItem,D4 ;keep base items in D4
-
- MOVE D3,D5 ;copy item count
- SUB D4,D5 ;compute # of new items
- BEQ DoneARMenu ;if none, we're done
-
- ; OK, now we're ready to do the real work. A3 will point to the current
- ; item we're bubbling. First, skip to it.
-
- MOVE.L (A2),A3 ;start at the beginning
- ADD.W #14,A3 ;skip header
- MOVEQ #0,D0 ;clear out high part
- MOVE.B (A3)+,D0 ;get title length
- ADD.W D0,A3 ;skip over it
-
- ; skip the number of items in D4
-
- BRA.S NextSkipBase
- SkipBaseLoop
- MOVE.B (A3),D0 ;get item length
- ADD.W D0,A3 ;skip item
- ADDQ.W #5,A3 ;skip length, prop bytes
- NextSkipBase
- DBRA D4,SkipBaseLoop
-
- ; remember the first item we're starting with
-
- MOVE.L A3,A4
-
- ; here's the sort loop. Compare the current item with the next one and,
- ; if it's lexically greater, swap them
-
- SortLoop0
- MOVE.L A4,A3 ;start with first one
- SortLoop1
- MOVEQ #0,D0
- MOVE.B (A3),D0
- LEA 5(A3,D0),A0 ;compute next one
- MOVE.L A0,D6 ;remember for later
-
- TST.B (A0) ;is it the last?
- BEQ.S NextIteration ;if so, skip
-
- ; use Pack6 for the string compare
-
- MOVE.L A3,A1
- SUBQ #2,SP ;reserve space for result
- MOVEQ #0,D1
- MOVEQ #0,D2
- MOVE.B (A1)+,D1 ;get 1st length
-
- ; if it begins with null, skip it
-
- TST.B (A1)
- BNE.S @0
- ADDQ #1,A1
- SUBQ #1,D1
- @0
- MOVE.L A1,-(SP) ;push string
- MOVE.B (A0)+,D2 ;get 2nd length
-
- ; ditto for second string
-
- TST.B (A0)
- BNE.S @1
- ADDQ #1,A0
- SUBQ #1,D2
- @1
- MOVE.L A0,-(SP) ;push string
- MOVE.W D1,-(SP) ;push 1st length
- MOVE.W D2,-(SP) ;push 2nd string
-
- MOVE.W #10,-(SP) ;push selector
- _Pack6 ;invoke string compare
- MOVE.W (SP)+,D0 ;get result
- BLE.S NextItem ;if in order, skip
-
- ; the first item is greater than the second, so swap them. First move
- ; first item into a temporary location
-
- MOVE.L A3,A0 ;source address
- BSR.S GetSourceLen
- LEA -256(A6),A1 ;destination
- _BlockMove
-
- ; move the second item over the first
-
- MOVE.L D6,A0 ;source address
- MOVE.L A3,A1 ;destination address
- BSR.S GetSourceLen
- _BlockMove
-
- ; move the first back in
-
- LEA -256(A6),A0 ;source address
- MOVEQ #0,D0
- MOVE.B (A3),D0
- LEA 5(A3,D0),A1 ;destination address
- MOVE.L A1,D6 ;new next item
- BSR.S GetSourceLen
- _BlockMove
-
- ; now try the next item, bubbling down until we've reached the bottom
-
- NextItem
- MOVE.L D6,A3 ;point A3 to next item
- BRA.S SortLoop1 ;go put it in order
-
- ; GetSourceLen is a utility that returns the length of the string pointed
- ; to by A0 plus 5 in D0.
-
- GetSourceLen
- MOVEQ #0,D0 ;clear D0
- MOVE.B (A0),D0 ;get the length
- ADDQ #5,D0 ;include length, prop bytes
- RTS
-
- ; NextIteration is the bottom of the outer loop. Repeat it enough times
- ; until it's sorted
-
- NextIteration
- SUBQ #1,D5 ;more to do?
- BGT.S SortLoop0 ;if so, go do it
-
- ; we're all done so deallocate storage, restore registers and return
-
- DoneARMenu
- MOVEM.L (SP)+,D3-D6/A2-A4 ;restore work registers
- UNLK A6 ;release stack frame
-
- MOVE.L theReturnAddress,A0 ;recover return address
- JMP (A0) ;bye-bye!
-
- ; our local variables
-
- theMenuHandle
- DC.W 0,0
- theReturnAddress
- DC.W 0,0
- BaseItem
- DC.W 0
- OldARMenu
- DC.W 0,0
-
- ; InstallIt is the routine that installs the above in the system heap
-
- InstallIt
-
- ; get the address of the current AddResMenu routine and remember it
-
- MOVE.W #$14D,D0 ;trap ID of AddResMenu
- _GetTrapAddress ;get old address
-
- LEA OldARMenu,A1
- MOVE.L A0,(A1) ;remember old address
-
- ; compute size of code and allocate in system heap, then move it in
-
- LEA AddResPatch,A2
- LEA InstallIt,A0
- MOVE.L A0,D0
- SUB.L A2,D0 ;compute size
- MOVE.L D0,D1 ;remember size
-
- DC.W $A51E ;allocate in system heap
- BNE NoInstall ;if error, punt
-
- MOVE.L A0,D2 ;remember base
- MOVE.L A0,A1 ;that's the destination
- MOVE.L A2,A0 ;AddResPatchis source
- MOVE.L D1,D0 ;set up size
- _BlockMove ;move it in
-
- ; patch in the new routine
-
- MOVE.L D2,A0 ;get new address
- MOVE.W #$14D,D0 ;trap ID of AddResMenu
- _SetTrapAddress ;patch it in
-
- ; all done so exit to shell
-
- _ExitToShell
-
- ; handle the error case by beeping
-
- NoInstall
- MOVE #6,-(SP)
- _SysBeep
-
- _ExitToShell
-