THE SCRIPT LANGUAGE

The script language interpreted by "Terminal" is a subset of C with many
specialized intrinsic (built-in) functions. Please read a C reference book
to learn the C syntax, or see the enclosed script examples to get a feeling
of the language. I will not write a book about programming in C here, only
tell you the essentials.

PROGRAM

A program is recognized as a script if it is in a text file,  Spaces, tabs
and carriage return characters are considered to be white space.
No identifier and no keyword can be separated by white space.
A program consists of: comments, global variable definitions and function
definitions. Everything included between "/*" and "*/" is considered a comment
and will not be interpreted. Comments cannot be nested. The "/*" and "*/" are
not recognized as comment delimiters inside string or character constants.
Global variables are those variables that are known to all functions, unless
their names are reused as local variables.
Global variables can be initialized using any expression that involves
either constants or other globals that are already defined at that point.
Function definitions can appear in any order and their must be at least
one function called "main" with no parameters. It is this function that
is called when the script is started. Every function is supposed to return
an integer value as result. If there is no return statement in a function,
0 will be returned. Functions can be called recursively. There are many
built-in functions that are already defined when the script is started.

This is an example of a simple script that displays the message "The number
is 123" in the terminal window:

    int Number = 123;	/* This is a global variable */

    main ()	/* Every script must have a main() function */
    {
	/* cprintf() is a built-in function */
	cprintf("The number is %i\r\n", Number);
    }


IDENTIFIERS

An identifier is a sequence of letters and digits; the first character must
be a letter. The underscore "_" counts as a letter. An identifier can be of
any length up to 255 characters. All characters are significant and are
case sensitive. There are three types of identifiers: keywords, function
names, variable names. The keywords are: "break", "char", "else", "for",
"if", "int", "return", "while", "do", "continue", "switch", "case", "default".


CONSTANTS

An integer constant is a sequence of decimal digits, or 0x followed by up
to 8 hexadecimal digits. An integer value is represented internally by 4
bytes (32 bits). A minus sign before a constant is considered as an unary
operator, not a part of the constant itself. A character constant is a
sequence of 1 to 4 characters enclosed in single quotes. Character
constants are converted to integer values, the byte values corresponding to
the ASCII codes of the characters. A string constant is a sequence of
characters enclosed in double quotes. String constants are automatically
terminated by a NULL character. The value of a string constant is the
address of the first character. Some examples of valid constants:

    1239506	       <---   decimal digits
    0xABCD1234	       <---   hexadecimal digits
    037756	       <---   octal digits
    0b010101	       <---   binary digits
    'a'
    'TEXT'
    "An apple a day keeps troubles away"

In character and string constants the backslash "\" is used as an escape
sequence according to the following table:

    LF	    0x0A    \n
    TAB     0x09    \t
    FF	    0x0C    \f
    BELL    0x07    \a
    BS	    0x08    \b
    CR	    0x0D    \r
    VT	    0x0B    \v
    NULL    0x00    \0
    any     0x..    \x..    (at most 2 hex digits)
    any     0...    \...    (at most 3 octal digits)

If the character following a backslash is not one of those specified the
backslash is ignored. This can be used to represent the backslash itself,
to put a single quote into a character constant or to put a double quote
into a string constant. Some examples;

    "Going to the next line...\r"
    '\0'
    "This is a single backslash: \\"
    "\"Hello world!\""
    '\''
    '\x03'  /* That's a control-C */
    '\x3'               .
    '\003'              .
    '\03'               .
    '\3'                .

VARIABLES

There are four types of variables: characters, integers, pointers and
arrays. Integers represent 32 bit signed values and characters 8 bit signed
values. Pointers hold the 32 bit address of integers, characters or other
pointers. Arrays are more or less equivalent to pointers. The following
examples show how variables are defined:

    char c;	/* "c" is a character variable */
    int n;	/* "n" is an integer variable */
    char *ptr;	/* "ptr" is a pointer to characters */
    char **hdl; /* "hdl" is a pointer to character pointers */
    int *p;	/* "p" is a pointer to integers */
    int **q;	/* "q" is a pointer to integer pointers */
    char a[80]; /* "a" points to an array of 80 characters (80 bytes) */
    int b[10];	/* "b" points to an array of 10 integers (40 bytes) */
    char *c[5]; /* "c" points to an array of 5 character pointers (20 b) */
    int *d[5];	/* "d" points to an array of 5 integer pointers (20 b) */

Variable declarations can be grouped together like this:

    char c, *ptr, **hdl, a[80], *c[5];
    int n, *p, **q, b[10], *d[5];

Variables can be initialized using any legal expression, not only
constants. Arrays can only be initialized at the global level, i.e. outside
of function definitions. Initialized arrays must not include their size
between the square brackets, the size is calculated based on the
initializing values.

    int c = 'x';      putch(c);  get correct result
    char c; c = 'x';  putch(c);  get correct result
    char c = 'x';     putch(c);  get wrong result but standard C is correct
    int i; i = 10-3-2-1;   cprintf("%d\r\n", i);  get wrong result
    int i; i = 10-(3+2+1); cprintf("%d\r\n", i);  get correct result
    int i; i = 5-3+1;   cprintf("%d\r\n", i);  get wrong result
    int i; i = (5-3)+1; cprintf("%d\r\n", i);  get correct result
    int i; i = 5-(3-1); cprintf("%d\r\n", i);  get correct result
    char ccc[5][5];   illegal declaration but standard C is correct
    char *ccc[5];     correct

    int n = -123;
    int m = n * 10;	/* "m" is set to -1230 */
    char *digits = "0123456789";
    char message[] = "This is a character string";
    char *messages[] =	/* Array of strings */
	{ "This is string #1", "Another string", "and so on..." };
    int a[] = { 1, 2, 3, 4, 5 };    /* Array of 5 integers */


