Initial revision
[ssr] / StraySrc / Utilities / s / test
1 ;
2 ; test.s
3 ;
4 ; Tests a condition
5 ;
6 ; © 1995-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's core utilities (coreutils).
12 ;
13 ; Coreutils is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
16 ; any later version.
17 ;
18 ; Coreutils is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ; GNU General Public License for more details.
22 ;
23 ; You should have received a copy of the GNU General Public License
24 ; along with Coreutils. If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27 ;----- Standard header ------------------------------------------------------
28
29 GET libs:header
30 GET libs:swis
31
32 GET libs:stream
33
34 ;----- External dependencies ------------------------------------------------
35
36 IMPORT version
37
38 ;----- Main code ------------------------------------------------------------
39
40 AREA |!!!Utility$$Code|,CODE,READONLY
41
42 ; --- main ---
43 ;
44 ; On entry: R0 == pointer to command string
45 ; R1 == pointer to command tail
46 ;
47 ; On exit: May return an error
48 ;
49 ; Use: Performs a test, and does things appropriately.
50
51 main ROUT
52
53 STR R14,test_return ;Save the return address
54
55 ; --- Read the command line arguments ---
56
57 ADR R0,test_syntaxDef ;Find the definitions
58 ADR R2,test_args ;Point to argument buffer
59 MOV R3,#252 ;Get the buffer size
60 SWI XOS_ReadArgs ;Read the arguments
61 BVS test_error ;If it failed, return now
62
63 ; --- Check for some easy cases ---
64
65 LDR R14,tArg_help ;Load the help switch
66 CMP R14,#0 ;Is it enabled?
67 BNE test_help ;Yes -- give some help then
68
69 ; --- Sort out the test ---
70
71 ADR R0,tArg_file ;Point to file arg
72 ADR R1,tArg_exists ;And to the limit
73 BL test_which ;Which one is set?
74 ADRCC R0,test_noTest ;None -- point to error
75 BCC test_error ;And complain then
76 MOV R2,R0 ;Look after this
77
78 ADR R0,tArg_exists ;Point to file qualifiers
79 ADR R1,tArg_limit ;And to the very end
80 BL test_which ;Which one is set?
81 CMP R2,#0 ;Is this a file?
82 CMPNE R0,#-1 ;No -- make sure no quals
83 ADRNE R0,test_badQuals ;If there are, find error
84 BNE test_error ;And complain
85 MOV R10,R0 ;Look after this
86
87 ; --- Dispatch the test ---
88
89 MOV R14,PC ;Set up return address
90 ADD PC,PC,R2,LSL #2 ;Dispatch
91 B %f00 ;And continue when done
92
93 B test_file ;Handle a file test
94 B test_expr ;Handle an expression test
95 B test_key ;Handle a key test
96 B test_riscOs ;Handle an OS version test
97 B test_command ;Handle a command test
98 B test_true ;Handle a true test
99 B test_false ;Handle a false test
100
101 ; --- Now handle the results ---
102
103 00 LDR R14,tArg_multiLine ;Is this a multiline?
104 CMP R14,#0 ;Is the switch there?
105 BNE %50main ;Yes -- handle that then
106 CMP R0,#0 ;Was the condition true?
107 LDRNE R0,tArg_then ;Yes -- find then clause
108 LDREQ R0,tArg_else ;No -- find else clause
109 CMP R0,#0 ;Is the clause defined?
110 SWINE XOS_CLI ;Yes -- do it then
111 BVS test_error ;If it failed, die horribly
112 B test_end ;Otherwise end nicely
113
114 ; --- Deal with a multiline ---
115
116 50 CMP R0,#0 ;Did the test succeed?
117 ADR R0,test_uScore ;Point to variable name
118 ADRNE R1,test_vTrue ;Yes -- use true value
119 ADREQ R1,test_vFalse ;No -- use false value
120 BL test_setVar ;Set that up
121
122 ADR R0,test_else ;Point to variable name
123 ADRNE R1,test_eTrue ;Yes -- use true value
124 ADREQ R1,test_eFalse ;No -- use false value
125 BL test_setVar ;Set that up
126
127 ADR R0,test_endif ;Point to variable name
128 ADR R1,test_endVal ;Point to value
129 BL test_setVar ;Set that up
130 B test_end ;And return when done
131
132 test_uScore DCB "Alias$_",0
133 test_vTrue DCB "%*0",0
134 test_vFalse DCB "||",0
135 test_else DCB "Alias$Else",0
136 test_eTrue DCB "Set Alias$_ ||||",0
137 test_eFalse DCB "Set Alias$_ %%*0",0
138 test_endif DCB "Alias$EndIf",0
139 test_endVal DCB "Unset Alias$_|mUnset Alias$Else|m"
140 DCB "Unset Alias$EndIf",0
141
142 test_noTest DCD 1
143 DCB "No condition to test",0
144
145 test_badQuals DCD 1
146 DCB "File qualifier found, but not -file test",0
147 ALIGN
148
149 test_syntaxDef DCB "help/s,"
150
151 DCB "then/k,"
152 DCB "else/k,"
153 DCB "multiline/s,"
154
155 DCB "file/k,"
156 DCB "expr/e/k,"
157 DCB "key/e/k,"
158 DCB "riscOs/k,"
159 DCB "command/k,"
160 DCB "true/s,"
161 DCB "false/s,"
162
163 DCB "exists/s,"
164 DCB "isDir/s,"
165 DCB "isFile/s,"
166 DCB "isType/k",0
167
168 LTORG
169
170 ; --- test_which ---
171 ;
172 ; On entry: R0 == pointer to base argument
173 ; R1 == pointer to limit argument
174 ;
175 ; On exit: CS if an argument matched, and
176 ; R0 == index of argument chosen
177 ; else CC and
178 ; R0 == -1
179 ;
180 ; Use: Works out which argument in a collection is actually chosen.
181 ; an error is raised if more than one is chosen.
182
183 test_which ROUT
184
185 STMFD R13!,{R1-R3,R14} ;Save some registers
186 MOV R2,R0 ;Look after base pointer
187 MOV R0,#-1 ;Initially, we have no choice
188 MOV R3,#-1 ;Initialise a counter
189 00 ADD R3,R3,#1 ;Increment the counter
190 CMP R2,R1 ;Finished scanning?
191 BEQ %10test_which ;Yes -- deal with that
192 LDR R14,[R2],#4 ;Load the argument
193 CMP R14,#0 ;Is this one enabled?
194 BEQ %b00 ;No -- ignore it then
195 CMP R0,#-1 ;Do we have a choice yet?
196 MOVEQ R0,R3 ;No -- we do now
197 BEQ %b00 ;So skip back again
198
199 ADR R0,test_badRadio ;Point to the error
200 B test_error ;And report it
201
202 10test_which CMP R0,#-1 ;Did we get an answer?
203 LDMFD R13!,{R1-R3,R14} ;Restore registers
204 ORRNES PC,R14,#C_flag ;Yes -- return C set
205 BICEQS PC,R14,#C_flag ;No -- return C clear
206
207 test_badRadio DCD 1
208 DCB "Bad options",0
209
210 LTORG
211
212 ; --- test_help ---
213 ;
214 ; On entry: --
215 ;
216 ; On exit: Doesn't
217 ;
218 ; Use: Gives the user some help.
219
220 test_help ROUT
221
222 ADR R0,test_helpText ;Point to the help text
223 MOV R1,#0 ;Use the system dictionary
224 LDR R2,=version ;Find the version string
225 ADRL R14,main ;Point to the utility base
226 ADD R2,R14,R2 ;Relocate the pointer
227 SWI XOS_PrettyPrint ;Write the text out
228 B test_end ;And finish the program
229
230 test_helpText DCB "test ",27,0,13
231 DCB 13
232 DCB "Syntax: test <condition> <target>",13
233 DCB 13
234 DCB "Tests a condition and then performs an operation "
235 DCB "based on the result. Possible targets are:",13
236 DCB 13
237 DCB "[-then <command>] [-else <command>]",13
238 DCB "-multiline",13
239 DCB 13
240 DCB "-then ... -else ... works as expected. "
241 DCB "-multiline defines a collection of alias "
242 DCB "commands, as follows:",13
243 DCB 13
244 DCB "_",9,9,"prefix normal commands with this",13
245 DCB "else",9,9,"toggles whether `_' executes commands",13
246 DCB "endif",9,9,"undefines `_', `else' and `endif'",13
247 DCB 13
248 DCB "Permitted tests are:",13
249 DCB 13
250 DCB "-file <file> <qualifier>",13
251 DCB "-expr <expression>",13
252 DCB "-key <key number>",13
253 DCB "-riscos <version number>",13
254 DCB "-command <*command>",13
255 DCB "-true | -false",13
256 DCB 13
257 DCB "The file qualifiers test various things about a "
258 DCB "file:",13
259 DCB 13
260 DCB "-exists",9,9,"Ensure the file exists",13
261 DCB "-isDir",9,9,"Ensure it's a directory",13
262 DCB "-isFile",9,9,"Ensure it's a file",13
263 DCB "-isType <type>",9,"Ensure it's a file of given "
264 DCB "type",13
265 DCB 13
266 DCB "Key numbers are given either as internal key "
267 DCB "numbers (see sapphire:intKeys for bindings) or as "
268 DCB "BASIC-style -ve INKEY numbers",13
269 DCB 13
270 DCB "The -riscos test ensures that the current version "
271 DCB "of the OS is the same or later than that given.",13
272 DCB 13
273 DCB "The -command test runs a command and ensures that "
274 DCB "it didn't return an error. This may be useful "
275 DCB "just to suppress the error.",13
276 DCB 0
277
278 LTORG
279
280 ; --- test_file ---
281 ;
282 ; On entry: R10 == reason code
283 ;
284 ; On exit: R0 == 0 if false, non-0 if true
285 ; R1-R11 corrupted
286 ;
287 ; Use: Performs a file operation and returns its truth.
288
289 test_file ROUT
290
291 ; --- Find the file information ---
292
293 MOV R0,#17 ;Read file information
294 LDR R1,tArg_file ;Get the filename
295 SWI XOS_File ;Try to get this information
296 MOVVS R0,#0 ;If failed, say not there
297 CMP R10,#0 ;Just checking existance?
298 CMPNE R0,#0 ;Or is the file not there?
299 MOVEQS PC,R14 ;Yes -- return now
300
301 CMP R10,#-1 ;Was one chosen?
302 ADDNE PC,PC,R10,LSL #2 ;Yes -- dispatch it
303 MOVS PC,R14 ;No op -- assume existance
304
305 MOVS PC,R14 ;Dealt with this already
306 B test_fDir ;Check it's a directory
307 B test_fFile ;Check it's a file
308 B test_fType ;Check its type
309
310 test_fDir AND R0,R0,#2 ;Leave only the dir bit
311 MOVS PC,R14 ;And return
312
313 test_fFile AND R0,R0,#1 ;Leave only the file bit
314 MOVS PC,R14 ;And return
315
316 test_fType ANDS R0,R0,#1 ;Test the file bit
317 MOVEQS PC,R14 ;If clear, skip on
318 MOV R3,R2,LSL #12 ;Look after the filetype
319 MOV R0,#31 ;Convert filetype name
320 LDR R1,tArg_isType ;Find the type string
321 SWI XOS_FSControl ;Try to convert it
322 BVS test_error ;Fail if we couldn't
323 CMP R2,R3,LSR #20 ;Compare the filetypes
324 MOVEQ R0,#1 ;If match, say true
325 MOVNE R0,#0 ;Otherwise say false
326 MOVS PC,R14 ;And return
327
328 LTORG
329
330 ; --- test_expr ---
331 ;
332 ; On entry: --
333 ;
334 ; On exit: R0 == 0 if false, non-0 if true
335 ; R1-R11 corrupted
336 ;
337 ; Use: Evaluates an expression and returns the result.
338
339 test_expr ROUT
340
341 LDR R0,tArg_expr ;Find the expression result
342 B test_getValue ;Read the value
343
344 LTORG
345
346 ; --- test_key ---
347 ;
348 ; On entry: --
349 ;
350 ; On exit: R0 == 0 if false, non-0 if true
351 ; R1-R11 corrupted
352 ;
353 ; Use: Tests a key on the keyboard.
354
355 test_key STMFD R13!,{R14} ;Save the link register
356 LDR R0,tArg_key ;Find the expression result
357 BL test_getValue ;Find the value
358 TST R0,#&80000000 ;Is the result negative?
359 EOREQ R0,R0,#&FF ;No -- then do that then
360 MOV R2,#&FF ;Scan for the key
361 AND R1,R0,#&FF ;Only have lowest byte
362 MOV R0,#&81 ;Get the OS_Byte code
363 SWI XOS_Byte ;Read the key pressedness
364 BVS test_error ;If it failed, return error
365 MOV R0,R1 ;Get the result
366 LDMFD R13!,{PC}^ ;And return
367
368 LTORG
369
370 ; --- test_riscOs ---
371 ;
372 ; On entry: --
373 ;
374 ; On exit: R0 == 0 if false, and non-0 if true
375 ; R1-R11 corrupted
376 ;
377 ; Use: Returns the result of testing the OS version.
378
379 test_riscOs ROUT
380
381 STMFD R13!,{R14} ;Save a register
382 LDR R0,tArg_riscOs ;Find the version string
383 BL test_getVersion ;Translate it for me
384 MOV R3,R0 ;Look after this result
385
386 MOV R0,#129 ;Read the OS version
387 MOV R1,#0 ;Want the OS version
388 MOV R2,#255 ;Still want it, dammit
389 SWI XOS_Byte ;Try to read it then
390 BVS test_error ;If it failed, report error
391
392 ADR R2,test_verTable ;Point to version table
393 MOV R0,#-1 ;Start off with bad value
394 00 LDMIA R2!,{R4,R5} ;Load the values out
395 CMP R4,R1 ;Does this version match?
396 MOVLE R0,R5 ;Yes -- use it then
397 BGT %b00 ;Otherwise loop back
398
399 CMP R0,R3 ;Compare with his version
400 MOVGE R0,#1 ;If later or same, return ok
401 MOVLT R0,#0 ;Otherwise return false
402 LDMFD R13!,{PC}^ ;And return to caller
403
404 test_verTable DCD &A5,350
405 DCD &A4,310
406 DCD &A3,300
407 DCD &A2,201
408 DCD &A1,200
409 DCD &A0,120
410 DCD 0,0
411
412 LTORG
413
414 ; --- test_command ---
415 ;
416 ; On entry: --
417 ;
418 ; On exit: R0 == 0 if false, non-0 if true
419 ;
420 ; Use: Runs a command, and returns true if the command didn't
421 ; make an error.
422
423 test_command ROUT
424
425 LDR R0,tArg_command ;Load the command string
426 SWI XOS_CLI ;Run the command
427 MOVVC R0,#1 ;If OK, return true
428 MOVVS R0,#0 ;Otherwise return false
429 MOVS PC,R14 ;And return to caller
430
431 LTORG
432
433 ; --- test_true and test_false ---
434 ;
435 ; On entry: --
436 ;
437 ; On exit: R0 == 0 if false, non-0 if true
438 ; R1-R11 corrupted
439 ;
440 ; Use: Return particular values.
441
442 test_true MOV R0,#1 ;Return true
443 MOVS PC,R14 ;And return
444
445 test_false MOV R0,#0 ;Return false
446 MOVS PC,R14 ;And return
447
448 LTORG
449
450 ; --- test_getValue ---
451 ;
452 ; On entry: R0 == pointer to expression result
453 ;
454 ; On exit: R0 == value read
455 ;
456 ; Use: Reads the value of an expression from the OS_ReadArgs block.
457
458 test_getValue ROUT
459
460 STMFD R13!,{R1,R2,R14} ;Save some registers
461 LDRB R14,[R0],#1 ;Load the first byte
462 CMP R14,#0 ;Is this an integer?
463 ADRNE R0,test_notAnInt ;No -- then find error
464 BNE test_error ;And complain
465 AND R2,R0,#3 ;Find non-alignedness
466 BIC R0,R0,#3 ;Round down a little
467 LDMIA R0,{R0,R1} ;Load the value out
468 MOV R2,R2,LSL #3 ;Convert bits to bytes
469 RSB R14,R2,#32 ;And find the other shift
470 MOV R0,R0,LSR R2 ;Get the lower bits
471 ORR R0,R0,R1,LSL R14 ;And the upper bits
472 LDMFD R13!,{R1,R2,PC}^ ;And return to caller
473
474 test_notAnInt DCD 1
475 DCB "Integer expected",0
476
477 LTORG
478
479 ; --- test_getVersion ---
480 ;
481 ; On entry: R0 == pointer to version string
482 ;
483 ; On exit: R0 == value of version number-
484 ;
485 ; Use: Reads a version umber
486
487 test_getVersion ROUT
488
489 STMFD R13!,{R1,R2,R14} ;Save some registers
490 MOV R2,#0 ;Clear version accumulator
491
492 00 LDRB R1,[R0],#1 ;Load next byte from thing
493 SUB R14,R1,#'0' ;Convert digit to integer
494 CMP R14,#10 ;Is it in range?
495 ADDCC R2,R2,R2,LSL #2 ;Yes -- accumulate
496 ADDCC R2,R14,R2,LSL #1 ;Multiply by 10 and add
497 BCC %b00 ;And loop back round
498
499 ADD R2,R2,R2,LSL #2 ;Multiply version by 100
500 ADD R2,R2,R2,LSL #2
501 MOV R2,R2,LSL #2
502
503 CMP R1,#'.' ;Is the character a dot?
504 BNE %f00 ;No -- skip on then
505 LDRB R1,[R0],#1 ;Load next byte from thing
506 SUB R14,R1,#'0' ;Convert digit to integer
507 CMP R14,#10 ;Is it in range?
508 ADDCC R14,R14,R14,LSL #2 ;Yes -- accumulate
509 ADDCC R2,R2,R14,LSL #1 ;Do it the other way round
510 LDRCCB R1,[R0],#1 ;Load next byte from thing
511 SUB R14,R1,#'0' ;Convert digit to integer
512 CMP R14,#10 ;Is it in range?
513 ADDCC R2,R2,R14 ;Yes -- add that on
514 LDRCCB R1,[R0],#1 ;Load next byte from thing
515
516 00 CMP R1,#&20 ;Is this the very end?
517 ADRCS R0,test_badVer ;Point to error message
518 BCS test_error ;And complain bitterly
519 MOV R0,R2 ;Get the version number
520 LDMFD R13!,{R1,R2,PC}^ ;And return to caller
521
522 test_badVer DCD 1
523 DCB "Bad version number",0
524
525 LTORG
526
527 ; --- test_setVar ---
528 ;
529 ; On entry: R0 == variable name
530 ; R1 == pointer to value
531 ;
532 ; On exit: --
533 ;
534 ; Use: Sets the variable given to the given value.
535
536 test_setVar ROUT
537
538 STMFD R13!,{R0-R4,R14} ;Save some registers
539 MOV R2,R1 ;Point to the value
540 00 LDRB R14,[R2],#1 ;Load the next byte
541 CMP R14,#&20 ;Is this the end yet?
542 BCS %b00 ;No -- keep going
543 SUB R2,R2,R1 ;Find the string length
544 SUB R2,R2,#1 ;Don't count the terminator
545 MOV R3,#0 ;Start at the beginning
546 MOV R4,#0 ;Normal GS type variable
547 SWI XOS_SetVarVal ;Set the variable
548 BVS test_error ;If failed, abort
549 LDMFD R13!,{R0-R4,PC}^ ;And return to caller
550
551 LTORG
552
553 ; --- test_end ---
554 ;
555 ; On entry: --
556 ;
557 ; On exit: --
558 ;
559 ; Use: Returns to the operating system.
560
561 test_end ROUT
562
563 LDR R14,test_return ;Find the return address
564 BICS PC,R14,#V_flag ;And return with no error
565
566 LTORG
567
568 ; --- test_error ---
569 ;
570 ; On entry: R0 == pointer to error block
571 ;
572 ; On exit: --
573 ;
574 ; Use: Reports an error to the operating system.
575
576 test_error ROUT
577
578 LDR R14,test_return ;Find the return address
579 ORRS PC,R14,#V_flag ;And return the error
580
581 LTORG
582
583 ;----- Workspace ------------------------------------------------------------
584
585 ^ 0,R12
586 test_wStart # 0
587
588 test_return # 4 ;Return address
589
590 test_args # 0 ;Argument output buffer
591 tArg_help # 4 ;Help switch
592 tArg_then # 4 ;Then command
593 tArg_else # 4 ;Else command
594 tArg_multiLine # 4 ;Multiline switch
595 tArg_file # 4 ;File condition
596 tArg_expr # 4 ;Expression condition
597 tArg_key # 4 ;Key condition
598 tArg_riscOs # 4 ;OS version condition
599 tArg_command # 4 ;Run a *command
600 tArg_true # 4 ;True condition
601 tArg_false # 4 ;False condition
602 tArg_exists # 4 ;Exists filetest
603 tArg_isDir # 4 ;IsDir filetest
604 tArg_isFile # 4 ;IsFile filetest
605 tArg_isType # 4 ;IsType filetest
606 tArg_limit # 4 ;End of the arguments
607
608 test_buffer EQU test_wStart+256 ;Misc buffer for things
609
610 ;----- That's all, folks ----------------------------------------------------
611
612 END