; ; test.s ; ; Tests a condition ; ; © 1995-1998 Straylight ; ;----- Licensing note ------------------------------------------------------- ; ; This file is part of Straylight's core utilities (coreutils). ; ; Coreutils 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. ; ; Coreutils 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 Coreutils. If not, write to the Free Software Foundation, ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ;----- Standard header ------------------------------------------------------ GET libs:header GET libs:swis GET libs:stream ;----- External dependencies ------------------------------------------------ IMPORT version ;----- Main code ------------------------------------------------------------ AREA |!!!Utility$$Code|,CODE,READONLY ; --- main --- ; ; On entry: R0 == pointer to command string ; R1 == pointer to command tail ; ; On exit: May return an error ; ; Use: Performs a test, and does things appropriately. main ROUT STR R14,test_return ;Save the return address ; --- Read the command line arguments --- ADR R0,test_syntaxDef ;Find the definitions ADR R2,test_args ;Point to argument buffer MOV R3,#252 ;Get the buffer size SWI XOS_ReadArgs ;Read the arguments BVS test_error ;If it failed, return now ; --- Check for some easy cases --- LDR R14,tArg_help ;Load the help switch CMP R14,#0 ;Is it enabled? BNE test_help ;Yes -- give some help then ; --- Sort out the test --- ADR R0,tArg_file ;Point to file arg ADR R1,tArg_exists ;And to the limit BL test_which ;Which one is set? ADRCC R0,test_noTest ;None -- point to error BCC test_error ;And complain then MOV R2,R0 ;Look after this ADR R0,tArg_exists ;Point to file qualifiers ADR R1,tArg_limit ;And to the very end BL test_which ;Which one is set? CMP R2,#0 ;Is this a file? CMPNE R0,#-1 ;No -- make sure no quals ADRNE R0,test_badQuals ;If there are, find error BNE test_error ;And complain MOV R10,R0 ;Look after this ; --- Dispatch the test --- MOV R14,PC ;Set up return address ADD PC,PC,R2,LSL #2 ;Dispatch B %f00 ;And continue when done B test_file ;Handle a file test B test_expr ;Handle an expression test B test_key ;Handle a key test B test_riscOs ;Handle an OS version test B test_command ;Handle a command test B test_true ;Handle a true test B test_false ;Handle a false test ; --- Now handle the results --- 00 LDR R14,tArg_multiLine ;Is this a multiline? CMP R14,#0 ;Is the switch there? BNE %50main ;Yes -- handle that then CMP R0,#0 ;Was the condition true? LDRNE R0,tArg_then ;Yes -- find then clause LDREQ R0,tArg_else ;No -- find else clause CMP R0,#0 ;Is the clause defined? SWINE XOS_CLI ;Yes -- do it then BVS test_error ;If it failed, die horribly B test_end ;Otherwise end nicely ; --- Deal with a multiline --- 50 CMP R0,#0 ;Did the test succeed? ADR R0,test_uScore ;Point to variable name ADRNE R1,test_vTrue ;Yes -- use true value ADREQ R1,test_vFalse ;No -- use false value BL test_setVar ;Set that up ADR R0,test_else ;Point to variable name ADRNE R1,test_eTrue ;Yes -- use true value ADREQ R1,test_eFalse ;No -- use false value BL test_setVar ;Set that up ADR R0,test_endif ;Point to variable name ADR R1,test_endVal ;Point to value BL test_setVar ;Set that up B test_end ;And return when done test_uScore DCB "Alias$_",0 test_vTrue DCB "%*0",0 test_vFalse DCB "||",0 test_else DCB "Alias$Else",0 test_eTrue DCB "Set Alias$_ ||||",0 test_eFalse DCB "Set Alias$_ %%*0",0 test_endif DCB "Alias$EndIf",0 test_endVal DCB "Unset Alias$_|mUnset Alias$Else|m" DCB "Unset Alias$EndIf",0 test_noTest DCD 1 DCB "No condition to test",0 test_badQuals DCD 1 DCB "File qualifier found, but not -file test",0 ALIGN test_syntaxDef DCB "help/s," DCB "then/k," DCB "else/k," DCB "multiline/s," DCB "file/k," DCB "expr/e/k," DCB "key/e/k," DCB "riscOs/k," DCB "command/k," DCB "true/s," DCB "false/s," DCB "exists/s," DCB "isDir/s," DCB "isFile/s," DCB "isType/k",0 LTORG ; --- test_which --- ; ; On entry: R0 == pointer to base argument ; R1 == pointer to limit argument ; ; On exit: CS if an argument matched, and ; R0 == index of argument chosen ; else CC and ; R0 == -1 ; ; Use: Works out which argument in a collection is actually chosen. ; an error is raised if more than one is chosen. test_which ROUT STMFD R13!,{R1-R3,R14} ;Save some registers MOV R2,R0 ;Look after base pointer MOV R0,#-1 ;Initially, we have no choice MOV R3,#-1 ;Initialise a counter 00 ADD R3,R3,#1 ;Increment the counter CMP R2,R1 ;Finished scanning? BEQ %10test_which ;Yes -- deal with that LDR R14,[R2],#4 ;Load the argument CMP R14,#0 ;Is this one enabled? BEQ %b00 ;No -- ignore it then CMP R0,#-1 ;Do we have a choice yet? MOVEQ R0,R3 ;No -- we do now BEQ %b00 ;So skip back again ADR R0,test_badRadio ;Point to the error B test_error ;And report it 10test_which CMP R0,#-1 ;Did we get an answer? LDMFD R13!,{R1-R3,R14} ;Restore registers ORRNES PC,R14,#C_flag ;Yes -- return C set BICEQS PC,R14,#C_flag ;No -- return C clear test_badRadio DCD 1 DCB "Bad options",0 LTORG ; --- test_help --- ; ; On entry: -- ; ; On exit: Doesn't ; ; Use: Gives the user some help. test_help ROUT ADR R0,test_helpText ;Point to the help text MOV R1,#0 ;Use the system dictionary LDR R2,=version ;Find the version string ADRL R14,main ;Point to the utility base ADD R2,R14,R2 ;Relocate the pointer SWI XOS_PrettyPrint ;Write the text out B test_end ;And finish the program test_helpText DCB "test ",27,0,13 DCB 13 DCB "Syntax: test ",13 DCB 13 DCB "Tests a condition and then performs an operation " DCB "based on the result. Possible targets are:",13 DCB 13 DCB "[-then ] [-else ]",13 DCB "-multiline",13 DCB 13 DCB "-then ... -else ... works as expected. " DCB "-multiline defines a collection of alias " DCB "commands, as follows:",13 DCB 13 DCB "_",9,9,"prefix normal commands with this",13 DCB "else",9,9,"toggles whether `_' executes commands",13 DCB "endif",9,9,"undefines `_', `else' and `endif'",13 DCB 13 DCB "Permitted tests are:",13 DCB 13 DCB "-file ",13 DCB "-expr ",13 DCB "-key ",13 DCB "-riscos ",13 DCB "-command <*command>",13 DCB "-true | -false",13 DCB 13 DCB "The file qualifiers test various things about a " DCB "file:",13 DCB 13 DCB "-exists",9,9,"Ensure the file exists",13 DCB "-isDir",9,9,"Ensure it's a directory",13 DCB "-isFile",9,9,"Ensure it's a file",13 DCB "-isType ",9,"Ensure it's a file of given " DCB "type",13 DCB 13 DCB "Key numbers are given either as internal key " DCB "numbers (see sapphire:intKeys for bindings) or as " DCB "BASIC-style -ve INKEY numbers",13 DCB 13 DCB "The -riscos test ensures that the current version " DCB "of the OS is the same or later than that given.",13 DCB 13 DCB "The -command test runs a command and ensures that " DCB "it didn't return an error. This may be useful " DCB "just to suppress the error.",13 DCB 0 LTORG ; --- test_file --- ; ; On entry: R10 == reason code ; ; On exit: R0 == 0 if false, non-0 if true ; R1-R11 corrupted ; ; Use: Performs a file operation and returns its truth. test_file ROUT ; --- Find the file information --- MOV R0,#17 ;Read file information LDR R1,tArg_file ;Get the filename SWI XOS_File ;Try to get this information MOVVS R0,#0 ;If failed, say not there CMP R10,#0 ;Just checking existance? CMPNE R0,#0 ;Or is the file not there? MOVEQS PC,R14 ;Yes -- return now CMP R10,#-1 ;Was one chosen? ADDNE PC,PC,R10,LSL #2 ;Yes -- dispatch it MOVS PC,R14 ;No op -- assume existance MOVS PC,R14 ;Dealt with this already B test_fDir ;Check it's a directory B test_fFile ;Check it's a file B test_fType ;Check its type test_fDir AND R0,R0,#2 ;Leave only the dir bit MOVS PC,R14 ;And return test_fFile AND R0,R0,#1 ;Leave only the file bit MOVS PC,R14 ;And return test_fType ANDS R0,R0,#1 ;Test the file bit MOVEQS PC,R14 ;If clear, skip on MOV R3,R2,LSL #12 ;Look after the filetype MOV R0,#31 ;Convert filetype name LDR R1,tArg_isType ;Find the type string SWI XOS_FSControl ;Try to convert it BVS test_error ;Fail if we couldn't CMP R2,R3,LSR #20 ;Compare the filetypes MOVEQ R0,#1 ;If match, say true MOVNE R0,#0 ;Otherwise say false MOVS PC,R14 ;And return LTORG ; --- test_expr --- ; ; On entry: -- ; ; On exit: R0 == 0 if false, non-0 if true ; R1-R11 corrupted ; ; Use: Evaluates an expression and returns the result. test_expr ROUT LDR R0,tArg_expr ;Find the expression result B test_getValue ;Read the value LTORG ; --- test_key --- ; ; On entry: -- ; ; On exit: R0 == 0 if false, non-0 if true ; R1-R11 corrupted ; ; Use: Tests a key on the keyboard. test_key STMFD R13!,{R14} ;Save the link register LDR R0,tArg_key ;Find the expression result BL test_getValue ;Find the value TST R0,#&80000000 ;Is the result negative? EOREQ R0,R0,#&FF ;No -- then do that then MOV R2,#&FF ;Scan for the key AND R1,R0,#&FF ;Only have lowest byte MOV R0,#&81 ;Get the OS_Byte code SWI XOS_Byte ;Read the key pressedness BVS test_error ;If it failed, return error MOV R0,R1 ;Get the result LDMFD R13!,{PC}^ ;And return LTORG ; --- test_riscOs --- ; ; On entry: -- ; ; On exit: R0 == 0 if false, and non-0 if true ; R1-R11 corrupted ; ; Use: Returns the result of testing the OS version. test_riscOs ROUT STMFD R13!,{R14} ;Save a register LDR R0,tArg_riscOs ;Find the version string BL test_getVersion ;Translate it for me MOV R3,R0 ;Look after this result MOV R0,#129 ;Read the OS version MOV R1,#0 ;Want the OS version MOV R2,#255 ;Still want it, dammit SWI XOS_Byte ;Try to read it then BVS test_error ;If it failed, report error ADR R2,test_verTable ;Point to version table MOV R0,#-1 ;Start off with bad value 00 LDMIA R2!,{R4,R5} ;Load the values out CMP R4,R1 ;Does this version match? MOVLE R0,R5 ;Yes -- use it then BGT %b00 ;Otherwise loop back CMP R0,R3 ;Compare with his version MOVGE R0,#1 ;If later or same, return ok MOVLT R0,#0 ;Otherwise return false LDMFD R13!,{PC}^ ;And return to caller test_verTable DCD &A5,350 DCD &A4,310 DCD &A3,300 DCD &A2,201 DCD &A1,200 DCD &A0,120 DCD 0,0 LTORG ; --- test_command --- ; ; On entry: -- ; ; On exit: R0 == 0 if false, non-0 if true ; ; Use: Runs a command, and returns true if the command didn't ; make an error. test_command ROUT LDR R0,tArg_command ;Load the command string SWI XOS_CLI ;Run the command MOVVC R0,#1 ;If OK, return true MOVVS R0,#0 ;Otherwise return false MOVS PC,R14 ;And return to caller LTORG ; --- test_true and test_false --- ; ; On entry: -- ; ; On exit: R0 == 0 if false, non-0 if true ; R1-R11 corrupted ; ; Use: Return particular values. test_true MOV R0,#1 ;Return true MOVS PC,R14 ;And return test_false MOV R0,#0 ;Return false MOVS PC,R14 ;And return LTORG ; --- test_getValue --- ; ; On entry: R0 == pointer to expression result ; ; On exit: R0 == value read ; ; Use: Reads the value of an expression from the OS_ReadArgs block. test_getValue ROUT STMFD R13!,{R1,R2,R14} ;Save some registers LDRB R14,[R0],#1 ;Load the first byte CMP R14,#0 ;Is this an integer? ADRNE R0,test_notAnInt ;No -- then find error BNE test_error ;And complain AND R2,R0,#3 ;Find non-alignedness BIC R0,R0,#3 ;Round down a little LDMIA R0,{R0,R1} ;Load the value out MOV R2,R2,LSL #3 ;Convert bits to bytes RSB R14,R2,#32 ;And find the other shift MOV R0,R0,LSR R2 ;Get the lower bits ORR R0,R0,R1,LSL R14 ;And the upper bits LDMFD R13!,{R1,R2,PC}^ ;And return to caller test_notAnInt DCD 1 DCB "Integer expected",0 LTORG ; --- test_getVersion --- ; ; On entry: R0 == pointer to version string ; ; On exit: R0 == value of version number- ; ; Use: Reads a version umber test_getVersion ROUT STMFD R13!,{R1,R2,R14} ;Save some registers MOV R2,#0 ;Clear version accumulator 00 LDRB R1,[R0],#1 ;Load next byte from thing SUB R14,R1,#'0' ;Convert digit to integer CMP R14,#10 ;Is it in range? ADDCC R2,R2,R2,LSL #2 ;Yes -- accumulate ADDCC R2,R14,R2,LSL #1 ;Multiply by 10 and add BCC %b00 ;And loop back round ADD R2,R2,R2,LSL #2 ;Multiply version by 100 ADD R2,R2,R2,LSL #2 MOV R2,R2,LSL #2 CMP R1,#'.' ;Is the character a dot? BNE %f00 ;No -- skip on then LDRB R1,[R0],#1 ;Load next byte from thing SUB R14,R1,#'0' ;Convert digit to integer CMP R14,#10 ;Is it in range? ADDCC R14,R14,R14,LSL #2 ;Yes -- accumulate ADDCC R2,R2,R14,LSL #1 ;Do it the other way round LDRCCB R1,[R0],#1 ;Load next byte from thing SUB R14,R1,#'0' ;Convert digit to integer CMP R14,#10 ;Is it in range? ADDCC R2,R2,R14 ;Yes -- add that on LDRCCB R1,[R0],#1 ;Load next byte from thing 00 CMP R1,#&20 ;Is this the very end? ADRCS R0,test_badVer ;Point to error message BCS test_error ;And complain bitterly MOV R0,R2 ;Get the version number LDMFD R13!,{R1,R2,PC}^ ;And return to caller test_badVer DCD 1 DCB "Bad version number",0 LTORG ; --- test_setVar --- ; ; On entry: R0 == variable name ; R1 == pointer to value ; ; On exit: -- ; ; Use: Sets the variable given to the given value. test_setVar ROUT STMFD R13!,{R0-R4,R14} ;Save some registers MOV R2,R1 ;Point to the value 00 LDRB R14,[R2],#1 ;Load the next byte CMP R14,#&20 ;Is this the end yet? BCS %b00 ;No -- keep going SUB R2,R2,R1 ;Find the string length SUB R2,R2,#1 ;Don't count the terminator MOV R3,#0 ;Start at the beginning MOV R4,#0 ;Normal GS type variable SWI XOS_SetVarVal ;Set the variable BVS test_error ;If failed, abort LDMFD R13!,{R0-R4,PC}^ ;And return to caller LTORG ; --- test_end --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Returns to the operating system. test_end ROUT LDR R14,test_return ;Find the return address BICS PC,R14,#V_flag ;And return with no error LTORG ; --- test_error --- ; ; On entry: R0 == pointer to error block ; ; On exit: -- ; ; Use: Reports an error to the operating system. test_error ROUT LDR R14,test_return ;Find the return address ORRS PC,R14,#V_flag ;And return the error LTORG ;----- Workspace ------------------------------------------------------------ ^ 0,R12 test_wStart # 0 test_return # 4 ;Return address test_args # 0 ;Argument output buffer tArg_help # 4 ;Help switch tArg_then # 4 ;Then command tArg_else # 4 ;Else command tArg_multiLine # 4 ;Multiline switch tArg_file # 4 ;File condition tArg_expr # 4 ;Expression condition tArg_key # 4 ;Key condition tArg_riscOs # 4 ;OS version condition tArg_command # 4 ;Run a *command tArg_true # 4 ;True condition tArg_false # 4 ;False condition tArg_exists # 4 ;Exists filetest tArg_isDir # 4 ;IsDir filetest tArg_isFile # 4 ;IsFile filetest tArg_isType # 4 ;IsType filetest tArg_limit # 4 ;End of the arguments test_buffer EQU test_wStart+256 ;Misc buffer for things ;----- That's all, folks ---------------------------------------------------- END