EXPRESSIONS

The following is a list of the supported operators that build up an
expression. The list is by increasing precedence. Normally operators group
left to right unless otherwise noted below. Note that the assignment is an
operator, that an expression may contain several assignments, and that an
assignment returns a value. Logical and numerical operators can be freely
mixed, everything not zero is considered to be true. The precedence level
can be changed by using parentheses. The boolean operators will return 1 as
true.

Assignment			    =			    (right to left)

Conditional operators		    ? : 		    (right to left)

Logical OR			    ||

Logical AND			    &&

Bitwise AND, XOR, OR		    &	^   |

Equal, not equal		    ==	!=

Relational operators		    <	<=  >	>=

shift left, shift right 	    <<	>>

Add, subtract			    +	-

Multiply, divide, modulo	    *	/   %

Logical NOT, one's complement,
increment, decrement, unary minus,
indirection, address of 	    !  ~  ++  --  -   *   &   (right to left)
Function call, array element	    ()	[]

The bitwise operations are limited to processing integer variables and integer
value. (Standard C has no this limitation)
The increment or decrement operators can be used before or after a
variable. If the operator comes before the variable (preincrement,
predecrement) the variable is incremented, or decremented, and then the
variable's value is used in the expression evaluation. If the operator
comes after the variable (postincrement, postdecrement) the current value
of the variable is used in the expression evaluation, and then the variable
is incremented, or decremented.

Array subscripts start with 0. There is no runtime check of array
boundaries. An array subscript can be any valid expression. Some examples:

    char a[80];
    c = a[0];			    /* The first element */
    c = a[79];			    /* The last element */
    c = a[i = (79 - Func(x)*3)];    /* Expression as subscript */

For pointer arithmetic the following rules apply: if an integer value is
added or subtracted from a pointer (a pointer is an address) then the
integer value is first scaled depending on what the pointer is pointing to:
1 for characters, 4 for integers, 4 for pointers. If two pointers are
subtracted the result is scaled in the same way and yields an integer value
representing the number of objects separated by the two pointers. The two
pointers must point to the same type of objects.

A function identifier without a parameter list in an expression results in
the address of the function being used. If there is a parameter list, the
function is called and the integer value returned by the function is used.
Functions can also be called indirectly, using any expression that yields a
valid function address followed by a parameter list. Some examples:

    int pf;	    /* "int" can be used as function pointer */
    int i;
    pf = Func;	    /* "pf" will contain address of function "Func" */
    i = Func();     /* "i" gets function result */
    i = (pf)();     /* "i" gets function result */


FUNCTIONS

A function definition can only occur in the outer, global level. A function
cannot be defined inside another function. All functions are supposed to
return integers. A function definition consists of the function name,
followed by a parameter definition list enclosed in parentheses, followed
by a compound statement. The parameter definition list describes the
function parameters. These parameters are considered as local variables
inside the function. Example:

    /* The following function takes 3 parameters: a character, an integer
    and a character pointer. It always returns the value 123. */

    Function (char c, int i, char *p)
    {
	/* ... */
	return 123;
    }

A function call consists of the function name followed by a parameter list.
The parameter list is a comma separated list enclosed in parentheses of
expressions. All parameters are passed by value. There is no verification
if the number of parameters is correct or if the values passed to a
function correspond to the types of the declared parameters. Example:

    i = Function ('x', 4567 + x, "Hello");


STATEMENTS

A compound statement starts with an open brace "{" and terminates with a
closing brace "}". There is an optional variable definition part followed
by a list of statements. Variables defined inside a compound statement are
local to that compound statement (block).

A statement can be:
    compound statement
    expression ;
    if ( expression ) statement
    if ( expression ) statement else statement
    expression1 ? expression2 : expression3
    while ( expression ) statement
    do statement while ( expression );
    switch ( expression ) statement
    for ( opt expr1 ; opt expr2 ; opt expr3 ) statement
    break ;
    return ;
    continue ;
    return expression ;
    ;

The two forms of the conditional statement are:
    if ( expression ) statement
    if ( expression ) statement else statement
In both cases the expression is evaluated and if it is nonzero, the first
substatement is executed. In the second case the second substatement is
executed if the expression is 0. The "else" ambiguity is resolved by
connected an "else" with the last encountered "else"-less "if".

The "conditional expressions" has the form:
    expression1 ? expression2 : expression3
A conditional expression is a compound expressions that contains a condition
(expression1), expression2 to be evaluated if the condition has a nonzero
value, and expression3 to be evaluated if the condition has a zero value.
The conditional expression contains one two-part operator. The ? symbol
follows the condition (expression1), and the : symbol appears between the
two action expressions. All expressions between the operators ? and : are
treated as one expression.

The "while" statement has the form:
    while ( expression ) statement
The substatement is executed repeatedly so long as the value of the
expression remains nonzero. The test takes place before each execution of
the statement.

The "switch" statement has the form:
    switch ( expression ) statement
If no 'case' label matched, the sub-statement pointed to by the 'default'
label will be used as the entry point. If no 'default' label is found,
"terminal" will stop running the script. (but the statement associated with
the 'switch' is simply ignored by standard C programming language)

The "for" statement has the form:
    for ( opt expr1 ; opt expr2 ; opt expr3 ) statement
This statement is equivalent to:
    expression1 ;
    while ( expression2 ) {
	statement
	expression3;
    }
Thus the first expression specifies initialization for the loop, the second
specifies a test, made before each iteration, such that the loop is exited
when the expression becomes 0; the third expression often specifies an
incrementation which is performed after each iteration. Any or all of the
expressions may be dropped. A missing expression2 makes the implied "while"
clause equivalent to while(1); other missing expressions are simply dropped
from the expansion above.

