Showing changes from revision #1 to #2:
Added | Removed | Changed
Given the syntax Syntax string: String:"number=times/E,file/K/A,expand/S"
then the following input Input strings Strings will all match:
"-n 10 -file myfile"
"-times 1+7 -file myfile -expand"
"-file myfile -e"
However these input Input strings Strings will not:
"myfile -number 4"
this is because the keyword "-file"
has is the missing, /K qualifier and so must be specified, and
"-number 20 -times 4 -file myfile"
this is because the first keyword has been specified twice; once by its identifier "-number"
and again by it’s alias "-times"
.
So let’s say you’re writing a program “MyProgram” in C, and it accepts 2 parameters on the command line: an input filename and an output filename.
For OS_ReadArgs to process the command line you can set the Syntax String to 3 empty keywords: “,,” which says to OS_ReadArgs expect to process 3 parameters.
Thus the command line: MyProgram FileIn FileOut
will be in the Output Buffer as:
+0 points to 0-terminated string “MyProgram”
+4 points to 0-terminated string “FileIn”
+8 points to 0-terminated string “FileOut”
So what OS_ReadArgs is doing is reading the first part of the command line (ie program name “MyProgram”) and seeing if it has a match in the Syntax String. It doesn’t so it puts it in the first unused location in the Output Buffer (at +0).
It reads the next part (“FileIn”), no match and so puts it in the next unused location (at +4).
And then the final part (“FileOut”), again no match and so into the next unused location (at +8).
Which is why the command line: MyProgram FileOut FileIn
will be in the Output Buffer as:
+0 points to 0-terminated string “MyProgram”
+4 points to 0-terminated string “FileOut”
+8 points to 0-terminated string “FileIn”
And if your program assumes that the input filename will always be at +4 and the output filename will always be at +8 in the Output Buffer then you could be in trouble!
And so what keywords enable you to do is to make sure that the Output Buffer has the parameters in the positions you want them in.
So if we want the input filename to always be at +4 and the output filename to always be at +8 then we set the Syntax String to be: “,input,output”. The program name is still an empty keyword.
That way the user can then specify MyProgram -input FileIn -output FileOut
or MyProgram -output FileOut -input FileIn
, it matters not because OS_ReadArgs will put the input filename FileIn at +4 and the output at +8 because that’s what the Syntax String says.
And it puts the program name at +0 because that just happens to be the first unused location.
The Syntax String is saying to OS_ReadArgs, I want this parameter to be at this location in the Output Buffer.
So if you want the output filename to always be at +0, the input filename to always be at +4 and the program name to always be at +8 then you would set the Syntax String to “output,input,”.
And so as ReadArgs processes the command line, it will read the program name, it has no match in the Syntax String and so it would go in the first unused location which in this case is +8 in the Output Buffer.
It will then read the -output which matches a keyword and put the next parameter “FileOut” to its location at +0.
It will then read the -input which again matches a keyword and puts the next parameter “FileIn” to its location at +4.
And the Output Buffer will be:
+0 points to 0-terminated string “FileOut”
+4 points to 0-terminated string “FileIn”
+8 points to 0-terminated string “MyProgram”
The problem will come if you use that Syntax String and the user types on the command line: MyProgram FileIn FileOut
because it wont fill in the Output Buffer as above (the keywords -input and -output are currently optional), which is where the keyword qualifiers come in.
To force the user to specify the -input and -output on the command line you use the /K qualifier against the relevant keyword, in this case: “output/K,input/K,”.
Now if the user types: MyProgram FileIn FileOut
it will cause an error because they must specify -input and -output.
But they could still type: MyProgram -input FileIn
without specifying an output file because whilst the keyword must be specified the parameter (keyword and value) is still optional. So let’s say you can take input from the keyboard but the output must be to a file, so to make input optional on the command line but output mandatory you would set the Syntax String to be: “output/A/K,input/K,”.
That way if they type: MyProgram -input FileIn
they will get an error, but if they type: MyProgram -output FileOut
it will work just fine with the Output Buffer being:
+0 points to 0-terminated string “FileOut”
+4 = 0
+8 points to 0-terminated string “MyProgram”
As will MyProgram -input FileIn -output FileOut
, and the Output Buffer will be as you expect:
+0 points to 0-terminated string “FileOut”
+4 points to 0-terminated string “FileIn”
+8 points to 0-terminated string “MyProgram”
If you wanted the output to be GSTrans’d but not the input, then you would use: “output/A/K/G,input/K,”.
The Output Buffer will then be:
+0 points to GSTrans’d string: 2 bytes length (=7) followed by “FileOut” (no terminator)
+4 points to 0-terminated string “FileIn”
+8 points to 0-terminated string “MyProgram”
If just the input then: “output/A/K,input/K/G,” or if both, then: “output/A/K/G,input/K/G,”.
But with BASIC programs the parameters BASIC -quit
are added to the start of the command line. Without changing the Syntax String this will cause an error, and so “,quit/S” is usually added at the start of the Syntax String to ensure that BASIC -quit
gets handled without causing an error.
But if we have the keyword “quit/S” at the start of the Syntax String then it will cause a conflict with any other keyword beginning with “q”, such as “quiet/S” and if “-q” is specified on the command line it will be matched to the “quit/S” keyword first rather than “quiet/S” which is probably not what you want.
One way round this is to specify “q” as an alias to “quiet”, ie “quiet=q/S”.
The other way is to put the “quit/S” keyword at the end of the Syntax String ensuring that the “quiet/S” comes before it.
And so to keep FileOut and FileIn at +0 and +4 in the Output Buffer, the Syntax String needs to be amended to be: “output/A/K,input/K,quiet/S,,,quit/S”
The Output Buffer will then be:
+0 points to 0-terminated string “FileOut”
+4 points to 0-terminated string “FileIn”
+8 = 0 if -quiet is not specified on the command or = a non-zero value if it is
+12 points to 0-terminated string “BASIC”
+16 points to 0-terminated string “MyProgram”
+20 = A non-zero value to match -quit
You’ll notice that the name of our program “MyProgram” has moved to +16 and that “BASIC” is now at +12, and the -quit switch is at +20.
Another possible way to deal with BASIC -quit
is to not treat “-quit” as a switch. Whilst this wont solve the -quiet/-quit clash over -q but it will reduce the number of locations in the Output Buffer by one.
So the Syntax String: “output/A/K,input/K,quiet/S,,quit” will result in an Output Buffer of:
+0 points to 0-terminated string “FileOut”
+4 points to 0-terminated string “FileIn”
+8 = 0 if -quiet is not specified on the command or = a non-zero value if it is
+12 points to 0-terminated string “BASIC”
+16 points to 0-terminated string “MyProgram”
The following code puts all this into a BASIC procedure that shows how to read each parameter. This uses DIM LOCAL
so will only work under RISC OS 5. For it to work on earlier versions replace the DIM buffer% LOCAL buf_size%-1
with either DIM buffer% buf_size%-1
or another way of claiming some memory.
The global variable argc% will = 0 if no parameters specified, or if -help was specified, or there was an error parsing the parameters.
You will notice that the Syntax String starts “,quit,help/S” rather than have “quit” at the end. I have done it this way as it seems more natural to have the parameters in the order they would be on the command line. But as has already been demonstrated above, you can put the keywords in any order you like.
I’ve included “help” as it’s a good idea for programs to respond to “-help” on the command line. And because the “quit” keyword has moved we must change “quiet/S” to “quiet=q/S” to force “-q” to match “-quiet” rather than “-quit”.
The program will store the program name, input and output file specs in the array arg$(), whilst -quiet will set a flag quiet% and -number will store the number in the variable number%. Then either a syntax message is displayed or the results of the parameters that have been specified on the command line.
REM>MyReadArgs REM PROCreadArgs IF argc% = 0 THEN REM Either no parameters specified or there was an error in parsing them REM Either way tell the user what the syntax for this program is PRINT "Syntax: MyReadArgs [-input <file spec>] -output <file spec> [-quiet] [-number N]" PRINT " where N is between 1 and 99" END ENDIF PRINT "Program: '";arg$(0);"' called with parameters:" PRINT "-input: '";arg$(1);"'" PRINT "-output: '";arg$(2);"'" PRINT "-quiet set? ";:IF quiet% THEN PRINT "Yes" ELSE PRINT "No" PRINT "-number = ";number% END DEF PROCreadArgs REM Read and process command line arguments LOCAL i%, cmd%, syntax$, flags%, buffer%, buf_size% REM Set default values argc% = 0 quiet% = FALSE : REM Will be TRUE if -quiet is specified on the command line number% = 0 : REM Will store the number N if specified on the command line, else defaults to 0 buf_size% = 1024 : REM Max size of command line DIM buffer% LOCAL buf_size%-1 : REM RISC OS 5 only REM Syntax: MyReadArgs [-input <file spec>] -output <file spec> [-quiet] [-number N] syntax$ = ",quit,help/S,input/K/G,output/A/K/G,quiet=q/S,number/E/K" REM The Output Buffer will be: REM +0 = "BASIC" (which we ignore) REM +4 = "MyReadArgs" - will be GSTrans'd for us, so no need to specify /G REM +8 = non-zero if -help specified REM +12 = input file spec (GSTrans'd) REM +16 = output file spec (GSTrans'd) REM +20 = non-zero if -quiet if specified REM +24 = pointer to -number N if specified SYS "OS_GetEnv" TO cmd% SYS "XOS_ReadArgs",syntax$,cmd%,buffer%,buf_size% TO ;flags% IF ((flags% AND 1) = 1) THEN ENDPROC REM If -help specified then exit with argc% = 0 so we get the syntax message displayed otherwise get the file specs IF buffer%!8 <> 0 THEN argc% = 0 ELSE argc% = 2 DIM arg$(argc%) SYS "XOS_GenerateError",buffer%!4 TO arg$(0) : REM Get the program name (zero-terminated string) REM In theory the program name could be greater than 255 characters - in which case arg$(0) will be of length 0 REM And we know it can't be an empty string as we're in the middle of running the program! IF LEN(arg$(0)) = 0 THEN ERROR 19, "String too long for program name" IF argc% THEN REM GSTrans'd input file spec stored as 2 byte length followed by non-terminated string cmd% = buffer%!12 : REM Optional, so if not specified then buffer%!12 = 0 and arg$(1) will = "" IF cmd% <> 0 THEN REM Check that an empty string "" hasn't been specified on the command line REM Also in theory the filename could be longer than 255 characters i% = ?cmd% + ((cmd%?1)*256) IF (i% > 0) AND (i% < 256) THEN FOR i% = 2 TO (?cmd% + ((cmd%?1)*256) + 1) : arg$(1) += CHR$(cmd%?i%) : NEXT ELSE IF i% > 255 THEN ERROR 19, "String too long for input filename" ENDIF ENDIF REM GSTrans'd output file spec stored as 2 byte length followed by non-terminated string cmd% = buffer%!16 : REM Mandatory, so if not specified then OS_ReadArgs will error REM But we do need to check that an empty string "" hasn't been specified on the command line REM And in theory the filename could be longer than 255 characters i% = ?cmd% + ((cmd%?1)*256) IF i% = 0 THEN argc% = 0 ELSE IF (i% > 0) AND (i% < 256) THEN FOR i% = 2 TO (?cmd% + ((cmd%?1)*256) + 1) : arg$(2) += CHR$(cmd%?i%) : NEXT ELSE ERROR 19, "String too long for output filename" ENDIF ENDIF quiet% = (buffer%!20 <> 0) : REM TRUE if -quiet cmd% = buffer%!24 : REM Evaluated expression (-number N) stored as 1 byte type followed by 4 bytes of integer if type = 0 IF cmd% <> 0 THEN REM -number specified on command line IF ?cmd% = 0 THEN number% = cmd%!1 ELSE argc% = 0 : REM If type is not a number (<>0) then we wont accept it IF (number% < 0) OR (number% > 99) THEN argc% = 0 : REM N must be in range 1..99 but we don't flag 0 as an error ENDIF ENDIF ENDPROC