www.riscos.com Technical Support: |
|
There are two ways in which you can interact with the OS and the various modules which provide extensions to it. The first way is to call one of the many SWI routines provided, such as OS_Byte, OS_ReadMonotonicTime, Wimp_Initialise etc. The SWI interface provides an efficient calling mechanism for use within programs in any language.
However, for users wishing to issue commands to the operating system, the SWI interface is not so convenient. As it is difficult to remember SWI names, reason codes, register contents on entry and exit, etc, the command line interpreter (CLI) interface is often used. Using this technique, you enter a textual command string, possibly followed by parameters, which is then passed by the application to the OS. The OS tries to decode the command and carry out the appropriate action. If the command is not recognised by the OS, the other modules in the system try to execute the command instead.
The CLI interface is a powerful one because the OS performs a certain amount of pre-processing on the line before it attempts to interpret it. For example, variable names may be substituted in the parameter part of the line, and command aliases may be used.
By convention, an application passes commands to the OS if they are prefixed by the * character. For example, from the BASIC '>' prompt, any OS command may be issued simply by making * the first non-space character on the line. The * is not part of the command; the OS, in fact, strips any leading *s and spaces from a command before it tries to decode it.
Some languages also provide built-in statements which can be used to perform an OS command. Again, BASIC provides the OSCLI statement, which evaluates a string expression and passes this to the OS command line interpreter. The 'C' language provides the system() function for the same purpose.
A program can call the CLI using the SWI OS_CLI. This simply passes a string from the program to the CLI to be interpreted. If you wish to allow the user to type a number of CLI commands, then you can pass 'GOS' (see *GOS) as the string to OS_CLI. See the chapter entitled Program Environment, for information on how to set up RISC OS to return to your program when the user types *Quit.
When a CLI command is received by the kernel, it performs a number of operations upon it. Note that in most cases, the case of commands is ignored. Only if you are creating something with a name is the case kept. The sections below go through each of these.
Certain leading characters will be treated in a special way:
'*' | all leading stars are discarded |
' ' | all leading spaces are discarded |
'|' | this indicates that the line is a comment, and will be ignored |
'/' | treat the rest of the command as if it had been prefixed with *Run |
'%' | skip alias checking. |
'-' | override current filing system name: eg -adfs- |
'.' | check for Alias$. and use *Cat if it doesn't exist |
Apart from '%' and '-', the above commands should be self-explanatory. '%' is used to access a built-in command that currently has an alias overriding it; see the chapter entitled Aliases. For more information on '-', see the section below on Context overriding.
The currently selected filing system can be overridden in two different ways. The command can be prefixed with -name- or name:, where name is the name of a filing system or module. That is, you supply an absolute name of the filing system or module to send the command to. This gets around the problem of having to select the other filing system, perform the command and then re-enter the original filing system. For example, if you are on the net and want to look at a file on the current adfs device, the sequence of commands:
*adfs
*Info Fred
*net
can be replaced with either:
*-adfs-Info Fred
or even more succinctly:
*adfs:Info Fred
Here are some examples of overrides:
*-net-cat
Note that if you are using -net- or net:, you cannot specify nodes on the net: eg -net#spqr-. This is because the command prefix only alters the filing system selected for the command. The part of an object specification after the '#' character is not part of the filing system name but is part of the object name. For example, if you wish to issue a command such as:
*net#oz:info fred
you can use instead:
*net:info #oz:fred
Normally, input comes from the keyboard and output goes to the screen. Redirection allows this source and destination to be changed to any file or device. Output redirection can be viewed as having a *Spool file open for the duration of the command, and disabling all streams except for that one. Input redirection is like having a *Exec file open for the duration of the command.
The syntax of a redirection specifier is:
{ redirection_command [redirection_commands] }
where each redirection_command may be any of:
> filename | Output goes to filename |
< filename | Input read from filename |
>> filename | Output appended to filename |
The redirection specifier can appear anywhere in a line. Note that there must be exactly one space between each element, or it will not be recognised as one. After being decoded. The redirection specifier is stripped before the rest of the command is interpreted. You can put as many redirection commands as you like within the curly brackets; however, only the last one in a given direction will be acted on.
Here are some examples of redirection:
*Cat { > mycat } *Lex { > printer: } *BASIC -quit { < answers } prog *fred { < infile > outfile } *Cat { > out1 < infile > out2 }
The fourth example shows how redirections can be concatenated within the same pair of braces.
In the final example, out1 will be created with nothing in it, input will be read from infile and output will go to out2.
Commands may be abbreviated by terminating them with a '.'. For example, you could type '*Mod.' instead of '*Modules'. When the CLI finds a terminating '.', it remembers that the command is an abbreviation, and when trying to match it to possible aliases or commands to execute (see below), it is satisfied if the abbreviation is a leading substring of the alias or command, rather than an exact match.
It is very dangerous to use abbreviations in programs, as they are dependent on the environment in which they are run. The command they execute can be changed completely by the presence of an alias, or by any addition of commands and change in module ordering under different releases of RISC OS.
An alias is a variable of the form Alias$cmd, where cmd is the command name to match, made up from alphanumeric characters and these others:
! ' ( ) + - . ; = ? @ [ ] _ ' { } ~
If an alias exists which matches the current * Command, RISC OS obtains the value of the variable and replaces any of %0 to %9 in the value by the parameters, separated by spaces, that it reads on the rest of the input line. %*n in an alias stands for the rest of the command line, from parameter 'n' onwards.
Any unused parameters, which are given, are directly appended to the alias. The OS then recursively calls OS_CLI for all lines in the expanded value. However, it may give up at this stage if either the stack or its buffer space becomes full. For example, suppose this command is issued:
*SetPS 0.235
Suppose further that a variable exists called Alias$SetPS, and that this has the value -NET-PS %0|MConfigure PS %0. The OS will match the command name against the alias variable. It will then substitute all occurrences of %0 in the variable's value by 0.235. Then, the two lines of the variable will be executed thus:
-NET-PS 0.235
Configure PS 0.235
So, the net effect of executing the original command is to set the network printer server both temporarily, and also in the permanent configuration.
Another example using the parameter substitution is
*Set Alias$Mode Echo |<22>|<%0>
The '|'s before the angle brackets are to stop them from being evaluated when the *Set command is entered. Typing *Mode n will then set the display to mode 'n'.
After all the previous steps have been completed, the command that is left after pre-processing must be executed. This is a list in order of the things that RISC OS will check to execute a command:
A check is made to see whether the command is in the kernel.
The kernel checks each module to see whether it supplies the command. Modules are checked in the order of the module list, as printed by the *Modules command.
Amongst the modules checked is the filing system manager, File Switch, which contains those commands that apply to all filing systems, such as *Cat.
After the module search is complete, the kernel inspects the filing system specific commands in the current filing system module.
If the command is not recognised by the filing system module, the kernel issues an 'unknown command' service call.
If the net is the current filing system, the command is sent to the file server, to see if the command is implemented there. For example, *Pass is implemented in this way.
If the command is still not recognised, then an attempt will be made to *Run it using the current path. The result of this *Run is passed back to the user.
If you are writing a module, the chances are that you will want to recognise one or more * Commands. The Modules explains how you can cause the OS to recognise commands for you, and pass control to your module when one has been found. This section describes the OS calls which are available to facilitate the decoding of the rest of the command line.
The calls mentioned here may also be used by * Commands activated in other ways, eg a transient command loaded from disc. However, the way in which the tail of the command line is discovered will vary for these types of commands. See the chapter entitled Program Environment for details.
On entry to your * Command routine, R0 contains a pointer to the 'tail' of the command, ie the first character after the command name itself (with spaces skipped). R1 contains the number of parameters, where a parameter is regarded as a sequence of characters separated by spaces.
The way in which the command uses the parameters depends on what it is doing. First, if there are too many or too few parameters, an error could be given. (A module can arrange for the OS to do this automatically.)
If a parameter is to be regarded as a string, OS_GSTrans may be used to decode any special sequences, eg control codes, variable names etc. If the parameter is a number, OS_ReadUnsigned might be used to convert it into binary. Finally, OS_EvaluateExpression could be used to read a whole arithmetic or string expression, and return the result in a buffer.
These calls are documented in the Conversions.
Note that the convention in RISC OS is to have parameters separated by spaces. Some of the built-in commands which have been carried over from the BBC/Master machines also allow commas. You should not support this option.
R0 = pointer to string terminated by Null, Linefeed or Return
R0 = preserved
Interrupts are enabled
Fast interrupts are enabled
Processor is in SVC mode
SWI is not-re-entrant
OS_CLI will execute a string passed to it as if it had been typed in at the supervisor command line. When it is called, it performs the following actions:
The OS needs a certain amount of workspace to deal correctly with a command. If this is not available, the error 'No room on supervisor stack' will be generated.
A * Command line must be less than or equal to 256 bytes long, including the terminating character. If it is not, the error 'Too long' is returned.
The command is then passed to the command line interpreter and executed as any other * Command. This is described in the Overview and Technical Details.
None
CLIV
R0 = new file handle for input
R0 = old file handle for input
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
This SWI reads or writes the file handles used by OS_CLI to redirect input/output. It is mainly provided for the use of the TaskWindow module, but you may also find the call useful.
None
None
Calls Command Line mode, and hence allows you to type * Commands
*GOS
None
*GOS starts the RISC OS Supervisor application from the current environment. The supervisor can only execute *Commands.
This is useful for entering simple commands for immediate execution, or for testing longer sequences of commands - while building command line scripts -on a line-by-line basis.
However you should be careful when calling it from the middle of an application which does not 'shell' new applications. For example, calling *GOS in the middle of writing a BASIC program will mean that you will lose all of your unsaved work.
From the desktop, pressing F12 has a similar effect. To return to the desktop, press Return at the start of a line with the Supervisor prompt ('*'). If you do not have this prompt, you will first have to type *Quit to leave the application you are using.
See the chapter entitled Overview and Technical Details for a description of how the command line interface works.
*Quit, *Desktop
None