The statement
    break ;
causes termination of the smallest enclosing "while" or "for" statement;
control passes to the statement following the terminating statement.

A function returns to its caller by means of the "return" statement, which
has one of the forms:
    return ;
    return expression ;
In the first case the returned value is undefined. In the second case the
value of the expression is returned to the caller of the function. The
expression must be enclosed in parentheses that prevents from occurring
either "out of place: C" or "out of place: S" error, the 'C' means the
expression is a constant and 'S' means that is a string. Flowing off the
end of a function is equivalent to a return with no return value.

The null statement has the form
    ;
A null statement is useful to supply a null body to a looping statement
such as "while".

Note: Unlike standard C, logical expressions are completely evaluated, even
if their TRUEthness (different from 0) ore FALSEness (equal to 0) can be
determined before the whole expression is evaluated. In standard C that's
called short circuit boolean evaluation. For example in the statement
    if (dothis() && dothat())
	;
the functions dothis() and dothat() are always called in script C. In standard
C the function dothat() is only called if dothis() returns a non-zero
result.


PREPROCESSOR DIRECTIVES

// comment		: comment until end-of-line
/* comment */		: comment between /* and */
#include "filename"     : includes a file
#include <filename>	: includes a file from directory pointed to by SIC
			  variable
#define ident redef	: defines ident to expand to redef, or defines a macro

Please read the enclosed cpp.doc to learn the syntax of the preprocessor
directives.


INTRINSIC FUNCTIONS


Intrinsic functions are built-in and need not to be defined in the script.
They can be called by any script.

-- CONSOLE --

scanf
cprintf
sprintf
getch
ungetch
cputs
putch
cgets
editgets
getpos
setpos
disp_cursor
clrscr
attrib
update_status_bar
status_bar
title_bar

-- MEMORY --

malloc
free
stack

-- STRING  --

sscanf
atoi
itoa
strtol
strcat
strcmp
strncmp
strnicmp
stricmp
strcpy
strncpy
strncat
strlen
strchr
strrchr
strtok
strstr
strpbrk
strcspn
strspn
strlwr
strupr
strerror
tolower
toupper
ltrim
rtrim
strset
strnset
strlenset
DIM2_qsort
DIM2_qsort2
TimeFileName
hhmmss
yymmdd

-- STREAM  I/O --

capture
fopenread
ungetc
fprintf
fputc
fputs
fgetc
fgets
fscanf
fseek
ftell
fflush
feof
fileno

-- LOW LEVEL  I/O --

open
read
write
close
lseek
tell
eof

-- TIMER --

sleep
delay
timerstart
timerstop
timeout

-- COMM PORT I/O --

type
writechar
writechartimed
writebuffer
writebuffertimed
readchar
readchartimed
readbuffer
readbuffertimed
peekchar

-- MISC --
mathexpr (floating point numbers/expressions)
autofilename
show (watch)
nextline
view
access
remove
rename
chmod
chdir
getcwd
gethomedir
getdisk
setdisk
getenv
doskey
mapbuffer
system
bioskey
exit
sound
nosound
Test_prn
beep
CursorOn
CursorOff

================================================================================

All formatting functions ("sprintf", "cprintf", "fprintf", "type") use a
template string to specify the formatting to be done on the following
parameters.
Format specifiers begin with the character % and include zero or more of
the following conversion specification elements (optional fields are in
brackets):

    % [option flags] [field size] conversion

Some of these elements are optional, but if present, they must be specified
in the order in which they are described below.
Option flags (optional):
    -	Left adjust output in field, pad on right (default is to right
	justify).
    0	Use zero (0) rather than space for the pad character
Field size specification (optional):
    The minimum field width, expressed as a decimal integer. The
    corresponding parameter will be printed in a field at least this wide.
Conversion characters (required)
    c	Parameter is a character
    i	Parameter is an decimal integer
    d	Parameter is an decimal integer
    b	Parameter is an binary integer
    o	Parameter is an octal integer
    x	Parameter is an hexadecimal integer
    s	Parameter is a null terminated string
    %	Print a %, no parameter used
The format specification elements must correspond to the following
parameters. Some examples:
    char k, m[80];
    int n;
    type("Unrecognized character %c on line %i of file %s\r", k, n, m);

The following list describes all the existing intrinsic functions. They are
described in the so-called prototype format, i.e. the format you would have
to use to define them. E.g.
    xxxx (char *s, int i)
means that "xxxx" is a function taking 2 arguments, the first is a pointer
to a character and the second is an integer. Note that all functions return
integers, but the value returned is not necessarily meaningful for every
function.

:atoi
    long atoi(const char *s);
    Converts a string to a long
    On success, return the converted value of the input string.
    If the string can't be converted, returns 0.

:attrib
    void attrib(int def_attrib, int clr_attrib);
    def_attrib:  default writing attribute
    clr_attrib:  attribute for clearing window

:beep
    void beep(void);

:bioskey
    int bioskey(cmd);
    int cmd;
    - keyboard operations
    - 'cmd' = 0  return next keystroke if the lower 8 bits of the return
		 value are non-zero else the upper 8 bits are the extended
		 keyboard codes
	    = 1  test if key hit (0 = no, -1 = ctrl-brk pressed, else value)
	    = 2  return shift key status, where value is OR of:
		0x80 insert toggled   0x40 caps toggled  0x20 num lock toggled
		0x10 scrl lck toggled 0x08 ALT down	 0x04 CTRL down
		0x02 left shift down  0x01 right shift down

