Copyright © 2001 PegaSoft
Canada and Free Software Foundation
This software is released under the GNU Public License. See COPYING
file.
AdaScript language created by Ken
O. Burtch and is a trademark of PegaSoft
Canada.
BUSH (Business Shell) is a powerful Linux/UNIX shell for
designing secure, reliable shell scripts that can be later compiled as
a fast executable programs. It can also be used an an interactive login
shell or to generate Java Virtual Machine applications. BUSH is a robust
and readable alternative to BASH, CSH, and (to a certain extent) Python
and PERL.
BUSH is available for downloads from http://www.vaxxine.com/pegasoft/bush-down.html. Discuss BUSH at PegaSoft's Linux Cafe. Send bug reports to ken@nospam.tiamet.vaxxine.com (remove the "nospam").
New To This Version
What's Not Complete
BUSH vs. BASH
BUSH vs. Python
BUSH vs. PERL
BUSH vs. Ada 95
BUSH vs. Java
Does Bush...
Interactive BUSH
A Very Basic Tutorial
Command Line Interaction
Progressive Development Model
Compiling An Executable
Interactive Statements
Profile Scripts
Script Structure
Restricted Shells
Language Reference
AdaScript Language Reference
Fundamental Types
User-defined Types
Basic Assignment and Expressions
The @ and % Operands
Built-in Constants/Variables
Basic Input/Output
Text File I/O
TCP/IP Sockets
Numeric Formatting with Put
Flow of Control
Other Statements/Subprograms
External Commands
Interpreter Directives
Command Line Options
Command Reference
System Package
Numerics Package
Strings Package
ASCII Character Set
BUSH is a shell that has the fundamental syntax of the Bourne shell. However, BUSH uses a different language for advanced features making BUSH easier to read and debug. BUSH scripts can be compiled into Java byte code or into an executable program. BUSH's reliability, scalability and speed make it ideally suited for professional scripting projects. BUSH can act as an interactive shell and can run scripts.
BUSH is a shell and language designed for high reliability business applications. BUSH scripts are slower to develop than Python programs but are easier to maintain over the lifetime of a project. The shortcuts BUSH provides are carefully chosen so as not to undercut reliability. BUSH features do not fall victim to the "feature bloat" syndrome that weakens the reliability of a language. BUSH scripts can be easily upgraded to a compiled language.
BUSH is a Linux shell and shell language designed for high reliability business applications. It's not a report generation language although it can generate reports using formatted output and pattern matching like PERL does. BUSH scripts are slower to develop than PERL scripts but are easier to maintain over the lifetime of a project. Because of its emphasis on a typo-resistent syntax, BUSH is easier to maintain, especially when used large projects.
The BUSH shell is not an Ada interpreter. BUSH uses AdaScript, a subset of the Ada 95 language with additional features specifically for interactive shell sessions. Because of its Ada 95 background, BUSH scripts are easy to create, maintain, debug and can be compiled into fast, executable programs using an Ada 95 compiler.
If you are looking for full Ada compilers or interpreters, they are
available on the Internet.
BUSH scripts can also be compiled into Java byte code (using the JGNAT compiler) and run the same way as Java applets/applications, including web page applets. BUSH scripts are easy to create, maintain, debug and can be compiled into fast, executable programs using an Ada 95 compiler.
Have a GPL licence? | YES |
Have source code available? | YES |
Can it be compiled? | YES |
Can it create Java byte code? | YES |
Run as an interactive shell? | YES |
Run as a login shell? | YES |
Run scripts? | YES |
Offer easy scalability to a more powerful language? | YES |
Have test suite included? | YES |
Run on Linux or UNIX? | YES |
Use its own interal byte code? | YES |
Have scoped variables and blocks? | YES |
Check for undeclared variables? | YES |
Have strong type checking? | YES |
Have powerful pattern matching like PERL? | YES |
Have command line shortcuts like Python? | YES |
Have built-in string and numeric functions? | YES |
Support Bourne shell syntax? | Often |
Have arrays? | When a script is upgraded to Ada 95 |
Have enumerated types? A boolean type? | YES |
Have floating-point numbers? | YES |
Have unlimited length strings? | YES |
Have modules/units/packages? | When a script is upgraded to Ada 95 |
Have objects? | When a script is upgraded to Ada 95 |
Have multithreading? | When a script is upgraded to Ada 95 |
Have TCP/IP sockets? | YES |
Do formatted output for writing reports? | YES |
Have user-defined types? | YES |
Support typeless variables? | YES |
Job control? Signal handling? | Partially, incomplete. |
Have I/O redirection? | YES |
Have secure command aliases? | YES |
Automatically declare variables at the command prompt? | YES, with a warning. |
Have process substitution? | No |
In most shells, you can quit your interactive session using control-d, the end of file character. BUSH will only terminate your session by the command "logout". This prevents an accidental logout caused by the end of file character. (In a shell script, BUSH will quit when the script file is reached or at a return statement.)
The help command presents a short summary of recognized BUSH commands.
For information on a particular topic, use "help" and the topic name.
=> help delay
delay - wait (sleep) for a specific time
delay secs
BUSH comments are started with a double minus sign. Any text following the comment sign to the end of the document are treated as explanatory text. For example,
=> -- BUSH is great
BUSH can be used as a simple calculator. The "?" command will print the result of an arithmetic expression. The basic arithmetic operators are the same as they are in most languages: + (add), - (subtract), * (multiply), and / (divide). Also available are ** (exponentiation), rem (remainder), mod (modulus), and (bitwise and), or (bitwise or), xor (bitwise exclusive or). Parentheses can be used to group subexpressions. Unlike BASH, BUSH numbers are not limited to integers.
=> ?5.5+2.5
8
=> ? (25-4)*6
126
=> ? 12/4
3
Because BUSH is a shell, the "?" is required. If it is missing, BUSH assumes that the expression is the name of a Linux command and will report an error. (This differs from Python because Python is not a shell.)
=> 12/4
12/4: No such file or directory
External operating system commands can be executed by typing them at the prompt. The "ls" command lists files in the current directory.
=> ls
letter2mom.txt bushscript.bush
Operating system commands can be called in two different formats. If the command is followed by a left parenthesis, the command is executed using AdaScript arguments. If there is no parenthesis, it's executed with traditional Bourne shell arguments.
=> echo 2*3
2*3
=> echo (2*3)
6
This behavior is only applicable to external commands. BUSH commands almost always use the AdaScript syntax.
External commands will run in the background when a trailing ampersand (&) is used. The ampersand must be separated from the rest of the command by a space.
=> sleep( 5 ) &
sleep ( 11400) has started
The bracketed number returned is the UNIX/Linux process id.
The "?" command is a short-form for the put_line command. The shortform is provided as a convenience at the command prompt.
=> put_line( 12/4 )
3
Strings are surrounded by double quotes, characters by single quotes.
=> ? "Hello world!"
Hello world!
=> ? 'c'
c
The "put" command is similar to put_line except that it doesn't start a new line after printing and it can display formatted numeric values. The formatting is described by a picture string.
=> put( 123.45, "####9.99" )
$123.45
Strings are joined together with the concatenation operator, "&".
=> ? "Hello " & "world!"
Hello world!
The last outputted value is represented by "%". Like "?", this is a convenience operand to save typing at the command prompt.
=> ?% & " It's good to be alive!"
Hello world! It's good to be alive!"
Other string functions are available in the strings package. Package functions are accessed by prefixing the function with the package name.
=> ? strings.glob( "*pear*", "apple pear peach" )
true
=> ? strings.glob( "*cherry*", "apple pear peach" )
false
=> ? strings.length( "apple" )
5
ASCII character codes can be expressed with "ASCII", a period, and the code for the character.
=> ? "The tilde is " & "'" & ASCII.Tilde & "'."
The tilda is '~'.
Boolean and relation expressions can be computed using "=", "/=", ">", ">=", "<", "<=", and, or and xor. The built-in constants "true" and "false" represent true and false respectively.
=> ? 5=5
true
=> ? (5>6) or (2<3)
true
=> ? false
false
All variables in BUSH are typed. When a variable has a type, only values of the same type can be assigned to it. This prevents variables containing fundamentally different values from being combined.
The assignment operator is ":=".
=> x : integer
=> x := 5
=> ? x
5
=> x := "hello"
x := "hello";
^ type integer (a universal_numeric) is inherently different from a universal_string
When using BUSH interactively, undeclared variables being assigned values will be declared for you with a warning. The type of variable is guessed at by the value being assigned. (This behaviour can be suppressed with an appropriate pragma.)
=> y := 15
=> (Assuming y is a new universal_numeric variable)
=> a : integer := 5
=> b := a
=> (Assuming b is a new integer variable)
If BUSH's guess is not specific enough, you can explicitly set the type of the variable with the typeset command.
=> typeset y is float
A typeless variable adapts its type to the context of an expression. If there is doubt, the type is assumed to be a string. This behaviour is very similar to the way traditional Bourne shell variables work.
=> t : universal_typeless
=> t := "hello"
=> t := 5.0
=> ? t + 1
6
=> ? t & " is a string"
5.0 is a string
Constants are created with the word "constant" before the type.
=> company : constant string := "Omnicorp Software"
=> ? company
Omnicorp Software
=> company := "Evil Rivals Ltd."
company := "Evil Rivals Ltd.";
^ "company" is a constant,
not a variable
Commands can be ended with a semi-colon. Using semi-colons, more than one command can be placed on a line.
=> x := 3
=> (Assuming x is a new universal_numeric variable)
=> y := 4
=> h := numerics.sqrt( x*x + y*y )
=> (Assuming h is a new universal_numeric variable)
=> ? "Hypoteneuse is" ; ? h
Hypoteneuse is
5
This concludes this short tutorial of BUSH's interactive session features. Read on to learn about BUSH built-in packages, scripting and complete coverage of BUSH's interactive features. To see a sample script, try running "eliza.bush", the BUSH version of the famous artificial intelligence program. This script is included in the examples directory and can be run with "bush eliza.bush".
The "emacs mode" key bindings are:
If you prefer to use vi cursor movement instead, press the escape key to enter vi mode. Press escape again to return to emacs mode. In vi mode, you can use lower-case 'h', 'j', 'k', 'l', '^' and '$'.
BUSH recognizes a fundament problem in business programming. Programmers
with limited time and resources are often required to write up quick scripts
to solve pressing business problems. Once the script is written, they have
no time to return to the script to write a "proper" solution. Scripts,
designed for rapid and simple solutions, continue to grow and mutate, becoming
rapidly unreadable and easily broken, leaving a complete rewrite in a different
language as the only to upgrade the software.
To combat this problem, BUSH scripts can be developed using a progressive development model.
In its native mode, BUSH provides a quick and easy environment to write short Linux programs. Like BASH, variables can be declared anywhere and can be typeless. Although its structure is relaxed compared to a compiled programming language, AdaScript's syntax is both easier to read than a BASH script and provides much more security against typing errors. Common errors in BASH such as missing a quotation or spelling mistakes on variable names are quickly caught.
As an BUSH script grows over time, becoming longer and carries more responsibility, the structure of the script can be improved by using "pragma ada_95". This BUSH directive disables many of the "lazy" AdaScript features such as typeless variables and requires closer conformation to the Ada language. A programmer can "tighten" his code as part of his regular duties, add type checking, and ensure that the script's structure is sound and the source is readable without resorting to a complete rewrite.
Some important scripting features, like running commands in the background with "&", are still allowed.
Finally, if the BUSH script continues to grow and is no longer suitable as a script, the script can be compiled with minimum changes as an Ada program. With other shells and scripting languages, a developer would have no choice but to rewrite the script "from scratch".
Results of an HP-UX benchmark with an early version of BUSH 0.8 shows that BUSH (when compiled) easily outperforms than the fastest shell tested. It ran about 16 times faster than BASH. Except for white space, the output was identical to the original shell script. It did not require a rewrite into another programming language.
AdaScript is not completely compatible with Ada 95 because Ada 95 was never designed as a language for writing scripts. Changes must be made to your script, but the changes should be minimal and easily made.
First, compile your script with the pragma ada_95 directive. This will report most non-Ada 95 features as an error. pragma ada_95 disallows the following in scripts:
Third, external commands will have to be rewritten as Ada procedures or calls to GNAT.OS_Lib.Spawn or the Linux/UNIX system() call. You will have to import system() to use it.
Finally, compile the script with GNAT compiler. To generate Java
byte code to run on a Java Virtual Machine, use the JGNAT compiler instead
of GNAT.
Second, compound statements (statements that enclose other statements) can be used provided that the complete statement appears on a single line. Semi-colons will have to be placed after every command except the final command.
=> for i in 1..5 loop put_line( i ) ; end loop
1
2
3
4
5
A semi-colon isn't required after the first "loop" because the "for" statement is a compound statement ending with "end loop"--the semi-colon is only required after the final keyword in a compound statement. In this case, the final keyword is also the last keyword on the command line and the semi-colon is optional.
During an assignment, if the variable being assigned isn't declared, it's automatically declared unless pragma ada_95 or pragma restriction( no_auto_declarations ) is used. The type of the variable is the type of the expession being assigned.
=> y := numerics.sqrt( 9 )
=> (Assuming y is a new universal_numeric variable)
External commands can be grouped into pipelines using the vertical bar character (|). Pipelines are a command line convenience feature and are not intended for use in scripts (this is true in other Linux shells as well).
Interactive sessions can only be terminated with the logout command.
First, BUSH looks for a script called "/etc/bush_profile". This script should contain commands to be run by every user logging in.
Second, BUSH looks for a script called ".bush_profile" in the user's home directory. This script should contain commands specific to a particular user.
The following is a sample ".bush_profile" script:
-- Sample profile script
-- disable automatic declaractions because I don't like them
pragma restriction( no_auto_declaractions );
-- declare company name
company : constant string := "Compu-Global-Mega-Corp Inc.";
-- show the date and time
date;
After the profile scripts are executed, the user sees the "=>" prompt
and can being entering commands.
$ echo "? \"Hello World\" ; logout" | bush
BUSH treats this as if it was an interactive session with a human user. Command prompts are written to the screen and the keyword logout is necessary to terminate the session. (In an interactive session, the end of file without a logout will cause BUSH to go into an infinite loop as it waits for more commands to be typed by the user.)
A better way to execute a set of commands is to write a script. A script is a text file containing AdaScript commands. A script has these advantages:
In simple scripts, variables, statements, and external commands can be freely mixed. Scripts usually start with "#!/bin/bush" (or whatever BUSH's pathname is), UNIX/Linux's way of determining the program to execute when a script is run.
#!/bin/bush
sales_force : universal_numeric := 55;
yearly_sales : universal_numeric := 2000000;
put( "Average sales is " );
put( yearly_sales / sales_force );
new_line;
BUSH will execute these statements as if they were typed in sequentially at the command prompt. However, to make your script easier to read, you can organize your script into separate declaration and executable sections using a procedure statement.
#!/bin/bush
procedure demo_script is
sales_force : universal_numeric := 55;
yearly_sales : universal_numeric := 2000000;
subtotal : universal_numeric := yearly_sales / sales_force;
begin
put( "Average sales is " );
subtotal : universal_numeric := yearly_sales / sales_force;
put( subtotal );
new_line;
end demo_script;
For compliancy with Ada 95 compilers, your program must be enclosed in a procedure statement if your program uses pragma ada_95.
A program can be separated in declarations and an executable part with the declare statement.
#!/bin/bush
declare
sales_force : universal_numeric := 55;
yearly_sales : universal_numeric := 2000000;
subtotal : universal_numeric := yearly_sales / sales_force;
begin
put( "Average sales is " );
put( yearly_sales / sales_force );
new_line;
end;
Declare blocks can be nested inside of one another, usually to break up a very long script into logical parts.
#!/bin/bush
declare
sales_force : universal_numeric := 55;
yearly_sales : universal_numeric := 2000000;
begin
put( "Average sales is " );
declare
subtotal : universal_numeric := yearly_sales
/ sales_force;
begin
put( subtotal );
end;
new_line;
end;
When blocks are nested, you can declare new variables which only have meaning in that particular block, reducing the chance of using the wrong variable name in a large script.
A script is run by using the script name as an argument to BUSH. BUSH normally performs a syntax check before running the script.
$ bush demo.script
There are several command line options which can change how the script is run. For example, the BUSH syntax check will sometimes report errors for a legitimate script--for example, by declaring variables inside of an "if" statement. Normally, this is a sign of a poorly organized script, but the syntax check can be disabled . To run the script without checking it, use the --no-check command line option.
The execution of a script can be traced with the BUSH trace command. Suppose you want to trace the execution of the following script:
#!/bin/bush
trace true;
procedure main is
type paint is ( black, white, blue );
begin
for p in black..blue loop
put_line( p );
end loop;
end main;
Once tracing is turned on by trace true, each line will be shown before it's executed, with the line number in square brackets to the right of the line. Some statements will also show additional information. For example, an assignment statement will show the value being assigned. The trace information is written to standard error, so the output from the command may appear in the wrong order because some versions of UNIX buffer their output.
$ bush trace_demo.bush
Trace is on
=> "" [ 4]
=> "procedure main is" [ 5]
=> " type paint is ( black, white, blue );" [ 6]
=> "begin" [ 7]
=> " for p in black..blue loop" [ 8]
=> " put_line( p );" [ 9]
=> (p := ' 0')
black
=> " end loop;" [ 10]
=> " end loop;"
=> " put_line( p );" [ 9]
=> (p := ' 1')
white
=> " end loop;" [ 10]
=> " end loop;"
=> " put_line( p );" [ 9]
=> (p := ' 2')
blue
=> " end loop;" [ 10]
=> " end loop;"
=> " put_line( p );" [ 9]
=> " end loop;" [ 10]
=> "end main;" [ 11]
=> "" [ 12]
=> "[End of File]" [ 13]
=> (Script exit status is 0)
BUSH restricted shells don't allow:
=> cd ..
cd ..;
^^ cd not allowed in a restricted shell
BUSH's restricted shell mode differs from Bourne restricted shells in
that it's not intended to isolate users but scripts. User sessions,
however, can be started in restricted mode, but the restrictions do not
apply to the profile files, allowing the administrator to setup the shell
environment before the restrictions are enforced.
AdaScript is intended to be "upward compatible" with Ada 95. AdaScript scripts should run with little difficulty under Ada, but Ada programs may require large changes run under BUSH. For example,AdaScript is a case-sensitive language (because shell variables and Linux commands are case-sensitive), but Ada is case-insensitive and programs may need to have the capitalization of keywords changed to fit the case expected by AdaScript.
AdaScript has a number of reserved words. These are words that have a special significance to the language and they cannot be used as variable names. All Ada 95 keywords are also reserved, even those that are not used by AdaScript, to make it easier to compile scripts with an Ada compiler. The reserved words must always be in lower case.
abort | mod |
abs | new |
abstract | not |
accept | null |
access | of |
aliased | or |
all | others |
and | out |
array | package |
at | pragma |
begin | private |
body | procedure |
case | protected |
clear | raise |
constant | range |
declare | record |
delay | rem |
delta | renames |
digits | requeue |
do | return |
else | reverse |
elsif | select |
end | separate |
entry | subtype |
env | tagged |
exception | task |
exit | terminate |
for | then |
function | trace |
generic | type |
goto | typeset |
help | unset |
if | until |
in | use |
is | when |
jobs | while |
limited | with |
logout | xor |
loop |
Comments are denoted by either a "#" or a "--" and all text after these symbols is ignored until the end of line.
Universal Types
There are three "universal types":
* universal_string
* universal_numeric
* universal_typeless
These universal types can be used to disable AdaScript's strong typing in parameters and expressions. Universal types automatically match any type derived from the same universal type. For example, a string literal like "hello" is a universal_string and can be used with any string type. And the numeric literal 45.5 is a universal_numeric can be used with float, long_float, or any other numeric type.
Variables can also be declared universal_typeless, which means they can be used with both string variables and numeric variables, automatically converting into the proper type when required. (Two typeless variables in the same subexpression are treated as two strings.)
Using these three built-in types will give you a minimum amount of type checking, suitable for short scripts or quick command line calculations. Universal types should not be used in large scripts because they make debugging difficult.
Pre-defined, Non-Universal Types
For more extensive scripts, AdaScript extends the universal string and numeric types into all the predefined Ada language types, plus some AdaScript-specific types:
By default, all numeric variables are initialized without any value.
Any attempt to use uninitialized numeric variables in an expression will
cause an error or exception.
=> i : integer -- no value specified
=> i := i + 1
i := i + 1;
^ exception
raised
All types are logical types: that is, all numeric types are stored in the same format. A natural, integer or float are all stored as a universal numeric value. There are only minimal checks to make sure that variables of these types conform to their descriptions. However, types provide an indication to the reader of how a variable is intended to be used, and AdaScript will not allow these types to be combined without an appropriate type cast.
=> i : integer := 5
=> f : float := 0
=> f := i
f := i;
^ type 'float' is not compatible
with type 'integer'
=> f := float(i) -- typecast
=> ? f
5
You cannot typecast a numeric type into a string type directly. There are functions in the numerics and strings packages to do these conversions.
Since all values are stored as a universal type, this can cause some unusual side-effects. A character variable can contain more than one character if you really want it to by assigning a string literal. Characters are stored as a universal_string and a string literal is a universal_string type. AdaScript will allow the assignment. However, the type checking will prevent a character variable from being assigned to a string variable.
c : character;
c := "hello"; -- confusing, perhaps stupid, but legal
s : string := c; -- ILLEGAL
AdaScript strings are an unbounded string type--that is, as an Ada.Strings.Unbounded.Unbounded_String variable. They have an unlimited length and are not implemented as any sort of array. Unlike Ada "fixed" strings, AdaScript strings can have any length and are not subject to array restrictions.
Constants
Constants can be declared with the word "constant" for any type. The use of "constant" doesn't not affect the type of the variable--it simply prevents new values from being assigned by making the variable "read-only".
program_name : constant string := "Nightly FTP Transfer";
Limited Types
file_type and socket_type variables are known as limited type variables. Limited types cannot be assigned a new value with an assignment statement
=> f : file_type
=> g : file_type
=> f := g
f := g;
^ limited variables cannot be assigned
a value
BUSH manages the contents of these variables and scripts are not allowed to change the contents.
Command Types
External operating system commands can be declared using command variables. When a command is declared, BUSH will ensure that the command exists and is runnable.
Command types are similar to limited types and have several restrictions.
=> l : constant command := "/bin/ls"
=> m : constant command := "/bin/lt"
m : constant command := "/bin/lt";
^ "/bin/lt" is not an executable command
=> n : constant command := l;
n : constant command := l;
^ type universal_string is inherently different from a command
=> ? l & " is the path"
? l & " is the path";
^ type command is inherently different from a universal_string
=> ? l
/bin/ls
The subtype statement will create a type that is compatible with the original, as if it was a renaming of the original type.
=> subtype int is integer;
=> i1 : integer := 1
=> i2 : int := 2
=> ? i1 + i2
3
In this case, "int" is equivalent to "integer" and variables of both types can be mixed freely without type casting. Unlike Ada 95, there is no way to place restrictions on a subtype--they are simple renamings in AdaScript.
To make incompatible types, you need to create a new type with the type statement.
=> type employee_number is new integer;
=> type customer_number is new integer;
=> en : employee_number
=> cn : customer_number
=> en := cn
en := cn;
^ type 'employee_number'
is not compatible with type 'customer_number'
In this case, "employee_number" variables cannot be mixed with "customer_number" (or other) variables without a typecast. Use new types to make sure variables that are logically different don't accidently mix.
AdaScript also has an enumerated type. Enumerated types are naturally incompatible with one another, and the items in the enumerated list cannot be overloaded with other enumerated types.
=> type fruit is (apple, blueberry, cherry);
=> f : fruit
=> f := apple
=> f := 5
f := 5;
^ type fruit (an enumerated type)
is inherently different from a universal_numeric
There are two built-in enumerated types. The boolean type is a predefined enumerated type with values "false" and "true". The file_mode type has the values "in_file", "out_file" and "append_file".
AdaScript has no aggreagate types. There is no object, array or record/structure type. If you need these, your project is probably too complicated for a simple script and should be upgraded to Ada 95.
Assignment (:=) is a statement, not an operator, and cannot be used in expressions.
x := 5 * ( 7 + 2 );
s := "hello " & "there!";
total := @ + 1; -- total := total + 1;
AdaScript provides a last output operand. "%", pronounced "last output", returns the last put_line value.
=> put_line( 5*2 );
10
=> put_line( %+5 );
15
The type of the last output is remembered.
=> put_line( 5 )
5
=> put_line( % & " is a good number" )
put_line( % & " is a good number" );
^ type universal_numeric is inherently different from a universal_string
AdaScript contains many built-in constants, variables and functions.
Some of these are grouped into packages.
To use a function or constant inside a package, prefix the function with the name of the package. For example, to use the "length" function in the "strings" package, refer to it as "strings.length".
=> ? strings.length( "PegaSoft" )
8
The built-in Text_IO package, which contains put_line and get_line, is treated as an inherent part of the language and doesn't use a prefx of "Text_IO".
Parameters to the script are available using the built-in command_line package. However, for compatibility, the Bourne shell syntax can also be used:
The Bourne shell form are intended as command line shortcuts and the command_line package should normally be used in a well-structured script.
rm ("/tmp/temp." & $$)
if $? /= 0 then
put_line( standard_error, "unable to delete temp file"
);
end if;
The status code of the last command executed is returned from a script
when it finishes executing. A specific status code can be returned
using the command_line package.
Directory Walking
There are two built-in BASH-style commands for managing your current directory:
Console I/O
The question mark command "?" is a short-form for put_line
to standard output.
get is provided for compatibility for Ada 95. A more useful function for reading a keypress is
put and put_line can take any type of parameter. Also, they can also explicitly direct their output to standard output or standard error by using standard_output or standard_error as the first parameter.
=> put_line( standard_error, "an error occurred!" );
get_line reads a line of text from the keyboard until the return key is pressed.
Ada's get_immediate is not implemented.
BASH opens files on the basis of file numbers or "file descriptors".
In AdaScript, files are declared using a file_type variable.
AdaScript's I/O system implements a subsection of the Ada Text_IO library.
The file is closed with close.
=> close( f )
standard_input, standard_output and standard_error can be redirected with the appropriate command to an open file.
=> set_output( f )
From now on, all output going to standard output is written to the file_type
variable f. The current_output function refers to the file being written
to (in this case, f). Output redirected to f is not counted by the line
function.
The main difference between a socket and a file is that sockets are always "in" and "out". When opening a socket, do not specify a mode.
The name of the socket is a string containing the name of the server computer, followed by a colon and a port number. The port number is 80 (a web server) if no port is specified. Certain ports, such as those above 32767, are prohibited as a security precaution.
#!/bin/bush
-- download a web page
f : socket_type;
c : character;
open( f, "www.somewebserver.com" );
put( f, "GET /index.html HTTP/1.0" & ASCII.CR & ASCII.LF
);
put( f, "User-Agent: BUSHTest/1.0 (BUSHTest)" & ASCII.CR &
ASCII.LF );
put( f, ASCII.CR & ASCII.LF );
loop
get( f, c );
put( c );
exit when end_of_file( f );
end loop;
put_line( "End of web page" );
close( f );
The picture string may include:
=> put( 12.34, "***9.99" ) ; new_line
**12.34
=> put( 12.34, "###9.99" ) ; new_line
$12.34
=> put( 12.34, "+###9.99" ) ; new_line
+ $12.34
=> put( 12.34, "-###9.99" ) ; new_line
$12.34
=> put( 12.34, "<###9.99>" ) ; new_line
$12.34
=> put( -12.34, "<###9.99>" ) ; new_line
( $12.34)
if statements are used for conditional branching.
if x > y then
put_line( "x is greater than y" );
elsif x = y then
put_line( x is equal to y" );
else
put_line( x is less than y" );
end if;
The case statement can test a variable for several different values.
type country is ( australia, u_k, brazil );
...
case c is
when austraila =>
put_line( "Australia" );
when u_k =>
put_line( "United Kingdom" );
when brazil =>
put_line( "Brazil" );
when others =>
put_line( "Unexpected country" );
end case;
The "when" cases must not be variables. The "when others" case is always required.
The while loop is a pre-test loop. The commands in the loop are repeat while the condition is true and the condition is tested each time the first line of the loop is executed.
while x > y loop
x := @ + 1;
end loop;
The for loop increments its index variable by 1 until it iterates through the specified range. The index variable is automatically declared for you and only exists for the scope of the the loop. The range can either be numeric or enumerated.
for i in 1..10 loop
put( "i is " );
put_line( i );
end loop;
To loop in reverse in a for loop, use "in reverse" instead of "in".
Any loop can be exited by using either an exit statement or an "exit when" shorthand.
if x > 100 then
exit;
end if;
exit when x > 100;
A "loop" loop is a general purpose loop. It can only be exited with "exit".
loop
reply := get_line;
exit when reply = "exit";
end loop;
null; -- do nothing
delay 2.5; -- wait 2 1/2 seconds
system( "date" ); -- execute the Linux date command
return; -- quit the program
=> echo
will run the Linux echo command and print a blank line to the screen, the same as new_line.
Commands are accepted in one of two different formats. If the command is followed by a "(", the parameters are expected to be in AdaScript format with each parameter separated by a comma (","). These parameters may be any legitimate AdaScript expression and no shell quote removal or file globbing is performed.
=> ls( "bush.adb" )
bush.adb
If the command is not followed by a "(", the parameters are expected to be in Bourne shell format. This is provided for convenience in interactive sessions. The parameters are shell "words" separated by spaces. Each word has file globbing performed. The words may be enclosed in double quotes to allow embedded spaces, or single quotes to inhibit file globbing. Special characters may also be escaped with backslashes.
=> ls b*.adb
builtins.adb bush.adb
Bush will not perform any BASH-style "$" substitutions.
Command names containing space characters can be quoted with double quotes.
=> "inventory report"
When pragma ada_95 is used, shell commands must only use the AdaScript parameter format, to make conversion to Ada 95 easier.
External commands can be run in the background using an ampersand ("&") at the end of the command. With AdaScript parameters, place the ampersand after the closing parenthesis. The jobs command displays the status of any outstanding background commands.
The built-in shell commands are listed in a section above. when a Linux command conflicts with a built-in command, the Linux command can be executed using the command command.
begin
see declare
case
Syntax: case var is when constant|literal => ... when others => ...
end case
Description: Test a variable for multiple values. "when others" case
is required.
cd
Syntax: cd - | dirname
Description: change directory. "-" is the previous directory.
A leading '~' is your home directory.
clear
Syntax: clear
Description: reset tty device and clear the screen
close
Syntax: close( file )
Description: close an open file
command
Syntax: command cmd
Description: run a Linux command (instead of a built-in command).
create
Syntax: create( file [, out_file | append_file] [, path ] )
Description: create - create a new file or overwrite an existing file.
The default type is out_file. The default path a temporary file name.
declare
Syntax: [declare declarations] begin ... end
Description: begin a new block
delay
Syntax: delay secs
Description: wait (sleep) for a specific time
delete
Syntax: delete( file )
Description: close and delete a file
end_of_file
Syntax: end_of_file( file )
Description: true if an in_file file has no more data
end_of_line
Syntax: end_of_line( file )
Description: true if an in_file file has reached the end of a line
with get
else
see if
elsif
see if
env [ident or keyword]
Syntax: env
Description: show all identifiers, or identify an identifier or keyword.
exit
Syntax: exit | exit when condition
Description: break out of a loop
for
Syntax: for var in [reverse] first..last loop ... end loop
Description: for loop - loop through between first and last assigning
value to var. The for starts a new block and the for variable is automatically
declared based on the type of first.
get
Syntax: get( [file,] var )
Description: read a character from a line of text.
get_line
Syntax: var := get_line [ (file) ]
Description: read a line of text
if
Syntax: if expression then ... [elsif expr then ...] [ else ...]
Description: conditional execution";
inkey
Syntax: c := inkey
Description: read a character from standard input without echoing
is_open
Syntax: is_open( file )
Description: true if file is open
jobs
Syntax: jobs
Description: list status of current background jobs
line
Syntax: line( file )
Description: the number of read/written lines
logout
Syntax: logout
Description: terminate an interactive session
loop
syntax: loop ... end loop
Description: General loop. exit with an exit statement.
mode
Syntax: mode( file )
Description: the file mode (in_file, out_file, append_file)
name
Syntax: name( file )
Description: name of an open file
new_line
Syntax: new_line [(file)]
Description: start a new line
null
Syntax: null
Description: do nothing
open
Syntax: open( file, in_file | out_file | append_file, path )
Description: open an existing file or open a socket
pragma
interpreter directive
put
Syntax: put ( [file], expression [, picture] )
Description: write to output, no new line. If picture is included,
format the number according to the picture.
put_line
Syntax: put_line ( [file], expression )
Display: write to output and start new line
pwd
Syntax: pwd
Description: present working directory
reset
Syntax: reset( file [,mode]
Description: reopen a file
return
Syntax: return [status code]
Description: exit script and return status code
set_input
Syntax: set_input( file ), set_output( file ), set_error( file )
Description: input/output redirection
skip_line
Syntax: skip_line [(file)]
Description: discard the next line of input
subtype
Syntax: subtype newtype is oldtype
Description: create an alias for a type
system
Syntax: system( commandstring )
Description: run a BASH shell command
trace
Syntax: trace [true | false]
Description: show verbose debugging information
typeset
Syntax: typeset var [is type]
Description: change the type of a variable, declaring it if necessary.
Cannot be used in scripts or with pragma ada_95.
unset
Syntax: unset ident
Description: delete an identifier. Cannot be used in scripts or with
pragma ada_95.
wait
Syntax: wait
Description: wait for all background commands to finish.
while
Syntax: while condition loop ... end loop
Description: while loop - repeat the loop until the condition is false
?
Syntax: ? expression
Description: put_line to standard output. Cannot be used with pragma
ada_95.
=> ? System.Memory_Size
4294967296
Predefined numeric constants:
Absolute value (abs) is not technically a part of the numerics package
but is documented here.
Match characters include:
ASCII.NUL - control-@
ASCII.SOH - control-A
ASCII.STX - control-B
ASCII.ETX - control-C
ASCII.EOT - control-D
ASCII.ENQ - control-E
ASCII.ACK - control-F
ASCII.BEL - control-G
ASCII.BS - control-H
ASCII.HT - control-I
ASCII.LF - control-J
ASCII.VT - control-K
ASCII.FF - control-L
ASCII.CR - control-M
ASCII.SO - control-N
ASCII.SI - control-O
ASCII.DLE - control-P
ASCII.DC1 - control-Q
ASCII.DC2 - control-R
ASCII.DC3 - control-S
ASCII.DC4 - control-T
ASCII.NAK - control-U
ASCII.SYN - control-V
ASCII.ETB - control-W
ASCII.CAN - control-X
ASCII.EM - control-Y
ASCII.SUB - control-Z
ASCII.ESC - Escape key
ASCII.FS
ASCII.GS
ASCII.RS
ASCII.US
ASCII.DEL - ASCII 127, delete key
ASCII.Exclam - "!"
ASCII.Quotation - """"
ASCII.Sharp - "#"
ASCII.Dollar - "$"
ASCII.Percent - "%"
ASCII.Ampersand - "&"
ASCII.Colon - ":"
ASCII.Semicolon - ";"
ASCII.Query - "?"
ASCII.At_Sign - "@"
ASCII.L_Bracket - "["
ASCII.Back_Slash - "\"
ASCII.R_Bracket - "]"
ASCII.Circumflex - "^"
ASCII.Underline - "_"
ASCII.Grave - "`"
ASCII.L_Brace - "{"
ASCII.Bar - "|"
ASCII.R_Brace - "}"
ASCII.Tilde - "~"
End of Document