Commit bfd6ee03 authored by John Spikowski's avatar John Spikowski

AIR Script BASIC User Guide Conversion

parent 39b28c35
This diff is collapsed.
# Introduction
\[\<\<\<\] [\[\>\>\>\]](ug_2.md)
ScriptBasic is a BASIC language interpreter with several features that
makes it unique. First of all ScriptBasic itself is **free** and is
supported by the **GNU LGPL licence**. Note that the GNU LGPL
[licence](http://www.gnu.org/copyleft/lesser.txt) applies only to
ScriptBasic itself, while the modules interfacing 3rd party software may
apply different licenses. For example the module interface code for the
module T\<bdb\> is under LGPL, but the library it uses, namely the
Berkeley DB is NOT LGPL\!
ScriptBasic runs on **Windows NT, Windows95, Linux, Tru64 UNIX** and
probably on many other platforms. ScriptBasic the ideal tool to write
small scripts that gurus write in Perl. However you need not be a guru
to powerfully program in ScriptBasic.
This is not the only situation to consider ScriptBasic. ScriptBasic can
be a valuable tool for experts as well as a language interpreter ready
to be built into their application. Read the list of ScriptBasic
features and decide how you can use it.
- **IT IS BASIC.** No question, this is the MOST important feature of
ScriptBasic. There are a lot of people who can program BASIC and
only BASIC. There are many people, who can not really program. Those
who do not really know what programming is, and still: they write
their five-liners in BASIC to solve their simple problems. They
never write Perl, Tcl, Java or C. Therefore it is BASIC.
- **SCRIPTING** language. There are no data types in the language. You
can store real numbers, integer numbers and strings in any variable.
You can mix them and conversion is done automatically. Therefore the
language is very simple and easy to use.
- **PORTABLE** Available in C source and can be compiled on UNIXes as
well as on Windows NT.
- **4E LANGUAGE**, which means easy to extend, easy to embed.
ScriptBasic was developed to provide clean and clear interfaces
around it, and inside it. It is easy to embed the language to an
application and use it as a macro language just like TCL. It is also
easy to implement new built-in function and new commands. You can
develop dynamically loaded libraries that ScriptBasic may load at
run time. The language source is clean, well documented and
development guides are available.
- **COMPILED CODE** ScriptBasic creates intermediate compiled code,
which is interpreted afterwards. This can protect intellectual
property for the BASIC programmer and faster code loading.
- Syntax analysis is done at first and only syntactically perfect
programs start to run.
- The compiled code is put into a continuous memory space and
compiled code can be saved and loaded again to run without
recompilation. This is vital for CGI scripts and is not
available for most scripting programming languages.
- Compiled code is binary, not readable. Therefore you can develop
and distribute programs and getting some help to protect your
intellectual property. You need not give the source code.
- **MULTI THREAD** aware. Although the current implementation is not
multi thread, all the code was designed to be thread safe. You can
embed the code into systems that run multiple interpreters in the
same process. On the other hand the interpreter can run the same
code in multiple threads and was designed to be capable handling
call-back functions, and multithread programs in the future.
This documentation is the User's Guide for the so-called STANDARD
variation of the interpreter. This code runs on the command line,
accepts command line arguments and runs a single program in a single
process. Other variations exist, which are based on the same code but
exhibit different interfaces to the system. Some features for those
variations may be different, but most language features probably remain
the same. The variation Eszter SB Application Engine is shipped with the
ScriptBasic package and is embedding the interpreter into a
multi-thread, single process web server. Other embedded variations are
available from independent developers.
This document describes how to use the interpreter and the programming
language.
-----
\[\<\<\<\] [\[\>\>\>\]](ug_2.md)
# Print
[\[\<\<\<\]](ug_10.md) [\[\>\>\>\]](ug_10.2.md)
The print statement can either print to a file or to the standard
output, which is usually the terminal window. If no file number is
specified after the keyword the statement print prints to the screen. It
takes a list of expressions, formats them and prints the values to the
screen.
print "haho!"
print "hahaho!"
print
print "kukac\n"
print "oooh"
print "The number is ",number
The list of expression is one or more expressions separated by commas.
Old implementations of the BASIC language used `;` for that and inserted
a space between the printed item. These old BASIC languages used the
comma as list separator to put the next printed item on the next tab
position. There is nothing like that in ScriptBasic. The comma simply
separates the list elements, which are printed adjacent. Comma does not
insert space between them and does not position on tab. `;` as list
separator is not allowed.
In case you want to position something in tab position you can
print "hello\ttab"
use the `\t` escaped character.
-----
[\[\<\<\<\]](ug_10.md) [\[\>\>\>\]](ug_10.2.md)
# Input
[\[\<\<\<\]](ug_10.1.md) [\[\>\>\>\]](ug_10.3.md)
ScriptBasic has the usual input statement, however a slightly different
from other BASIC implementations. Input statement in other basic
languages reads the keyboard and puts a string, real or integer number
into the variable depending on the type of the variable. In ScriptBasic
there is no type of the variables, any variable can hold any type of
value. Thus the input statement can not know if the input is to be read
as integer, real or character string as typed.
Because of this ScriptBasic reads the characters as typed into the
variable on the input statement as string. Because this is the usual
behavior of the BASIC languages for the command `line input` ScriptBasic
also names this statement `LINE INPUT`.
This command reads a whole line from the file specified after the \#
sign or from the standard input if no file number was specified. The
string read is put into the variables listed on the command. Each
variable gets a line including the line terminating new line character.
print "Give me a line:"
line input a
print "This is a=",a,"This was a\n"
To remove the new line from the end of the read string you can use the
function `chomp`.
-----
[\[\<\<\<\]](ug_10.1.md) [\[\>\>\>\]](ug_10.3.md)
# Handling command line arguments
[\[\<\<\<\]](ug_10.2.md) [\[\>\>\>\]](ug_11.md)
Though the command line is parsed by the interpreter up to the name of
the executable basic program name and all other command line options and
arguments are passed to the basic program to handle. To access this part
of the command line the basic program should use the function
`command()`. This function does not need any argument and returns a
string containing the command line arguments.
In the variation STANDARD the command line returned by the function
`command()` contains the parameters separated by a single space. Even if
the real command line contains multiple spaces or tabs between the
parameters it is converted to a list of parameters separated by single
space.
' This program demonstrates the command function
' start the program using the command line:
' scriba commandline.bas a b c d e f
'
print "The command line was:\n",command(),"\n"
will print
The command line was:
a b c d e f
-----
[\[\<\<\<\]](ug_10.2.md) [\[\>\>\>\]](ug_11.md)
# Interacting with the user
[\[\<\<\<\]](ug_9.19.md) [\[\>\>\>\]](ug_10.1.md)
Although this topic is detailed elsewhere we present a short
introduction here, because of its importance. Interacting with the user
is the most important action a program takes. There are many ways to do
it, but the most frequently used is printing to the screen and reading
from the keyboard and interpreting command line arguments. To do this
ScriptBasic has the command print and the command line input.
-----
[\[\<\<\<\]](ug_9.19.md) [\[\>\>\>\]](ug_10.1.md)
# Name spaces
[\[\<\<\<\]](ug_10.3.md) [\[\>\>\>\]](ug_12.md)
ScriptBasic does not have real name spaces to separate modules from each
other. There are no such things as public and private variables of
modules or classes. Whenever you develop a module you have to trust the
programmer using the module that he or she will use the module in the
way it is intended and the way you hopefully documented. A programmer
should not use the internal variables of a module not because he can not
but because he is supposed not to.
ScriptBasic name spaces only help the programmers to avoid accidental
name collisions. When you develop a module you start it saying
MODULE MyModule
After this line until the end of the module which is noted by the line
END MODULE
will belong to the specific module and all global variables will belong
to that module.
However all these module and name space handling is done on low level
altering the names of the variables and functions. When you start to
write a program and you write:
A = 3
print A
you actually use the variable `main::A`. This is because the default
name space is `main`, and if there is no name space defined in a
variable its name is altered so that the variable will belong to the
current name space. The default name space is called `main`. Try the
following:
A = 3
print main::A
It prints 3. Surprising? Try the following:
A=5
module boo
A=3
print main::A
end module
It will print 5. This is because `main::A` is 5, `boo::A` is 3 and the
variable name `main::A` is not converted to `boo::main::A`, because it
is explicitly denoted to belong to the name space `main`.
Name spaces can be nested. You can write:
A=1
module boo
A= 2
module boo::baa
A= 3
print A
print boo::A
print main::A
end module
end module
which will print 321.
To ease the nesting of modules you can write the same code as
A=1
module boo
A= 2
module ::baa
A= 3
print A
print _::A
print main::A
end module
end module
When the module name in the module declaration starts with double colon
ScriptBasic knows that the module is to be nested into the current
module. The variable name \_::A means: the variable A of the surrounding
name space. This is the same as the operating system directories. You
can think of name spaces as directories and variables as files. Whenever
you write
../../mydir/file.c
a similar construct may say
_::_::mynamespace::variable
When the parser sees the end module statement it always returns to the
previous name space. You can start and close modules many times,
ScriptBasic will not complain that the module was already defined. You
can even totally neglect the module statement and you can write the
above program as
main::A=1
boo::A= 2
boo::baa::A= 3
print boo::baa::A
print boo::A
print main::A
This is a bit less readable. Name spaces can serve another purpose. See
the following code:
string = "AF"
hex = 0
while string <> ""
chr = mid(string,1,1)
string = mid(string,2)
hex = hex*16 + asc(chr) - asc("A")
wend
print hex
when you try to compile you will probably get many errors. Why? Because
string, `chr` and `hex` are predefined functions and can not be used as
variable names. What to do then? You can use them as variable names when
you specify that they are variables:
::string = "AF"
::hex = 0
while ::string <> ""
::chr = mid(::string,1,1)
::string = mid(::string,2)
::hex = ::hex*16 + asc(::chr) - asc("A")
wend
print ::hex
When you write var{::string}, `::chr` or `::hex` ScriptBasic will know
that they are variables belonging to the current name space. This is a
bit weird, so you better avoid using function names and predefined
function names as variable names.
-----
[\[\<\<\<\]](ug_10.3.md) [\[\>\>\>\]](ug_12.md)
# Opening and creating files
[\[\<\<\<\]](ug_12.md) [\[\>\>\>\]](ug_12.2.md)
ScriptBasic handles the files the same way as any other BASIC type
language. You open a file, read from it, write to it and finally close
the file. To make a jumpstart see a simple example:
open "myfile.txt" for output as 1
print#1,"This is the first line of myfile\n"
close 1
open "myfile.txt" for input as 1
line input #1, a
close 1
print a
This simple program opens the file named \``myfile.txt`' in the current
directory, prints a single line into it, and closes the file. Next time
it opens the file for reading, reads a line from it, closes the file and
prints the line read from the file to the screen.
When you open a file you have to have a file number that you want the
file associated with. In the example above this number is 1. This is
called many times the "file number". Whenever you do something with an
opened file you have to use the file number.
There are more things than reading from a file and writing to a file.
You can read from a certain position on a file and you can write to a
certain position. You can determine the length of a file and dates and
times the file has, like last time it was accessed, modified or created.
-----
[\[\<\<\<\]](ug_12.md) [\[\>\>\>\]](ug_12.2.md)
# Truncating a file
[\[\<\<\<\]](ug_12.9.md) [\[\>\>\>\]](ug_12.11.md)
When you write to a file it is automatically extended by the operating
system and grows. On the other hand files do not shrink automatically.
When you write into file before the position of the end of the file the
bytes after the written region are still valid and remain in the file.
The exception is when you open a file for `output`. In that case the
original file is deleted and you can start to write of length zero,
However you may want to open a binary file, read from it, write into it
and sometimes you may want to decrease the size of the file. The
instruction truncate does it for you. The syntax of the instruction is:
truncate#fn,size
Where `fn` is the opened file number, and size is the new size of the
file in terms of records. The content of the file after the position
`size-1` is lost. Note that the argument to the instruction truncate is
the desired length of the file, which is the position of the last byte
or record plus one. Positions start with zero offset just like in file
positioning statements.
If the specified length is larger than the actual length of the file
then the file is elongated with bytes containing the value zero padded
to the end of the file.
-----
[\[\<\<\<\]](ug_12.9.md) [\[\>\>\>\]](ug_12.11.md)
# Deleting a file or directory
[\[\<\<\<\]](ug_12.10.md) [\[\>\>\>\]](ug_12.12.md)
Using the command truncate you can truncate a file to size zero, but the
empty file is still there. To totally delete a file you have to use the
command `DELETE`. The syntax of the command is
```
delete expression
```
where the expression is the name of the file or directory to be deleted.
When issuing this command to delete a directory the directory should be
empty otherwise the command fails and an error occurs. There is another
command with the syntax
deltree expression
that deletes a directory even if the directory is not empty. Note that
this command is very dangerous, because it forcefully deletes full
directory trees and therefore you have to use this format of the command
with exceptional great care.
-----
[\[\<\<\<\]](ug_12.10.md) [\[\>\>\>\]](ug_12.12.md)
# Creating a directory
[\[\<\<\<\]](ug_12.11.md) [\[\>\>\>\]](ug_12.13.md)
Although the `OPEN` statement automatically creates the directory for
the file whenever you want to create a new file you may want to create a
directory without creating a file in it. For the purpose the statement
`mkdir` can be used. The syntax of the command is very simple:
mkdir expression
The expression should result a string, which is the directory to be
created. The command recursively creates the directories that do not
exist by the time the command is executed and need creation in order to
create the final directory. For example you can issue the command
mkdir "/usr/bin/scriba"
without issuing the commands
mkdir "/usr"
mkdir "/usr/bin"
The directories \``/usr`' and \``/usr/bin`' are automatically created in
the unlikely case they did not exist.
The command executes without error if the directory is created or if the
directory already existed. If the directory can not be created an error
occurs. The reason for directory creation failure can be numerous. The
most typical is access control prohibiting for the process directory
creation. Another usual problem is when some sub-path of the desired
directory already exists, but is a file. For example we want to create
the directory /usr/bin/scriba/exe and /usr/bin/scriba already exists and
is a plain file.
-----
[\[\<\<\<\]](ug_12.11.md) [\[\>\>\>\]](ug_12.13.md)
# Setting file parameters
[\[\<\<\<\]](ug_12.12.md) [\[\>\>\>\]](ug_12.14.md)
Files usually have parameters in addition to the information contained
in the file itself. Such information is the owner of the file, the group
the file belongs to, creation time, modify time, access time, change
time and so on. To set these parameters of a file ScriptBasic provides
the command `set file`.
The syntax of the command is
set file filename parameter=value
where \``filename`' is the name of the file for which the parameter is
to be set, the `parameter` is the name of the parameter to change and
value is the desired value of the parameter.
The `parameter` can be
- `Owner` to set the owner of the file. This owner is a user of the
system identified by its login name. The owner of a file is usually
the person who ran the program that created the file. The super user
or administrator can change the owner of a file passing the
ownership to any other legal user. The use of the command can be
different on Windows NT from UNIX. Windows NT uses different NT
domains and user names can be noted in the form `DOMAIN\USER`. The
owner of a file on a machine belonging to one domain can be a user
from another domain (that the domain the machine belongs to
hopefully trusts). If the user name specified in the command `chown`
contains a `\` character (do not forget to use `\\` in the strings)
the user name is looked up in the domain specified in the name. If
the name does not contain any domain specification the local user
database is used.
- `CreateTime` to set the creation time of a file. The value for the
time should be expressed in terms of seconds since January 1, 1970.
00:00. This is the usual measure of time on UNIX systems. This
parameter does not exist on UNIX operation systems. UNIX maintains
only modification, access time and change time, therefore setting
`CreateTime` is not possible under UNIX and trying to perform the
set file command for this parameter results error with error code
`sbErrorNotimp`.
- `ModifyTime` to set the last modification time of a file. The value
for the time should be expressed in terms of seconds since January
1, 1970. 00:00. This is the usual measure of time on UNIX systems.
- `AccessTime` to set the last access time of a file. The value for
the time should be expressed in terms of seconds since January 1,
1970. 00:00. This is the usual measure of time on UNIX systems.
If the file does not exist or some other condition prevents the
successful change of the parameter the program generates an error with
one of the error codes `sbErrorSetCreateTime`, `sbErrorSetModifyTime`,
`sbErrorSetAccessTime`.
Note that Windows NT file system (NTFS) and UNIX operating systems store
file time values in GMT. Do not forget to convert the local time to GMT
if needed when changing some of the file time values. Other file
systems, like FAT may store the file times as local time. Be careful.
-----
[\[\<\<\<\]](ug_12.12.md) [\[\>\>\>\]](ug_12.14.md)
# Open directory
[\[\<\<\<\]](ug_12.14.md) [\[\>\>\>\]](ug_12.14.2.md)
The syntax of the command open directory
is
OPEN DIRECTORY dir_name PATTERN pattern_value OPTION option_value AS dir_number
The parameter `dir_name` should be an expression evaluating to a string,
which is the name of the directory for which the listing is needed. It
can be absolute path or relative to the current working directory. It
may but need not contain the trailing slash.
The parameter `pattern_value` should be an expression evaluating to a
string. When the list of the files is gathered this pattern is used to
select the files. Only the files matching the pattern will be included
in the list of files. The pattern matching uses the same algorithm as
the operator `LIKE`. Altering the joker and wild characters for the
operator `LIKE` also alters the pattern matching mechanism of file
selection. The command `OPEN DIRECTORY` leaves the pattern matching
memory in a non-matched state. In other words the function `JOKER` will
return the `undef` value after executing an `OPEN DIRECTORY` command
until the next `LIKE` operator is executed.
Pattern matching and selection is done during the execution of the
command `OPEN DIRECTORY` the other file list handling commands and the
function `NextFile` do not interfere with the pattern matching.
Pattern matching while building up the list is a time and processor
consuming tasks. If you do not want to perform pattern matching just
getting all the file names use value `undef` or empty string as pattern
value. In either case pattern matching is skipped during file list build
up. Using `*` to get all files is a bad idea unless your aim to make
your CPU generate heat.
Note that pattern matching can either be case sensitive or insensitive
based on the setting of the option \``compare`'. This option alters the
behavior of pattern matching during file list build up on UNIX systems,
but not under Windows. Under Windows NT pattern matching during file
list build up is always case insensitive, no matter how the option
\``compare`' is set.
The parameter `option_value` should be an expression evaluating to an
integer value. This value is used to drive the behavior of the command.
Each bit of the value has a special meaning. To set the correct value
ScriptBasic predefines several global constants that you can use. These
constants can be used in this value. If more than one constant is needed
you have to use the operator `and` to connect them. The predefined
constants and their corresponding meanings are:
- `SbCollectDirectories` Collect the directory names as well as file
names into the file list.
- `SbCollectDots` Collect the virtual . and .. directory names into
the list.
- `SbCollectRecursively` Collect the files from the directory and from
all the directories below.
- `SbCollectFullPath` The list will contain the full path to the file
names. This means that the file names returned by the function
`NextFile` will contain the directory path specified in the open
directory statement and therefore can be used as argument to file
handling commands and functions.
- `SbCollectFiles` Collect the files. This is the default behavior.
- `SbSortBySize` The files will be sorted by file size.
- `SbSortByCreateTime` The files will be sorted by creation time.
- `SbSortByAccessTime` The files will be sorted by access time.
- `SbSortByModifyTime` The files will be sorted by modify time.
- `SbSortByName` The files will be sorted by name. The name used for
sorting will be the bare file name without any path even if the