:capture
    Start/stop capture to text file. (needs 'show' function to receive data or
    uses 'fputc', 'fputs' and 'fprintf' function to save data)
    capture (int opt, char *name);
    result: file system error, 0 if no error, -1 if error
    opt:    0 = Close capture file
	    1 = Capture on, new file
	    2 = Capture on, append to existing file
    name:   This is the file name.

:CursorOn
    void CursorOn(int startline, int endline);
    set visible cursor and size.
    startline: starting scan line (0-13).
    endline: ending scan line (0-13).

:CursorOff
    void CursorOff(void);
    unset visible cursor.

:fopenread
    Open/close text file for reading only.
    fopenread (int opt, char *name);
    result: file system error, 0 if no error, -1 if error
    opt:    0 = Close file
	    1 = open file for reading
    name:   This is the file name.

:fputc
    void fputc(unsigned char c);
    capture character to capturing file.
    to prevent from capturing redundantly user should not use this function,
    when the script is already using 'show' function to receive data.

:fputs
    char *fputs(char *str);
    capture character string to capturing file.
    to prevent from capturing redundantly user should not use this function,
    when the script is already using 'show' function to receive data.

:fgets
    char *fgets(char *s, int n);
    - fgets reads characters from a default stream into the string s.
      It stops when reads  either n-1 characters or a newline character,
      whichever comes first.
    - newline character is retained and appends a null byte to 's' to mark
      the end of the string.
    - the default stream is opened by fopenread()
    - fgets returns the string pointed to by s.
    - On end-of-file or error, fgets returns null.

:fgetc
    int fgetc(void);
    - fgetc gets character from the default stream which opened by fopenread()
    - returns the character read (converted to an int)
    - On error, fgetc returns EOF (-1)

:scanf
:sscanf
:fscanf
    int scanf(const char *format, address1, address2, ...);
    - accepts input from keyboard
    WARNING: scanf often leads to unexpected results if you diverge from an
    expected pattern. You must teach scanf how to synchronize at the end of
    a line.
    The combination of cgets or fgets followed by sscanf is safe and easy, and
    therefore recommended over scanf.

    int sscanf(const char *buffer, const char *format, address1, address2, ...);
    - gets formatted input from a character string

    int fscanf(const char *format, address1, address2, ...);
    - gets formatted input from a stream which opened by fopenread()

    Remarks:
    The ...scanf functions do the following:
    1. Scan a series of input fields one character at a time.
    2. Format each field according to a corresponding format specifier passed
       in the format string *format.
    3. There must be one format specifier and address for each input field.
    4. Store the formatted input at an address passed as an argument following
       *format
    5. Please use format specifier %ld for integer address
    6. More ...scanf Topics:
       Please refer to other C document

    - On success, ...scanf functions return the number of input fields
      successfully scanned , converted, and stored.
      The return value does not include scanned fields that were not stored.
    - Return value = 0 if no fields were stored.
    - Return value = EOF if scanf or fscanf attempts to read at end-of-file, or
      sscanf attempts to read at end-of-string.

:feof
    int feof(void);
    - detects if end-of-file has been reached on a file stream which opened
      previously by fopenread()
    - once the indicator is set, read operations on the file return the
      indicator until rewind is called, or the file is closed.
    - returns zero if NOT eof, else non-zero

:fileno
    int fileno(void);
    - returns the file handle for the default stream which opened by fopenread()
    - error return undefined

