; ; dllmerge.s ; ; Merge two DLL resources together (MDW) ; ; © 1994-1998 Straylight ; ;----- Licensing note ------------------------------------------------------- ; ; This file is part of Straylight's Dynamic Linking System (SDLS) ; ; SDLS is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2, or (at your option) ; any later version. ; ; SDLS is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with SDLS. If not, write to the Free Software Foundation, ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ;----- Change history ------------------------------------------------------- ; ; Version By Change ; ; 1.00 MDW Initial version written. ; ; 1.01 MDW Added error handler to stop bombing out on errors. ; ; 1.02 MDW Done copyright and version messages with setdate. ; ; 1.03 MDW Made most SWIs generate errors, and added confirm ; on error handler. ; ; 1.04 MDW Updated dm_setField in line with Sapphire version. ; ; 1.05 MDW Moved menu definition into code area, and copied it ; out at run-time, for the sake of tidiness. Workspace ; now *exactly* &0900 bytes! ; ; 1.06 MDW Used embedded templates instead of separate file. ; ; 1.07 MDW Fixed problem identifying !DLLs folder link dragged ; from Kysmet -- it was returning &FC0 as the filetype, ; instead of &1000/&2000 as expected. I now check ; the type with OS_File instead of relying on the ; type in the message. ; ; 1.08 MDW Reduced size of prompt in `merge' template and ; indirected data buffer. Image now less than 4K. ; Made some other space-saving modifications, although ; I can't reduce the memory requirements to less than ; 8K, which is a shame. ; ; 1.09 MDW Changed LDRs to ADRs when finding version and ; copyright strings, now that the linker can handle it. ; ; 1.10 MDW Moved all messages into a separate file so it can ; be easily changed for different countries should the ; need arise. This is converted to an AOF file and ; linked in during the build. ; ; 1.11 MDW Changed dm_error to base filler strings on `%0' not ; `%1', and updated messages in line with this. ;----- Standard header ------------------------------------------------------ GET libs:header GET libs:swis GET libs:stream ;----- External dependencies ------------------------------------------------ ; --- Embedded template handling --- GET libs:embTemp.sh.embTemp ; --- Linker symbols --- IMPORT |Image$$RW$$Limit| ; --- Linked resources --- GET sh.templates GET sh.messages ; --- Generated strings --- IMPORT version IMPORT cright ;----- Macros --------------------------------------------------------------- MACRO $label TWELVE $string ASSERT :LEN:"$string"<=12 ALIGN $label DCB "$string" % 12-:LEN:"$string" MEND ;----- Icon numbers --------------------------------------------------------- dm_INFO_NAME EQU 7 dm_INFO_PURPOSE EQU 5 dm_INFO_AUTHOR EQU 3 dm_INFO_VERSION EQU 1 dm_MERGE_DEST EQU 2 dm_MERGE_SOURCE EQU 3 dm_MERGE_MSG EQU 5 ;----- Main code ------------------------------------------------------------ AREA |DLLMerge$$Code|,CODE,READONLY ENTRY ; --- main --- ; ; On entry: -- ; On exit: Doesn't main ROUT BL dm_init BL dm_initWimp BL dm_setHandlers returnPoint BL dm_poll exitPoint BL dm_die SWI OS_Exit LTORG ; --- dm_init --- ; ; On entry: -- ; On exit: R12 and R13 set up, other registers corrupted dm_init ROUT ; --- Set up application workspace --- ADRL R12,|Image$$RW$$Limit| ;Find limit of this program SWI OS_GetEnv ;Find info about application MOV R13,R1 ;Start stack at top of slot SUB R0,R13,R12 ;Find how mich space I have LDR R1,=dm_wsize ;How much do I need? CMP R0,R1 ;Do I have enough? ADRLTL R0,msg_errNoMem ;No -- point to the error... SWILT OS_GenerateError ;... and die ; --- Initialise workspace contents --- MOV R0,#0 ;No flags set yet STR R0,dm_flags ;Store that away MOVS PC,R14 ;Return to caller LTORG ; --- dm_initWimp --- ; ; On entry: -- ; On exit: Registers corrupted dm_initWimp ROUT STMFD R13!,{R14} ;Keep link register ; --- Initialise WindowManager --- MOV R0,#200 ;WindowManager version LDR R1,=&4B534154 ;Magic TASK number ADR R2,dm__name ;Point to my name SWI Wimp_Initialise ;Start up the WIMP ; --- Copy the menu over --- ADR R0,dm_menuBk ;Point to output block ADR R1,dm_menuDef ;Point to the definition MOV R2,#dm_menuSize ;Get the size too 00 SUBS R2,R2,#16 ;I'll do 16 at a time LDMCSIA R1!,{R3-R6} ;Load some bytes STMCSIA R0!,{R3-R6} ;Save them out BCS %b00 ;If more to do, loop ADD R2,R2,#16 ;We must have overshot 00 SUBS R2,R2,#4 ;Now do one word at a time LDRCS R14,[R1],#4 ;Load the word STRCS R14,[R0],#4 ;And store it out BCS %b00 ;And loop back again ; --- Load required windows --- MOV R1,#0 ;Not loaded any templates ADRL R0,tpl_progInfo ;Find the template BL dm_loadTemplate ;Load a window STR R0,dm_infohand ;Store that away nicely STR R0,dm_menuBk+28+0*24+4 ;And store as Info... submenu ADRL R0,tpl_merge ;Point to template name BL dm_loadTemplate ;Load a window STR R0,dm_windhand ;Store that away nicely ; --- Fill in the Info window fields --- LDR R0,dm_infohand MOV R1,#dm_INFO_NAME ADR R2,dm__name BL dm_setField MOV R1,#dm_INFO_PURPOSE ADRL R2,msg_infoPurpose BL dm_setField MOV R1,#dm_INFO_AUTHOR ADRL R2,cright BL dm_setField MOV R1,#dm_INFO_VERSION ADRL R2,version BL dm_setField ; --- Open the merge window --- ADR R1,dm_pollbk ;Point to a work block LDR R0,dm_windhand ;Get the window's handle STR R0,[R1,#0] ;Store in the block SWI Wimp_GetWindowState ;Find the position of window MOV R2,#-1 ;Move the window to front STR R2,[R1,#28] ;Store in `behind' field SWI Wimp_OpenWindow ;Open the window LDMFD R13!,{PC}^ ;Return to caller dm__name DCB "DLLMerge",0 dm_menuDef TWELVE "DLLMerge" DCB 7,2,7,0 DCD 16*7+16 DCD 44 DCD 0 DCD &00000000 DCD 0 DCD &07000131 DCD msg_menuInfo,-1,1 DCD &00000080 DCD -1 DCD &07000131 DCD msg_menuQuit,-1,1 dm_menuSize EQU {PC}-dm_menuDef LTORG ; --- dm_setHandlers --- ; ; On entry: -- ; On exit: Registers corrupted dm_setHandlers ROUT ; --- Find somewhere to go on an exception --- STR R13,dm_exceptStack ;Save this stack pointer away ; --- Set up the error handler --- STMFD R13!,{R14} ADR R11,dm_handlers ;Point to handler buffer MOV R0,#6 ;Set up error handler ADR R1,dm_errors ;Point to the error handler MOV R2,R12 ;Set up the workspace ptr ADR R3,dm_stacklim ;Use stack base as error buff SWI OS_ChangeEnvironment ;Set up the handler STMIA R11!,{R1-R3} ;Save the old information ; --- Set up other handlers to quit the program --- MOV R0,#11 ;Set up exit handler ADR R1,dm_exits ;Point to the handler MOV R2,R12 ;Point to my workspace MOV R3,#0 ;No buffer pointer SWI OS_ChangeEnvironment ;Set up the handler STMIA R11!,{R1-R3} ;Save the old information MOV R0,#16 ;Set up UpCall handler ADR R1,dm_upcalls ;Point to the handler MOV R2,R12 ;Point to my workspace MOV R3,#0 ;No buffer pointer SWI OS_ChangeEnvironment ;Set up the handler STMIA R11!,{R1-R3} ;Save the old information LDMFD R13!,{PC}^ ;Return to caller LTORG ; --- dm_killHandlers --- ; ; On entry: -- ; On exit: Registers preserved dm_killHandlers ROUT STMFD R13!,{R0-R3,R11,R14} ;Save registers ADR R11,dm_handlers ;Point to handlers buffer MOV R0,#6 LDMIA R11!,{R1-R3} SWI XOS_ChangeEnvironment MOV R0,#11 LDMIA R11!,{R1-R3} SWI XOS_ChangeEnvironment MOV R0,#16 LDMIA R11!,{R1-R3} SWI XOS_ChangeEnvironment LDMFD R13!,{R0-R3,R11,PC}^ ;Return to caller LTORG ; --- dm_errors --- ; ; On entry: R0 == pointer to my workspace ; On exit: Doesn't -- goes back to main loop at appropriate point dm_errors ROUT ; --- Reset stack and workspace pointers --- MOV R12,R0 ;Point to my workspace LDR R13,dm_exceptStack ;Restore my stack pointer ; --- Is this a double exception? --- LDR R0,dm_flags ;Get my flags TST R0,#dm_ERROR ;Is this a repeated error? BNE %00dm_errors ;Yes -- handle this specially ; --- Mark that we're in the error handler --- ORR R0,R0,#dm_ERROR ;Say we're in the handler STR R0,dm_flags ;Store this in the flags ; --- Report the error and give a chance to quit --- ADRL R1,dm_stacklim+8 ;Point to main error message ADRL R0,msg_errInternal ;Point to error skeleton BL dm_error ;Construct a message MOV R1,#&00000003 ;Provide OK and Cancel boxes ADR R2,dm__name ;Point to my name SWI Wimp_ReportError ;Report the error CMP R1,#1 ;Was OK clicked? BEQ %01dm_errors ;Yes -- return to main loop ADRL R0,msg_errConfirm ;Point to the confirm message MOV R1,#3 ;OK and Cancel buttons again ADR R2,dm__name ;Point to my name SWI Wimp_ReportError ;Display the question CMP R1,#1 ;Was OK clicked? BEQ %01dm_errors ;Yes -- return to main loop B exitPoint ;Commit hari-kiri then ; --- We can continue --- 01dm_errors LDR R0,dm_flags ;Get my flags BIC R0,R0,#dm_ERROR ;There's no error any more STR R0,dm_flags ;Store the flags away B returnPoint ;Go back into the top level 00dm_errors BL dm_killHandlers ;Restore all the handlers ADRL R0,dm_stacklim+4 ;Point to the error buffer SWI OS_GenerateError ;Let the OS handle it all LTORG ; --- dm_exits --- ; ; On entry: -- ; On exit: Doesn't -- branches to main loop dm_exits LDR R13,dm_exceptStack ;Get my stack pointer B exitPoint ;Close down the application ; --- dm_upcalls --- ; ; On entry: R0 == UpCall type ; On exit: Varies dm_upcalls CMP R0,#256 ;Is a new app starting? MOVNES PC,R14 ;No -- return to caller ; --- Hopefully this will never happen :-) --- MOVS PC,R14 ;Return to caller and hope ; --- dm_die --- ; ; On entry: -- ; On exit: Registers corrupted dm_die ROUT STMFD R13!,{R14} BL dm_killHandlers ;Get rid of any handlers SWI Wimp_CloseDown ;Stop being a Wimp task LDMFD R13!,{PC}^ ;Return to caller LTORG ; --- dm_poll --- ; ; On entry: -- ; On exit: Registers corrupted dm_poll ROUT STMFD R13!,{R14} ;Keep return address ; --- Find out if we need continue --- 00dm_poll LDR R0,dm_flags ;Get the flags word TST R0,#dm_QUIT ;Check the quit bit LDMNEFD R13!,{PC}^ ;Return if it failed ; --- Get an event and dispatch it --- AND R0,R0,#dm_SOURCE :OR: dm_DONE ;What's my status? CMP R0,#dm_SOURCE ;If not complete... MOVEQ R0,#0 ;... wait for an idle event MOVNE R0,#1 ;Otherwise, ignore idles ADR R1,dm_pollbk ;Point to the big block SWI Wimp_Poll ;Get an event CMP R0,#19 ;Check the event is sensible MOV R14,PC ;Set up return address ADDLS PC,PC,R0,LSL #2 ;If so, go to branch table B %00dm_poll ;Silly event -- ignore it ; --- Event dispatching table --- B dm_null ;Null_Reason_Code B dm_redraw ;Redraw_Window_Request B dm_open ;Open_Window_Request B dm_close ;Close_Window_Request MOVS PC,R14 ;Pointer_Leaving_Window MOVS PC,R14 ;Pointer_Entering_Window B dm_click ;Mouse_Clicked MOVS PC,R14 ;User_Drag_Box MOVS PC,R14 ;Key_Pressed B dm_menu ;Menu_Selection MOVS PC,R14 ;10 MOVS PC,R14 ;11 MOVS PC,R14 ;12 MOVS PC,R14 ;13 MOVS PC,R14 ;14 MOVS PC,R14 ;15 MOVS PC,R14 ;16 B dm_message ;User_Message B dm_message ;User_Message_Recorded MOVS PC,R14 ;User_Message_Acknowledge LTORG ;----- Event handlers ------------------------------------------------------- ; --- Null_Reason_Code --- ; ; We copy the source to the destination dm_null ROUT STMFD R13!,{R14} ;Stack the link register MOV R0,#26 ;We want to do a copy ADR R1,dm_source ;Point to source app ADR R2,dm_dest ;Point to destination app LDR R3,=&00005003 ;Copy options SWI XOS_FSControl ;Do the copy operation BVS %00dm_null ;If it failed, display msg ; --- Update the DLL$Path variable --- MOV R0,R2 ;Point to destination name SWI Wimp_StartTask ;Run its !Run file ; --- Put the text into the message field --- LDR R0,dm_windhand ;Get the window handle MOV R1,#dm_MERGE_MSG ;Get the icon handle ADRL R2,msg_stateDone ;Point to message BL dm_setField ;Write the text in ; --- Update the flags and quit --- LDR R0,dm_flags ;Get the flags word ORR R0,R0,#dm_DONE ;We've finished STR R0,dm_flags ;Write the flags back LDMFD R13!,{PC}^ ;Return to caller ; --- It failed. Report an error and start again --- 00dm_null ADD R1,R0,#4 ;Point to the message ADRL R0,msg_errCopy ;Point to the error skeleton BL dm_error ;Fill it in MOV R1,#1 ;Only have an OK box ADR R2,dm__name ;Point to my name SWI Wimp_ReportError ;Make an error LDR R0,dm_windhand ;Get the window handle MOV R1,#dm_MERGE_DEST ;Get the icon handle ADR R2,dm__empty ;Point to message BL dm_setField ;Write the text in MOV R1,#dm_MERGE_SOURCE ;Get the icon handle BL dm_setField ;Write the text in MOV R1,#dm_MERGE_MSG ;Get the icon handle ADRL R2,msg_stateErr ;Point to message BL dm_setField ;Write the text in MOV R0,#0 ;Clear all the flags STR R0,dm_flags ;Store them away LDMFD R13!,{PC}^ dm__empty DCB 0 LTORG ; --- Redraw_Window_Request --- ; ; We just bundle the redraw event off to Sculptrix and forget about it dm_redraw ROUT SWI Wimp_RedrawWindow 00dm_redraw CMP R0,#0 MOVEQS PC,R14 SWI XSculptrix_RedrawWindow SWI Wimp_GetRectangle B %00dm_redraw LTORG ; --- Open_Window_Request --- ; ; Just open the window. Nothing could be easier --- dm_open ROUT SWI Wimp_OpenWindow MOVS PC,R14 LTORG ; --- Close_Window_Request --- ; ; We close down the application. dm_close ROUT LDR R0,dm_flags ORR R0,R0,#dm_QUIT STR R0,dm_flags MOVS PC,R14 LTORG ; --- Mouse_Clicked --- ; ; If it's the Info window, we start moving it about. If it's the Merge ; window, we open a menu dm_click ROUT LDR R0,[R1,#12] ;Get the window handle LDR R2,dm_windhand ;Is it the Merge window? CMP R0,R2 ;Find out BEQ %10dm_click ;If so, handle it there LDR R2,dm_infohand ;It may be the Info window CMP R0,R2 ;So check BEQ %20dm_click ;If so, handle it MOVS PC,R14 ;Not recognised -- ignore it ; --- Handle a click on the Merge window --- 10dm_click LDR R0,[R1,#8] ;Get the button status TST R0,#2 ;Check the menu button bit MOVEQS PC,R14 ;If not, return LDMIA R1,{R2,R3} ;Get coordinates from block SUB R2,R2,#64 ;Displace the menu ADR R1,dm_menuBk ;Point to the menu defn SWI Wimp_CreateMenu ;Display the menu MOVS PC,R14 ;Return to caller ; --- Handle a click on the Info window --- 20dm_click LDR R0,[R1,#8] ;Get the button status TST R0,#5 ;Check for Select or Adjust MOVEQS PC,R14 ;If not, return SUB R13,R13,#56 ;Make a drag info block LDR R0,dm_infohand ;Get the Info window handle STR R0,[R13,#0] ;Store the window handle MOV R0,#1 ;Move the window STR R0,[R13,#4] ;Store the drag type MOV R1,R13 ;Point to the block SWI Wimp_DragBox ;Start the window moving ADD R13,R13,#56 ;Reclaim the stack space MOVS PC,R14 ;Return to caller LTORG ; --- Menu_Selection --- ; ; If it's Info, open the Info box. If it's Quit, then quit. dm_menu ROUT LDR R0,[R1,#0] ;Get toplevel selection CMP R0,#0 ;Is it `Info...'? BEQ %10dm_menu ;Yes -- process it CMP R0,#1 ;Is it `Quit'? BEQ dm_close ;Yes -- quit the program MOVS PC,R14 ;Return to caller ; --- Open the Info... window --- 10dm_menu SUB R13,R13,#36 ;Get some workspace MOV R1,R13 ;Point to this new block SWI Wimp_GetPointerInfo ;Where is the mouse now? LDMIA R1,{R2,R3} ;Get the mouse coordinates LDR R0,dm_infohand ;Get the window handle STR R0,[R1,#0] ;Store the window handle SWI Wimp_GetWindowState ;Get the window's information LDMIA R1,{R1,R4-R7} ;Get the window positions SUB R4,R6,R4 ;Get the window width SUB R5,R7,R5 ;And the window height SUB R2,R2,R4,LSR #1 ;Centre window over X ADD R3,R3,R5,LSR #1 ;Centre window over Y ADD R13,R13,#36 ;Reclaim the stack space SWI Wimp_CreateMenu ;Display the Info window MOVS PC,R14 ;And return to caller LTORG ; --- User_Message and User_Message_Recorded --- ; ; Handle Quit messages, and files dropped on the window dm_message ROUT LDR R0,[R1,#16] ;Get message type CMP R0,#0 ;Is it a Message_Quit? BEQ dm_close ;This has the code for quit CMP R0,#3 ;Is it a load message? BEQ %10dm_message ;Yes -- deal with it MOVS PC,R14 ;If not interested, return ; --- Someone dropped a file on my window --- 10dm_message LDR R0,[R1,#20] ;Where was the file dropped? LDR R11,dm_windhand ;Get my window handle CMP R0,R11 ;Do they match? MOVNES PC,R14 ;No -- ignore it ; --- Check what to do with it --- LDR R10,dm_flags ;Get my flags word TST R10,#dm_SOURCE ;Have I finished? MOVNES PC,R14 ;Yes -- not interested then ; --- Got to do something now --- STMFD R13!,{R14} ;Stack link register now BL dm_checkFile ;Make sure it's a !DLLs CMP R0,#0 ;Did it fail? LDMEQFD R13!,{PC}^ ;Yes -- return to poll loop ; --- Which filename do I fill in? --- TST R10,#dm_DEST ;Have I got one filename? BNE %20dm_message ;Yes -- fill in the other ; --- Fill in the first filename --- ADD R1,R1,#44 ;Point to filename ADR R0,dm_dest ;That's the destination file BL dm_strcpy ;Copy it across MOV R2,R1 ;Point to name again MOV R1,#dm_MERGE_DEST+(1<<31) MOV R0,R11 ;And set up the window handle BL dm_setField ;Fill that icon in ; --- Now display a new message --- ADRL R2,msg_stateSource ;Point to the new message MOV R1,#dm_MERGE_MSG ;Put it in the message icon BL dm_setField ;Fill that icon in ORR R10,R10,#dm_DEST ;Remember we've got a name STR R10,dm_flags ;Store the new flags away B %30dm_message ;Reply to the message now ; --- Fill in the second filename --- 20dm_message ADD R1,R1,#44 ;Point to filename ADR R0,dm_source ;That's the source file BL dm_strcpy ;Copy it across MOV R2,R1 ;Point to name again MOV R1,#dm_MERGE_SOURCE+(1<<31) MOV R0,R11 ;And set up the window handle BL dm_setField ;Fill that icon in ; --- Now display a new message --- ADRL R2,msg_stateGoing ;Point to the new message MOV R1,#dm_MERGE_MSG ;Put it in the message icon BL dm_setField ;Fill that icon in ORR R10,R10,#dm_SOURCE ;Remember we've got a name STR R10,dm_flags ;Store the new flags away ; --- Reply to the message in the block --- 30dm_message ADR R1,dm_pollbk ;Point to the message LDR R0,[R1,#8] ;Get his reference STR R0,[R1,#12] ;Store as his reference MOV R0,#4 ;This is an acknowledgement STR R0,[R1,#16] ;Store as the message type MOV R0,#17 ;Don't bother recording it LDR R2,[R1,#4] ;Get his task handle SWI Wimp_SendMessage ;Reply to his message now LDMFD R13!,{PC}^ ;Return to the caller LTORG ;----- Support routines ----------------------------------------------------- ; --- dm_setField --- ; ; On entry: R0 == window handle ; R1 == icon handle ; R2 == string to write ; On exit: Everything preserved unless there was an error dm_setField ROUT STMFD R13!,{R0-R5,R14} ;Stash registers away ; --- Find out about the icon --- AND R4,R1,#&FF000000 ;Get the flag bits out BIC R1,R1,#&FF000000 ;Leave just the icon number SUB R13,R13,#40 ;Make space for icon block STMIA R13,{R0,R1} ;Store the info in it MOV R1,R13 ;Point to the icon block SWI Wimp_GetIconState ;Get the icon's information ; --- Make sure we can change the text --- LDR R1,[R13,#24] ;Get the icon's flags ; --- Now find how much we actually have to copy --- LDR R5,[R13,#36] ;Get the buffer length SUB R5,R5,#1 ;Take terminator into account MOV R0,R2 ;Point to the string to copy BL dm_strlen ;Find out how long it is SUBS R0,R0,R5 ;Find out the difference BICLE R4,R4,#(1<<31) ;If it fits, don't add dots BLE %00dm_setField ;And skip ahead TST R1,#1<<9 ;Is it right aligned? ADDNE R2,R2,R0 ;Yes, chop off front ORRNE R4,R4,#1 ;And set a flag to remember ; --- Copy the text into the buffer --- 00dm_setField LDR R0,[R13,#28] ;Find the buffer address MOV R3,#0 ;Count the length too 10dm_setField CMP R5,R3 ;How much space left in buff? MOVLE R1,#0 ;None -- pretend null char LDRGTB R1,[R2],#1 ;Get a byte from the string CMP R1,#' ' ;Is it a control char? MOVLO R1,#0 ;Yes -- say it's a zero BLO %15dm_setField ;And don't bother with dots ; --- Handle ellipsis generation --- TST R4,#(1<<31) ;Do we put the ellipsis in? BEQ %15dm_setField ;No -- skip ahead then TST R4,#1 ;Are we right-justified? ADDNE R14,R3,#1 ;Yes -- just get the length SUBEQ R14,R5,R3 ;Otherwise find what's left CMP R14,#4 ;Are we within three? MOVLO R1,#'.' ;Yes -- put in a dot then ; --- Return to normality --- 15dm_setField LDRB R14,[R0],#1 ;Get one from the buffer CMP R14,#' ' ;Same for the buffer char MOVLO R14,#0 CMP R1,R14 ;Are they different ORRNE R4,R4,#2 ;Yes -- remember this STRNEB R1,[R0,#-1] ;And store the different char CMP R1,#0 ;Is that end of the string? ADDNE R3,R3,#1 ;No -- bump the length on BNE %10dm_setField ;And go round for another ; --- We've copied the string -- now update the icon --- TST R4,#2 ;Is the string different? BEQ %20dm_setField ;No -- skip ahead MOV R1,#0 STR R1,[R13,#8] ;The EOR mask for setstate STR R1,[R13,#12] ;The BIC mask for setstate MOV R1,R13 ;Point to the block SWI Wimp_SetIconState ;Flicker the icon nastily ; --- Now check for the caret --- SWI Wimp_GetCaretPosition ;Find out where the caret is LDMIA R13,{R2,R4} ;Get the window and icon ADD R0,R13,#40 ;Point past this block LDMIA R0,{R0,R1} ;Get the old window and icon CMP R0,R2 ;Do the window handles match? CMPEQ R1,R4 ;And the icon handles? BNE %20dm_setField ;No -- skip ahead ; --- Push the caret back a little --- LDR R5,[R13,#20] ;Get the caret index CMP R5,R3 ;Is this bigger than new len? MOVGT R5,R3 ;Yes -- trim the index ; --- Now put the caret in the right place --- MOV R2,#-1 ;Don't set the x coord MOV R3,#-1 ;Don't set the y coord MOV R4,#-1 ;Don't set the height SWI Wimp_SetCaretPosition ;Put the caret in its place ; --- Return nicely --- 20dm_setField ADD R13,R13,#40 ;Reclaim that temporary space LDMFD R13!,{R0-R5,PC}^ ;Return to caller LTORG ; --- dm_checkFile --- ; ; On entry: R1 == pointer to message block ; On exit: R0 == 0 if it *wasn't* a DLL folder dm_checkFile ROUT STMFD R13!,{R1-R5,R14} ;Stack registers ; --- Ensure it's a directory --- ; ; Kysmet seems to ignore the fact that it might be an image ; and returns &FC0 for links, instead of &1000/&2000 which ; the Filer gives you. So we examine the file using OS_File ; and check bit 1 of the object type from that. ADD R1,R1,#44 ;Find the name MOV R0,#17 ;Try to read information SWI XOS_File ;Read the file information MOVVS R0,#0 ;Say not there if it failed TST R0,#2 ;Is it a directory? BEQ %10dm_checkFile ;No -- then complain ; --- Now find the leafname --- MOV R0,R1 ;Keep pointer to name 01dm_checkFile LDRB R14,[R1],#1 ;Get a character CMP R14,#'.' ;Is it a dot? MOVEQ R0,R1 ;Yes -- this it the leafname CMP R14,#' ' ;Is it the end? BGE %01dm_checkFile ;No -- go round again ; --- Compare this to what it should be --- ADR R1,dm__dlls ;Point to the ideal one MOV R2,#0 ;Not case-sensitive BL dm_strcmp ;Is it a match? BNE %10dm_checkFile ;No -- be unhappy MOV R0,#1 ;It was a real !DLLs resource LDMFD R13!,{R1-R5,PC}^ ;Return to caller 10dm_checkFile ADRL R0,msg_errNotDLL ;Point to error message LDR R1,[R13,#0] ;Get the message pointer ADD R1,R1,#44 ;Find the name string BL dm_error ;Fill in the error MOV R1,#1 ;Just an OK box please ADRL R2,dm__name ;Point to my name SWI Wimp_ReportError ;Report the error MOV R0,#0 ;It wasn't a real one LDMFD R13!,{R1-R5,PC}^ ;Return to caller dm__dlls DCB "!DLLs",0 LTORG ; --- dm_loadTemplate --- ; ; On entry: R0 == pointer to template ; R1 == 0 on first call, or R1 from previous ; On exit: R0 == window handle ; R1 == a new magic number dm_loadTemplate ROUT STMFD R13!,{R2-R5,R14} ;Stack registers ; --- Set up indirected data pointer --- CMP R1,#0 ;Is this the first call? ADREQL R2,dm_indspace ;Yes -- point to buff start MOVNE R2,R1 ;Set up indirected data ptr ; --- Load template into buffer --- ADRL R3,dm_eindspace ;Point to buff end ADR R1,dm_pollbk ;Point to poll block MOV R4,#1 ;Use the Wimp sprite area MOV R5,#1 ;I really mean that BL embTemp_extract ;Extract the template ; --- Create the window and return --- SWI Wimp_CreateWindow ;Create the window MOV R1,R2 ;Get magic number to return LDMFD R13!,{R2-R5,PC}^ ;Return to caller LTORG ; --- dm_strlen --- ; ; On entry: R0 == pointer to string ; On exit: R0 == length of string dm_strlen ROUT STMFD R13!,{R1,R14} ;Save some registers MOV R1,#0 ;Start the counter nicely 00dm_strlen LDRB R14,[R0],#1 ;Load a byte from the string ADD R1,R1,#1 ;Bump on the counter CMP R14,#32 ;Is it the end? BHS %00dm_strlen ;No -- go round again then SUB R0,R1,#1 ;Return count of actual chars LDMFD R13!,{R1,PC}^ ;Return to caller LTORG ; --- dm_strcpy --- ; ; On entry: R0 == destination string ; R1 == source string ; On exit: R0 == pointer to terminator of destination dm_strcpy ROUT STMFD R13!,{R1,R14} ;Keep return address safe 00dm_strcpy LDRB R14,[R1],#1 ;Get a byte from source CMP R14,#' ' ;Is it a control character MOVLT R14,#0 ;Yes -- translate to a 0 STRB R14,[R0],#1 ;Store in destination BGE %00dm_strcpy ;No -- copy another byte SUB R0,R0,#1 ;Point back at terminator LDMFD R13!,{R1,PC}^ ;Return to caller LTORG ; --- dm_strcmp --- ; ; On entry: R0 == pointer to string A ; R1 == pointer to string B ; R2 == 0 => case insensitive, 1 => case sensitive ; ; On exit: Flags as appropriate dm_strcmp ROUT STMFD R13!,{R0,R1,R3,R4,R14} 00dm_strcmp LDRB R3,[R0],#1 ;Get a character from A LDRB R4,[R1],#1 ;And one from B CMP R2,#0 ;Do we want to do case xlate? BNE %10dm_strcmp ;No -- miss it out then SUB R14,R3,#'a' ;Subtract the bottom limit CMP R14,#26 ;Is it a lower case letter? BICLO R3,R3,#&20 ;Yes -- convert to upper SUB R14,R4,#'a' ;Subtract the bottom limit CMP R14,#26 ;Is it a lower case letter? BICLO R4,R4,#&20 ;Yes -- convert to upper 10dm_strcmp CMP R3,#&20 ;Is that the end of A? MOVLO R3,#0 ;Yes -- pretend it's null CMP R4,#&20 ;Is that the end of B? MOVLO R4,#0 ;Yes -- pretend it's null CMP R3,R4 ;How do they match up? LDMNEFD R13!,{R0,R1,R3,R4,PC} ;If NE, return condition CMP R3,#0 ;Is this the end? BNE %00dm_strcmp ;No -- loop again LDMFD R13!,{R0,R1,R3,R4,PC} ;Return to caller LTORG ; --- dm_error --- ; ; On entry: R0 == Pointer to error message skeleton ; R1 == Filler 1 ; R2 == Filler 2 ; R3 == Filler 3 ; R4 == Filler 4 ; On exit: R0 == Pointer to constructed error in dm_errorbuf EXPORT dm_error dm_error ROUT STMFD R13!,{R1-R6,R14} ADR R5,dm_pollbk ;Point to error buffer LDR R14,[R0],#4 ;Read the error's number STR R14,[R5],#4 ;And store in the new buffer 00dm_error LDRB R14,[R0],#1 ;Get an input character CMP R14,#'%' ;Is it a '%' sign? BEQ %01dm_error ;Yes -- deal with it 02dm_error STRB R14,[R5],#1 ;Not special, so store it CMP R14,#0 ;Is it the end of input? BNE %00dm_error ;No -- get another one ADR R0,dm_pollbk ;Point to error start LDMFD R13!,{R1-R6,PC}^ ;And return to caller 01dm_error LDRB R14,[R0],#1 ;Get the next character SUB R14,R14,#'0' ;Convert to binary (0..3) CMP R14,#4 ;Is it in range? BCS %02dm_error ;No -- just ignore the '%' LDR R6,[R13,R14,LSL #2] ;Load appropriate register 03dm_error LDRB R14,[R6],#1 ;Get an input byte CMP R14,#&20 ;Is it the end of the string? BLT %00dm_error ;Yes -- read main string STRB R14,[R5],#1 ;No -- store it in output B %03dm_error ;... and get another one LTORG ;----- Workspace layout ----------------------------------------------------- ^ 0,R12 dm_wstart # 0 dm_exceptStack # 4 dm_windhand # 4 dm_infohand # 4 dm_flags # 4 dm_handlers # 36 dm_menuBk # dm_menuSize dm_QUIT EQU 1<<0 dm_DEST EQU 1<<1 dm_SOURCE EQU 1<<2 dm_DONE EQU 1<<3 dm_ERROR EQU 1<<4 dm_pollbk # 256 dm_dest # 256 dm_source # 256 dm_indspace # 384 dm_eindspace # 0 dm_stacklim # 288 dm_wend # 0 dm_wsize EQU dm_wend-dm_wstart ;----- That's all folks ----------------------------------------------------- END