chiark / gitweb /
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