:fseek
    int fseek(long offset, int whence);
    - repositions the file pointer of a default stream which opened by fopenread()
      to new position which is 'offset' bytes beyond file location given by 'mode'
    - mode is 0 (beginning of file or SEEK_SET), 1 (current position or
      SEEK_CUR), or 2 (end of file or SEEK_END
    - For text mode streams, offset should be 0 or a value returned by ftell
    - fseek discards any character pushed back by ungetc()
    - fseek(0,0) rewinds the file pointer and clears eof indicator
    - returns 0 if pointer moved OK, else non-zero

:ftell
    long ftell(void);
    - If the file is binary, ftell returns the current file pointer position in
      bytes from the beginning of the file
    - The value returned by ftell can be used in a subsequent call to fseek
    - the file is previously opened by fopenread()
    - -1L on error

:fflush
    int fflush(void);
    - writes the buffered output for the default stream to the associated
      file, the stream remains open after fflush has executed.
    - returns 0 on success or EOF (-1) on error

:fprintf
    char *fprintf (char *templ, ...);
    capture formatted character string to capturing file.
    templ: template string
    ...: variable number of arguments (maximum 9)

:autofilename
    char *autofilename(char *fname);
    get current date string to 'fname'.
    return the pointer to 'fname'.

:clrscr
    clears the window uses the default attribute
    void clrscr(void);

:cgets
    get string, echo chars to window
    int cgets (char *buffer);
    buffer: put the string here
    return 0 if press Esc key

:editgets
    get string, echo chars to window
    int editgets (char *buffer, int password_mode);
    buffer: buffer to receive string
    password_mode: set 1 (nonzero) to password mode, set 0 to normal mode.
    normal mode - available editing keys referring to editgets.sic
    besides tab key.
    password mode - '*' is echoed for all characters,
    only ESC, ENTER, BACKSPACE, and CTRL_BACKSPACE are active.
    return value: the edited string's length

:cputs
    writes a character string to a window with a specified attribute
    cputs (char *str);
    str: the string to write

:putch
    writes a character to a window with a specified attribute
    putch (int c);
    c: the character to write

:cprintf
    display formatted character string in the terminal window
    char *cprintf (char *templ, ...);
    templ:  template string
    ...:    variable number of arguments (maximum 9)

:getpos
    get the current position of cursor
    void getpos(int *row, int *col);

:setpos
    set the current position of cursor
    void getpos(int row, int col);

:disp_cursor
    function sets the visible cursor to a position within the window
    specified. If the row number is less than 0, the current writing
    position is used as the cursor position.
    disp_cursor(int row, int col);

:delay
    void delay(unsigned milliseconds);
    suspends execution for interval (milliseconds);

:DIM2_qsort
    void DIM2_qsort(char *item[], int left, int right, int sign, int caps_sw);
    quick sorts text string in the two dimension array of pointer
    char *item[] - the two dimension array of pointer
    int left - the starting index of array element (0 - n)
    int right - the ending index of array element
    int sign - if sign = 1 then sorts ascendingly, if sign = -1 sorts
    descendingly
    int caps_sw - if caps_sw != 1 then case insensitive, if caps_sw = 1 then
    case sensitive

:DIM2_qsort2
    void DIM2_qsort2(char *item[], int left, int right, int sign, int caps_sw ,
    int begin_no, int compn);
    quick sorts text string in the two dimension array of pointer that only for
    the specified position and range
    char *item[] - the two dimension array of pointer
    int left - the starting index of array element (0 - n)
    int right - the ending index of array element
    int sign - if sign = 1 then sorts ascendingly, if sign = -1 sorts
    descendingly
    int caps_sw - if caps_sw != 1 then case insensitive, if caps_sw = 1 then
    case sensitive
    int begin_no -  which position to start comparing (1 - n)
    int compn - how many characters to compare

:getch
    int getch(void);
    - function which returns next character from console without echoing

:itoa
    char *itoa(long value,char *string,int radix);
    - converts 'long value' to 'string' where 'radix' specifies base (2-36) for
      conversion

:ltrim
    remove leading whitespace from a string
    char *ltrim(char *str);

:rtrim
    remove trailing whitespace from a string
    char *rtrim(char *str);

:sprintf
    formatted conversion of values into a string
    char *sprintf (char *str, char *templ, ...);
    str:    string for result
    templ:  template string
    ...:    variable number of arguments (maximum 8)

:free
    dispose of the memory allocated by the malloc() function
    free (void *p);
    p: pointer returned by previous call to malloc() function

:malloc
    void *malloc(size);
    unsigned size;
    - allocates memory of length 'size' in bytes
    - returns pointer if successful, else 0

:access
    int access(filename,amode);
    char *filename, int amode;
    - checks 'filename' for existence & R/W access
    - amode = 06 -- check for R/W permission
	      04 -- check for R
	      02 -- check for W
	      01 -- execute (ignored)
	      00 -- check if filename exists
    - 'filename' can be directory
    - returns 0 if OK; -1 on error;

:chmod
   int chmod(const char *filename, int amode);
   Sets file access permissions
   - changes access mode of file according to mask given by 'amode', where
     'amode' = S_IWRITE, S_IREAD, or S_IWRITE | S_IREAD
     #define S_IREAD 0x0100  /* user defines in script */
     #define S_IWRITE 0x0080 /* user defines in script */
   - returns 0 if OK; else -1

:open
    int open(const char *pathname, const char *mode);
    mode: may use r, w, +, t, b, a, c as following,
    r : open "O_RDONLY" mode
    w : open "O_WRONLY" mode
    + : open "O_RDWR" mode
    t : open text mode (default mode)
    b : open binary mode
    a : open "O_CREAT | O_APPEND" mode
	if file exists then append to file, otherwise create new one
    c : open "O_CREAT | O_TRUNC" mode
	if file exists, truncate length to zero, else create new file
    - returns a non-negative integer as the file handle, or -1 on error

:read
    int read(fd, buf, size);
    int fd, size;
    char *buf;
    - reads 'size' bytes from file handle 'fd' into 'buf'
    - _read() is direct call to MS-DOS read system all
    - read() removes CRs & reports EOF on a CNTL-Z for file
      opened in text mode.
    - returns actual number of bytes read, 0 on EOF, or -1 on
      error

:write
    int write(fd, buf, count);
    int fd, count;
    char *buf;
    - write() write a buffer 'buf' of data to file or
      device named by 'fd', writing 'count' of bytes.
    - for text files, write converts LF to CR-LF pair on output.
    - returns count of bytes written out (excluding any CR's
      generated for a text file), or -1 on error

:close
    int close(int fd);
    - closes file 'fd' where 'fd' is file handle from open().
    - write a CTL-Z to a text file on closing.
    - returns 0 if OK; else -1.

:lseek
    long lseek(fd, offset, mode);
    int fd, mode;
    long offset;
    - sets file associated with 'fd' to 'offset' from beginning of file
      ('mode' = 0) , current position ('mode' = 1),
      or end of file ('mode' = 2)
    - returns -1 on error

:tell
    long tell(int handle);
    - returns offset of file associated with 'fd' from beginning of file
    - returns -1 on error

:eof
    int eof(int handle);
    - returns 1 if the file associated with handle has reached end-of-file.
    - returns 0 if not end of file
    - returns -1 if bad file number

:sleep
    void sleep(unsigned seconds);
    - causes calling program to be suspended for 'seconds' of time

:sound
    void sound(unsigned frequency);
    - turns the PC speaker on at the specified frequency

:nosound
    void nosound(void);
    - turns the PC speaker off

:stack
    return free memory available for script heap and stack
    stack (void);
    result: combined free heap and stack space (bytes)

:status_bar
    void status_bar(void);
    redraw status bar if setting of terminal is 24 rows

:update_status_bar
    void update_status_bar(void);
    updates display on status bar if setting of terminal is 24 rows

:script_title
    void script_title(char *str, int def_attrib, int clr_attrib);
    str: the string to display
    def_attrib:  default writing attribute
    clr_attrib:  attribute for clearing window

:mathexpr
   int mathexpr(char *inbuf, char *outbuf);
   inbuf: char buffer to get input string
   outbuf: char buffer to get output string
   return 0 if successful else return -1
   The function mathexpr takes equations in the form of c strings and
   returns the char string of the value of the equation after parsing
   and performing the necessary calculations.
   example:
	  char outbuf[128];
	  mathexpr("2 + 3/4 - atan(1)", outbuf);
	 ( if successful will set "1.964602" string to outbuf )
   the operator precedence:
				  [ ]
				  ( )
				  ? :
				  !
				  * / %
				  + -
				  == != < > <= >=
				  &
				  |

   math functions:  sqrt sin cos tan atan log exp abs floor pow
   constants:  pi, e

:strcat
    char *strcat(char *dest, const char *src);
    - strcat appends a copy of src to the end of dest
    - strcat returns a pointer to the concatenated strings

:strchr
    char *strchr(const char *str, unsigned char c);
    - scans a string for the first occurrence of a given character c
    - the null-terminator is considered to be part of the string
    - returns pointer the first occurrence of character in str,
      or 0 (a null pointer) if the given character c is not present in str.
    The terminating null-character is considered part of the string.
    Therefore, it can also be located to retrieve a pointer to the end of
    a string.

:strcmp
    int strcmp(const char *str1, const char *str2);
    - compares 'str1' to 'str2'
    - returns < 0 if str1 < str2, = 0 if str1 == str2, or
      > 0 if str1 > str2, using a unsigned comparsion

:strcpy
    char *strcpy(char *dest, const char *src);
    - copies string src to dest, stopping after the terminating null character
      has been copied.
    - returns dest

:stricmp
    int  stricmp(const char *str1, const char *str2);
    - compares 'str1' to 'str2' without case sensitivity
    - returns < 0 if str1 < str2, returns 0 if str1 == str2, or
      > 0 if str1 > str2, using a unsigned comparsion

:strlen
    unsigned strlen(const char *str);
    - returns number of characters in 'str', not counting the
      terminating null character

:strlenset
    char *strlenset(char *str, int ch, int len);
    - if strlen(str) > len then truncate str to len bytes
    - if len > strlen(str) then appends (len -strlen(str)) bytes 'ch'

:strlwr
    char *strlwr(char *str);
    - converts str to all lower case
    - returns a pointer to the string str

:strncat
    char *strncat(char *destin, const char *source, unsigned maxlen);
    - appends up to 'maxlen' characters of 'source' to 'destin'
      and then appends a null character

:strncmp
    int  strncmp(const char *str1, const char *str2, unsigned maxlen);
    - compares 'str1' to 'str2' up to 'maxlen' characters
    - returns < 0 if str1 < str2, returns 0 if str1 == str2, or
      > 0 if str1 > str2, using a unsigned comparsion

:strncpy
    char *strncpy(char *destin, const char *source, unsigned maxlen);
    - copies at most maxlen characters of source to destin,
      truncating or null-padding destin
    - 'destin' might not be null-terminated if the length of source is
      maxlen or more

:strnicmp
    int  strnicmp(const char *str1, const char *str2, unsigned maxlen);
    - compares 'str1' to 'str2' up to 'maxlen' characters
    - case is ignored
    - returns < 0 if str1 < str2, = 0 if str1 = str2, or
      > 0 if str1 > str2, using a signed comparsion

:strnset
    char *strnset(char *str, int ch, unsigned n);
    - sets the first n characters of str to ch
    - if n > strlen(str) then strlen(str) replaces n
    - copying stops when n characters have been set, or when a null
      character is found
    - returns str

:strrchr
    char *strrchr(const char *str, unsigned char c);
    - finds the last occurrence of c in str
    - scans a string in reverse direction, looking for a specific
      character c
    - the null-terminator is considered to be part of the string
    - returns a pointer to last occurrence of the character c in str,
      if not found, the function returns 0 (a null pointer).
    The terminating null-character is considered part of the string.
    Therefore, it can also be located to retrieve a pointer to the end of a string.

:strset
    char *strset(char *str, int ch);
    - sets all characters in the string str to the character ch
    - returns str

:strstr
    char *strstr(const char *str1, const *str2);
    - scans str1 for the first occurrence of the substring str2.
    - returns a pointer to the first occurrence of str2 in str1,
      or 0 (a null pointer) if str2 is not part of str1.
    The matching process does not include the terminating null-characters.

:strpbrk
    char *strpbrk(const char *str1, const *str2);
    - returns a pointer to the first occurrence in str1 of any of the
      characters that are part of str2, or a null pointer if there are
      no matches.
    The search does not include the terminating null-characters.
    - return value: a pointer to the first occurrence in str1 of any of
      the characters that are part of str2, or a null pointer if none of
      the characters of str2 is found in str1 before the terminating
      null-character.
    If none of the characters of str2 is present in str1, a null pointer
    is returned.
    Both strcspn and strpbrk perform the same function. Only the
    return values differ.

:strcspn
    unsigned strcspn(const char *str1, const *str2);
    - scans str1 for the first occurrence of any of the characters
      that are part of str2, returning the number of characters of
      str1 read before this first occurrence.
    The search includes the terminating null-characters, so the function
    will return the length of str1 if none of the characters of str2 are
    found in str1.
    - return value: the length of the initial part of str1 not containing
      any of the characters that are part of str2.
    This is the length of str1 if none of the characters in str2 are found
    in str1.
    Both strcspn and strpbrk perform the same function. Only the
    return values differ.

:strspn
    unsigned strspn(const char *str1, const *str2);
    - find the initial segment of string str1 that consists entirely
      of characters NOT from string str2.
    - return value: the length of the initial portion of str1 containing
      only characters that appear in str2.
    Therefore, if all of the characters in str1 are in str2, the function
    returns the length of the entire str1 string, and if the first character
    in str1 is not in str2, the function returns zero.
    The function strspn is the complement of strcspn.

:strtol
    long strtol(const char *str, char **endptr, int radix);
    - converts character string str to a long integer value
    - stops reading at the first character that cannot be interpreted
      as part of a long value, returning in *endptr
    - 'str' must have format:
       [ws][sn][0][x][ddd]
       where [ws] = optional whitespace
             [sn] = optional sign (+ or -)
             [0]  = optional zero (0)
             [x]  = optional x or X
             [ddd]= optional digits
     - 'radix' is between 2 and 36; if 0, first few characters
       of 'str' determines base(radix) to be used (oct,hex or dec); any
       other value of 'radix' is illegal
     - returns the value of str as a long integer
     - returns 0 if error

:strtok
    char *strtok(char *str1, const char *str2);
    - scans str1 for the first token not contained in str2
    - strtok considers the string str1 to consist of a sequence of
      zero or more text tokens, separated by spans of one or more
      characters from the separator string str2
    - the first call to strtok returns a pointer to the first character
      of the first token in str1, and writes a null character into str1
      immediately following the returned token.  Subsequent calls
      with null for the first argument will work through the string
      str1 in this way until no tokens remain.
    - the separator string str2, can be different from call to call
    - returns a pointer to the token found in str1
    - when there are no more tokens, returns a null pointer 0

:strupr
    char *strupr(char *str);
    - converts str to all uppercase
    - returns a pointer to the string str

:strerror
    char *strerror(void);
    - returns a pointer to the generated message string.
    The string pointed to may be overwritten by a subsequent call to
    strerror().

:system
    int system(const char *command);
    - invokes MS-DOS COMMAND.COM to execute 'command', returning
      exit status of COMMAND.COM.  The COMSPEC environment variable
      is automatically searched if necessary.
    On success, returns 0
    On error, returns -1

:exit
    void exit(void);
    - alert, and terminates program

:show
    int show(int find, char *string1, char *string2, char *string3,
    char *string4, char *string5);
    read data from com port and output to screen
    if "find" sets to 0 then read data from com port and display to console
    if "find" sets to 1 then watch for one of the strings specified above.
    if string1 found return 16 (binary ==> 10000)
    if string2 found return 8  (binary ==> 01000)
    if string3 found return 4  (binary ==> 00100)
    if string4 found return 2  (binary ==> 00010)
    if string5 found return 1  (binary ==> 00001)
    if all strings are not found then return 0.
    user can use bitwise AND to check if compound strings or one of arrived
    strings are received.

:nextline
    char *nextline(char  *string, int maxsize, int delay);
    returns a line of characters from the com port.
    if a CR has not been received since the last nextline, the program
    accumulates characters until a CR is encountered, the amount of time
    specified in delay is reached, or maxsize characters has been accumulated.
    the resulting string is then returned and processing continues, If no
    characters have been received, a null string is returned.
    delay is the amount of time to wait for the next character. If delay is
    reached between the receipt of characters, the characters accumulated to
    that point are returned and script execution continues.
    the time specified in delay is expressed in milliseconds, and -1 is forever.
    maxsize is the size of the buffer of the string to accumulate before
    continuing if a CR is encountered.
    a line feed following a CR is ignored.

:tolower
    int tolower(c);
    int c;
    character converted to lowercase

:toupper
    int toupper(c);
    int c;
    character converted to uppercase

:hhmmss
    char *hhmmss(char *str);
    put PC's time to str with type "HH:MM:SS".

:yymmdd
    char *yymmdd(char *str, int sel);
    if sel sets to 1 then put PC's current time to str with type "yymmdd".
    if sel sets to 2 then put PC's current time to str with type "yy.mm.dd".
    if sel sets to 3 then put PC's current time to str with chinese type.
    if sel sets to 4 then put PC's current time to str with type "yyyy.mm.dd".

:TimeFileName
    char *TimeFileName(char *path, char *filename, char *ext_name);
    set filename with current PC's time.

:Test_prn
    int Test_prn(void);
    to test printer ready (return 1) or not (return 0)

:timerstart
    void timerstart(int nTimer, long milliseconds);
    to start a timer counter
    nTimer is limited from 2 to 7

:timerstop
    void timerstop(int nTimer);
    to stop a timer counter
    nTimer is limited from 2 to 7

:timeout
    int timeout(int nTimer);
    a timer counter if timeouts or not (return 1 or return 0)
    nTimer is limited from 2 to 7

:ungetch
    int ungetch(int ch);
    - pushes a character back to the keyboard buffer
    On success, returns the character ch.
    On error, returns -1.

:ungetc
    int ungetc(int c);
    Pushes a character back into input stream which opened by fopenread()
    This character will be returned on the next call to fgetc for that stream
    On success, ungetc returns the character pushed back
    On error, ungetc returns EOF (-1)

:update_timers
    void update_timers(void);
    update timer data on status_bar

:view
    void view(char *filename, int from);
    browse a text file
    filename : file name
    from : 0 read from first page, 1 read from last page

:chdir
   int chdir(const char *path);
   - changes current working directory to 'path'. Drive can be specified
     also, but this changes only the current directory on that drive; it
     doesn't change the active drive.
   - On success, returns 0.
   - On error, returns -1.

:getcwd
    char *getcwd(char *buf,int n);
    - gets full path name of current working directory up to 'n' bytes,
      stored into 'buf'
    - returns 'buf' pointer, else 0

:gethomedir
    char *gethomedir(char *hdir);
    gets full path name of home directory to 'hdir'.
    return the pointer to 'hdir'.

:getdisk
    int getdisk(void);
    - returns the current drive number ( 0 = A, 1 = B, 2 = C, 3 = D, etc.)

:setdisk
    int setdisk(int drive);
    - set current drive to 'drive' ( 0 = A, 1 = B, 2 = C, 3 = D, etc.)
    - returns the total number of drives available

:getenv
    char *getenv(const char *name);
    - gets a string from the environment
    - On success, getenv returns the value associated with name.
    - On error, getenv returns a NULL pointer (if the specified name is not
      defined in the environment)

:doskey
    void doskey(char *string, int mode);
    doskey-like function
    string : to edit
    0 overwrite mode, 1 append mode

:mapbuffer
    void mapbuffer(unsigned char ch);
    save typed character ch to doskey's buffer

:type
    send a string over the serial output port
    char *type (char *templ, ...);
    templ: template string
    ...: variable number of arguments (maximum 9)

:rename
    int rename(const char *oldf, const char *newf);
    rename changes the name of a file from oldname to newname
    - returns 0 if OK, else -1 on error

:remove
    int remove(const char *filename);
    remove deletes the file specified by filename.
    It is a macro that simply translates its call
    to a call to unlink.
    If your file is open, be sure to close it before removing it.
    - returns 0 if successful, else -1

:writechar
    int writechar(unsigned char c);
    writes a character to com port. The character is stored at
    the end of a transmit fifo buffer waiting to be sent.
    c - Character to be sent
    return 0 : operation successful
    return -5 : no room in the transmit queue to put a character

:whitechartimed
    int writechartimed(char c, int nTimeOut);
    writes one characters to the tx buffer, waits for the character to be
    sent, checks timeout.
    c - character to be sent
    nTimeOut - time out parameter in milliseconds. The library uses the
    system time and that's why the precision is +-50 milliseconds. If
    nTimeOut = -1 the function will wait indefinitely to transmit the
    character.
    return 0 : operation successful.
    return -6 : time out expired while waiting for the character to be
    sent.

:writebuffer
    int writebuffer(const char *pBuf);
    writes a block of data to the port.
    It may return before the requested number has been transferred if the
    buffer fills up.
    pBuf - an array of characters to be sent
    return 0 : operation successful
    return -5 : no room to transfer all the requested number of

:writebuffertimed
    int writebufferTimed(const char *pBuf, int nTimeOut);
    Writes block of characters to the tx buffer, waits to be sent, checks
    timeout.
    pBuf - an array of characters to be sent.
    nTimeOut - time out parameter in milliseconds. The library uses the
    system time and that's why the precision is +-50 milliseconds. If
    nTimeOut = -1 the function will wait indefinitely to transmit all the
    characters in the buffer.
    return 0 : operation successful
    return -6 : time out expired while waiting for block of characters
    to be sent.

:readchar
    int readchar(char *pChar);
    Reads a character from the com port receive buffer.
    pChar - put character here
    return 0 : operation successful
    return -3 : Receive buffer was unable to accept more incoming
    characters during last IRQ handling.
    return -4 : No characters in the receive buffer of the COM port.

:readchartimed
    int readchartimed(char *pChar,int nTimeOut);
    Reads a character from the com port receive buffer. If no characters
    available will wait up to nTimeOut milliseconds to retrieve one.
    pChar - put character here
    nTimeOut - time out parameter in milliseconds. The library uses the
    system time and that's why the precision is +-50 milliseconds. If
    nTimeOut = -1 the function will wait indefinitely to transmit the
    character.
    return 0 - operation successful
    return -3 : Receive buffer was unable to accept more incoming
    characters during last IRQ handling.
    return -4 : No characters in the receive buffer of the com port,
    and no characters appeared in the buffer during time out period
    expired.

:readbuffer
    int readbuffer(char *pBuf, int nCount);
    Reads a maximum of nCount characters from com's rx queue to a specific
    buffer. In the rx buffer should have at least nCount characters
    available upon calling this function.
    pBuf - put character here
    nCount - number of characters to transfer from library receive buffer
    to pBuf array.
    return 0 : operation successful
    return -3 : Receive buffer was unable to accept more incoming
    characters during last IRQ handling.
    return -4 : No enough characters in the receive buffer to satisfy
    the requested in nCount. Nothing is transferred!

:readbuffertimed
    int readbuffertimed(char *pBuf, int nCount, int nTimeOut);
    Reads a maximum of nCount characters from com's rx queue to a specific
    buffer. Will wait up to nTimeOut milliseconds to retrieve the requested
    number of characters.
    pBuf - put character here
    nCount - Number of character to wait for.
    nTimeOut - time out parameter in milliseconds. The library uses the
    system time and that's why the precision is +-50 milliseconds. If
    nTimeOut = -1 the function will wait indefinitely to transmit the
    character.
    return 0 : operation successful
    return -3 : Receive buffer was unable to accept more incoming
    characters during last IRQ handling.
    return -6 : The predetermined time out expired and the requested
    nCount characters were not delivered.

:peekchar
    int peekchar(char *pChar);
    Reads the next character available in the receive buffer. The
    character is not extracted and remains in the buffer. You can only peek
    one-deep into the buffer.
    pChar - where to put the character

================================================================================

Reference Materials

1. "Terminal", a serial communication program for the macintosh computer. 1990
   Author : Erny Tontlinger
2. RS-232 communication library user's Manual. 1998
   Author : Peter Marinov
3. The C Toolbox.  Second Edition. 1989
   Author : WILLIAM JAMES HUNT
