Welcome to Islandnet.com  
Locally owned and operated since 1993  
Live Help
LOG IN:  Username:    Password:    

Mscript Programmers Guide


 Contents

  1. Introduction
  2. How it Works
  3. Your First Program
  4. Passing Arguments
  5. Expressions
  6. Controlling Program Flow
  7. Variables, Numbers, and Strings
  8. Meta Commands
  9. Functions
    1. User Defined Functions
    2. String Functions
    3. I/O Functions
    4. Directory Functions
    5. DBM Functions
    6. MySQL Functions
    7. Math Functions
    8. Bit Functions
    9. Time and Date Functions
    10. CGI Functions
    11. GIF Functions
    12. Miscellaneous Functions


 Introduction

In 1994 I was experimenting with creating my own interpreted programming languages when I developed "M-Script". This was a simple yet effective language, truly interpreted. It did not allow for complex expressions or tests, but it was fast as far as interpreted languages go. It was a general purpose language that was sophisticated enough that I wrote a custom UNIX shell in M-Script and launched a successful ISP based on it (Islandnet.com).

Recently I began the task of recreating M-Script from scratch, with the goal of making it into a CGI programming language. CGI stands for "Common Gateway Interface" and is the means by which computer programs manipulate data gathered from web page submissions. The result is M-Script II, a much more sophisticated language that runs even faster than its precursor.

Using M-Script II, you can create your own CGI programs to process HTML forms, build a better shopping cart system, calculate mortgage and loan payments, make a custom hit counter, or practically anything else you can think of.


 How it Works

An M-Script II program is simply a list of expressions in an ASCII text file. The M-Script II interpreter is a program that reads and executes the expressions. You write the programs, the interpreter is installed on the server by your ISP.

Unlike many interpreted languages, the M-Script II interpreter reads in the entire program file at once, converting keywords into numbers and pre-parsing all the expressions. This results in a tremendous speed up, especially if there are many loops (sections that repeat one or more times) in your program.

To invoke the interpreter and run your program, you use an URL like this:

/cgi-bin/ms2/LOGIN/PROGRAM
Replace the word LOGIN with your account name. The interpreter will look up the home directory for that account and use that to locate the program file. It will also restrict your program so that it cannot manipulate files above that point.

Replace the word PROGRAM with the name of your MS2 program. If your program file is named "demo.ms2" (All M-Script II programs must end with a lower case ".ms2" extension) then you would replace PROGRAM in the above example with "demo". Note that you do not specify the file extension - it is assumed.

There are various ways you can cause an M-Script II program to be executed. The first way is to simply type the URL into your browser like any other URL. You can also use an URL like this as a clickable link so that it executes whenever a user selects a link or button:

http://www.islandnet.com/cgi-bin/ms2/LOGIN/PROGRAM
If your program depends on form input, then you would use something like this on your form page:

<form method=post action="/cgi-bin/ms2/LOGIN/PROGRAM">
If your program should be run automatically every time a page is loaded, you can use an exec tag like this:

<!--#exec cgi="/cgi-bin/ms2/LOGIN/PROGRAM" -->
You can also invoke a CGI via an image tag, like this:

<img src="/cgi-bin/ms2/LOGIN/PROGRAM">
Note that if you use this method, your program must output data using the "image/gif" mime type (see the mimetype() function).

All .ms2 files (the files you create) must be located within an "ms2" subdirectory off of your home directory. If you specified "demo" in the URL, then the interpreter will look for the file "ms2/demo.ms2" in your account.

If the interpreter does not find the specified program in your account, it will then look in a special public directory. This allows your ISP to set up public CGI's that any customer can use. If you write a CGI that you think may be useful to others, ask your ISP to put a copy in the public MS2 directory.


 Your First Program

Traditionally the first program anyone learns to write in a new programming language is a simple one that displays "Hello world". This simple M-Script II program does exactly that:

   ; hello.ms2 by Mark Morley

   print( "Hello world" )
The first line is a comment, since it starts with a semicolon. Any blank lines or lines that start with a semicolon are ignored. It is a good idea to use blank lines and comments throughout your program to make it easier to read, although they are not required.

The one and only statement in the example simply prints the message "Hello world". If we were to run this program, the user would see a simple web page with nothing else except "Hello world" printed on it. If we wanted it to appear in large letters, we could change that line to:

   print( "<h1>Hello world</h1>" )


 Passing Arguments

You can pass values (arguments) into a program in several ways. The most obvious way would be via a form. Your script can extract form values using the form() function.

Sometimes you want to pass arguments into a program without requiring an actual form. One way is to specify form variables and values right in the URL like this:

   /cgi-bin/ms2/LOGIN/PROGRAM?var1=val1&var2=val2
Note that a single question mark separates the program name and the list of form variables. Each form variable is followed by an equal sign and the value. A single ampersand symbol separates each form variable.

Note: There can be no spaces in an URL. Spaces and tabs and other characters (including question marks and ampersands that are meant to be part of a value) must be replaced with a percent sign and a two-digit hexidecimal ASCII code. Some common codes are:

   %20   Space
   %09   Tab
   %25   Percent Sign
   %26   Ampersand
   %3F   Question Mark
Any program that expects form input can be called in this manner (it has no way of knowing if there was really a form involved or not), since your program must also use the form() function to extract these values. It's a handy way to test certain programs without filling in a new form each time.

One other way to pass arguments to a script is like this:

   /cgi-bin/ms2/LOGIN/PROGRAM/VAL1/VAL2/VAL3
You can then use the varget() function to access the "arg" array. The first element in the array will always be the login name. The second element is the name of the script. The third element will be the first parameter passed (VAL1 in the example above), and so on. A special numeric variable called "numargs" specifies how many arg array elements there are.


 Expressions

The "hello world" example consisted of only one "expression". An expression is one or more literal values, variables, functions, and operators, optionally grouped together with parenthesis:

10.6
Literal number. Numbers are made up of '+', '-', '.', and the digits '0' through '9'.

"Mark"
Literal string. Strings are any characters enclosed within a pair of double quotes. To embed a double quote within a string, escape it with a single backslash. For example, print( "He said, \"Hello!\"" )

The following special character pairs have special meaning within strings: \r is a carriage return, \n is a newline, and \t is a tab.

varname
A variable. Variable names are made up of the letters 'a' through 'z', the digits '0' through '9', and the underscore. The first character must always be a letter. Variable names ay be virtually any length.

function()
A function. Function names are made up of the letters 'a' through 'z', the digits '0' through '9', and the underscore. The first character must be a letter. A function must always be followed by a pair of parenthesis, even if there are no arguments being passed to it. If there are arguments to a function they must appear within the parenthesis, separated by commas. Function names may be virtually any length.

Operators usually appear between two values and serve to combine them in some way or perform some sort of test. Operators include:

+
Plus. If both values on either side of this operator are numeric, then this operator adds them together. If one or both of the values are strings, then the result is a concatenation of the strings. For example, 5 + 2 is the number 7, while "5" + "2" is the string "52".

-
Minus. Applies to numeric values only. For example, 5 - 2 is the number 3.

*
Multiply. Applies to numeric values only. For example, 2 * 6 is the number 12.

/
Divide. Applies to numeric values only. For example, 10 / 3 is 3.33333

//
Integer divide. Applies to numeric values only. Works just like the normal divide operator, except that any fractional part of the result is ignored. For example, 10 // 3 is the number 3.

%
Modulo. Applies to numeric values only. Returns the remainder of an integer division. For example, 10 % 3 Is the number 1.

=
Assigns a value to a variable. For example, x = 5 + 10 assigns the number 15 to the variable named "x", and name = "Mark" assigns the string "Mark" to the variable named "name".

==
Equal. This test is true if the two values are the same. Case is significant when comparing strings.

!=
Not equal. This test is true if the two values are not the same. Case is significant when comparing strings.

<<
Begins with. Applies to strings only. This test is true if the first string begins with the second string. Case is significant. For example, "This is a test" begins with "This is".

>>
Ends with. Applies to strings only. This test is true if the first string ends with the second string. Case is significant. For example, "This is a test" ends with "a test".

<
Less than. This test is true if the first value is less than the second one. Case is significant when comparing strings.

<=
Less than or equal to. This test is true if the first value is less than or equal to the second one. Case is significant when comparing strings.

>
Greater than. This test is true if the first value is greater than the second one. Case is significant when comparing strings.

>=
Greater than or equal to. This test is true if the first value is greater than or equal to the second one. Case is significant when comparing strings.

*=
Wildcard match. Applies to strings only. This test is true if the first string matches the pattern in the second string. The second string may contain the wildcards '*' (matches zero or more characters) or '?' (matches a single character). Useful for testing file names. For example, "myfile.db" matches "*.db"

-=
Keyword match. Applies to strings only. This test is true if the first string matches the pattern in the second string. The second string contains one or more words separated by commas, and each word may contain a dash to indicate minimum abbreviation length. For example, "quit" matches "q-uit,ex-it", as does "q", "qu", "qui", "ex", "exi", and "exit".

~=
Regexp match. Applies to strings only. This test is true if the first string matches the regular expression in the second string. Some sample regular expressions include:

   ^Hello     Matches any string that begins with "Hello"
   test$      Matches any string that ends with "test"
   ^Bob$      Matches the string "Bob" only
   .          Matches any single character string
   [a-z]      Matches "a", "b", "c", through to "z" only
   [a-z]*     Matches "" or any string of lower case letters
   [a-c,X-Z]  Matches "a", "b", "c", "X", "Y", or "Z" only
   [A,m,t]    Matches "A", "m", or "t" only
   [a-z].     Matches any two character string that begins with a lower case letter
$
Contains. Applies to strings only. True if the first string contains the second string. Case is significant. For example, "This is a test" contains "is a".

and
This test is true if both expressions on either side of it are true. You may also use &&, which means the same thing.

or
This test is true if one or both expressions on either side of it are true. You may also use ||, which means the same thing.

not
This test toggles the result of the expression to the right of it. You may also use !, which means the same thing.

NOTE: It is possible to spread a single expression over multiple lines. If the last character on a line is a backslash, then the following line of code is assumed to be part of the same expression. This is useful if you have long, complex test conditions for example. This does not apply to comments, nor can you insert a comment line in the middle of a multi-line expression. The maximum size of a single line of code (even if it's broken up across multiple lines) is 8Kbytes.


 Controlling Program Flow

Normally a program is executed line by line from beginning to end. This is not always desirable however. Flow control constructs can alter the flow of the program, or cause a section of the program to repeat, etc. Flow control constructs can be nested within other flow control constructs to virtually any depth.

All of the flow control constructs depend on the "trueness" or "falseness" of an expression. Any expression can be used in a flow control test because every expression returns a value. If the net result of an expression is 0, then the expression is false. If the net result is a non-zero number or any string at all, then it is true.

Flow control constructs include:

   if expression
      one or more expressions
   elif expression
      one or more expressions
   else
      one or more expressions
   endif
If/elif/else/endif allows you to conditionally execute blocks of code. The if and endif statements are required, while the elif and else statements are optional. You can have as many elif statements as you need.

   while expression
      one or more expressions
   endwhile
While/endwhile will repeat a section of code as long as the test expression is true. The code within the loop may be executed zero or more times.

   loop
      one or more expressions
   until expression
Similar to the while construct, the loop/until construct repeats a section of code. The difference is that the code is always executed at least once, and it repeats as long as the test expression is false.

   break
The break statement will terminate the inner-most while/endwhile or loop/until construct. This allows you to "break out" of a loop if necessary.

   return
The return statement forces the current function to return (ie: exit). If the current function is the main one, then the program terminates. When used to exit from a user defined function, you can optionally specify a value to be returned, like this: return x * y


 Variables, Numbers, and Strings

Variables have both a name and a value. The name may be virtually any length and may consist of the letters 'a' through 'z', the digits '0' through '9', and the underscore character. The first character of a variable name must always be a letter. Variable names are case sensitive, that means that "abc", "Abc", and "ABC" would be three distinct variables.

A variable may have either a numeric or a string value. The difference is in how the values are treated in tests and by various functions.

Consider these two snippets of M-Script II code:

   a = 10
   b = 5
   c = a + b
   print( "C = ", c )
and

   a = "10"
   b = "5"
   c = a + b
   print( "C = ", c )

The first example assigns numeric values to the variables. The result that it prints would be C = 15.

The second example is similar, except it uses string values instead of true numbers. The result that it prints would be C = 105, which is the concatenation of the strings "10" and "5".

Any variable may have either a numeric value or a string value, but not both at the same time. You can reassign a new value to a variable at any time, and it does not need to be the same type as it was before.

It is possible to create and access variable arrays using the varget() and varset() functions, which are documented in the Miscellaneous Functions section.

NOTE: If you reference a variable name that has not been set to any specific value, it will default to having a numeric value of zero.


 Meta Commands

Meta Commands are special commands that aren't actually part of a program, instead they control how the M-Script II interpreter behaves. All meta commands start with an ampersand character.

@include filename
This command tells the interpreter to open the named file and to start reading lines from it as if it were part of the current file. When it is finished with that file, it continues with the next line in the current one. This allows you to put frequently used functions in an external file which you can then include in numerous MS2 programs. Included files may in turn include other files, up to 8 levels deep. The file is assumed to be relative to your root directory.

@echo and @endecho
Any lines that appear between these two commands are printed to the display according to the same properties as the echo() and includes() functions. Double quotes and backslashes are escaped with a backslash, and a newline character is added to the end of each line.

@comment and @endcomment
Any lines that appear between these two commands will be treated as if they each had a ';' character at the beginning, even if they don't. In this way you can create large comments that are easier to read. It's also a useful tool for temporarily shutting off parts of your program while you test. These may be nested up to any level.


 Functions

Functions are similar to variables, except that they cannot be assigned a value. Instead, a function performs some sort of calculation or operation and returns a result. Some functions return a number while others return a string. The only visual difference between a function and a variable is that all functions are followed with a pair of parenthesis. For example, abs is a variable name, while abs() is a function name.

Most functions require you to pass them one or more arguments. These are placed within the parenthesis, separated with commas. For example, the hypot() function takes two numeric parameters like this: hypot( 10, 15 )

There are two different types of functions. Intrinsic functions are built into the M-Script II programming language. User defined functions work exactly the same way, except you define them yourself in your program. All intrinsic functions have lower case names, but any functions you define yourself may have upper or lower or mixed case names. Don't forget that function names are case sensitive.

Functions are often referred to as "routines" or "subroutines".


User Defined Functions

Every M-Script II program has at least one user defined function called the "main" function. This is, generally, the program itself and it does not necessarily need to be explicitly defined.

Often it is desirable to define your own functions that you can call just like an intrinsic function. This is useful if you have to perform a similar calculation several times throughout your program, for example, or even just to break your program up into a more modular (and therefore more readable) format.

To define a function you use the define keyword, like this:

   define hypot2( a, b )
      return sqrt( a * a + b * b )
This example defines a new function called "hypot2", which takes two parameters called "a" and "b". It calculates and returns the hypotenuse of a right triangle who's sides adjacent to the right angle are "a" and "b" units long.

Note that we didn't name this function "hypot" because that is the name of an intrinsic function that does the same thing, and you cannot redefine intrinsic functions.

Once defined, you could use this function in exactly the same manner that you would use the intrinsic function hypot(). Of course, the intrinsic version is compiled and will run much faster than a user defined version.

Normally you would place all function definitions after the main part of your program. If you prefer to put them at the top, however, you will then need to explicitly define the main function so that the interpreter knows where it starts in the file. In this case simply add the line define main() before the first expression in the main function.

In the above example we define two parameters, "a" and "b". These are variable names by which your function can refer to whatever values are passed in to it. But what happens if you have a global variable called "a"? Well, as long as your function is executing, it will have it's own "a" variable and will be unable to reference the global one. Also note that if this function were to call other user defined functions, they will inherit the local value of "a" (unless they define their own local variable "a").

Function names may be virtually any length.


String Functions

addanchors( string )
Adds HTML anchor tags around any embedded URLs in the string. For example, addanchors( "Go to www.islandnet.com!" ) would return "Go to <a href="http://www.islandnet.com/>www.islandnet.com</a>!".

asc( string )
Returns the numeric ASCII code for the first letter in the specified string. For example, asc( "A" ) returns 65.

chr( number )
Returns a string, one character in length, consisting of the character who's ASCII code is the number. For example, chr( 65 ) returns "A", and chr( 13 ) returns a carriage return. If multiple numbers are given, a longer string is returned. For example, chr( 65, 66, 67 ) returns "ABC". A maximum of 16 numbers can be specified at once.

collapse( string )
Returns the specified string with all extraneous spaces removed. It leaves a single space between words.

countchar( string, delim )
Returns the number of times that "delim" appears in "string". If "delim" is left out then the default delimiter value is used.

escapehtml( string )
Returns the specified string with any HTML tags "escaped". That is, less than signs and greater than signs are replaced with "&lt;" and "&gt;". The resulting string can be displayed on a web page without being interpretted as HTML.

first( string, delim )
Returns the first token from the specified string that consists of characters not in "delim". If not specified, "delim" defaults to a space. For example, first( "This is a test" ) returns "This", while first( "one:two:three", ":" ) returns "one".

hex( string )
Converts the hexidecimal value of "string" into a number. For example, oct( "0xff" ) returns 253.

inlist( key, value1, value2, value3, ... )
Returns 1 if "key" is equal to value1, 2 if it equals value2, and so on. If the key does not match any of the values then the function returns 0. Works with strings or numbers.

insert( string1, string2, start, len )
This function inserts "string1" into "string2" starting at position "start". "len" specifies how many characters in "string2" are to be replaced by the characters in "string1". If you leave this parameter out it defaults to 0. For example, insert( "123", "abcdef", 3, 2 ) returns "ab123ef" ("123" is inserted at position 3 and replaces 2 characters.

join( delim, string1, string2, ... )
Joins all the strings together using "delim" as a delimiter.

last( string, delim )
Returns the last token from the specified string that consists of characters not in "delim". If not specified, "delim" defaults to a space. For example, last( "This is a test" ) returns "test", while last( "one:two:three", ":" ) returns "three".

left( string, length )
Returns the first "length" characters of "string". For example, left( "This is a test", 6 ) returns "This i".

len( string )
Returns the length of the string.

lower( string )
Returns the string with all letters converted to lower case.

md5( string )
Calculates and returns the 32 byte MD5 hash value of a string.

mid( string, start, length )
Returns the section of the string that is "length" characters long, starting with character number "start". For example, mid( "This is a test", 6, 4 ) returns "is a".

nth( string, number, delim )
Returns the "nth" token from the specified string that consists of characters not in "delim". If not specified, "delim" defaults to a space. For example, nth( "This is a test", 3 ) returns "a", while nth( "one:two:three", 2, ":" ) returns "two".

num( string )
Converts the string into a numeric value. For example, num( "10" ) returns 10.

oct( string )
Converts the octal value of "string" into a number. For example, oct( "077" ) returns 63.

pad( string, width, style )
This function returns the string, padded with blanks to make it "width" characters in length. If no style is specified, then the original string is left justified within the new value. If you specify a style 1, then the original string will be centered within the new value. A style of 2 will right-justify the original string in the new value. If the length of the original string is longer than the specified width then it simply returns the original string as is (it is not truncated).

pos( needle, haystack, start )
This function returns the position (a number) of the string "needle" in the string "haystack", or zero if "haystack" doesn't contain "needle" at all. "start" is a number telling it which position in "haystack" to start searching. If left out, "start" defaults to 1. The search for "needle" always proceeds freom left to right. For example, pos( "is", "This is a test" ) returns the number 3.

proper( string )
Returns the string with the first letter of each word converted to upper case and all other letters converted to lower case. For example, proper( "mark morley" ) returns "Mark Morley".

repeat( string, number )
This function returns a new string that consists of "number" copies of "string". For example, repeat( "*", 10 ) returns "**********".

rest( string, delim )
Returns the rest of the specified string minus the first token that consists of characters not in "delim". If not specified, "delim" defaults to a space. For example, rest( "This is a test" ) returns "is a test", while rest( "one:two:three", ":" ) returns "two:three".

reverse( string )
Returns the specified string with all characters reversed. For example, reverse( "1234" ) returns "4321".

right( string, length )
Returns the last "length" characters of the string. For example, right( "This is a test", 6 ) returns "a test".

str( number )
Converts the number into a string value. For example, str( 10 ) returns "10".

strip( string, chars )
Returns the specified string, stripped of all chararacters in "chars". For example, strip( "This is a test", "aeiou" ) returns "Ths s tst".

striphtml( string )
Returns the specified string stripped of all HTML tags. For example, striphtml( "<i>Testing</i>" ) returns "Testing".

trim( string )
Returns the specified string stripped of any leading or trailing spaces or tabs.

triml( string )
Returns the specified string stripped of any leading spaces or tabs.

trimr( string )
Returns the specified string stripped of any trailing spaces or tabs.

upper( string )
Returns the string with all letters converted to upper case.

wild( string, pattern )
Returns 1 if "string" matches the wildcard pattern. "Pattern" may contain the "*" and "?" wildcards. This is equivalent to using the *= operator.

words( string )
Returns the number of "words" in the specified string. A words is considered to be any string of characters that is not a space, tab, carriage return, or newline.


I/O Functions

These functions allow you to print to the screen, and read and write to files.

close( f )
Closes file number 'f'. 'F' is a number previously returned by the open(), opensorted(), or mail() functions. You can close multiple files at the same time by listing multiple file numbers like this: close( f1, f2, f3 )

delete( filename )
Deletes the specified file. Filenames are relative to your home directory. Returns 1 if it is successful, otherwise it returns 0. This is permanent! You cannot undelete a file once it is gone.

echo( value1, value2, ... )
This function works almost exactly like the print() function, except that values enclosed in curly braces are interpretted just like the includes() function.

eof( f )
Returns 1 if the file indicated by the file number is at the end-of-file, otherwise it returns 0. 'F' is a number previously returned by the open() function.

exists( filename )
Returns 1 if the specified file exists, otherwise it returns 0. Filenames are relative to your home directory.

filesize( filename )
Returns the size in bytes of the specified file. Filenames are relative to your home directory.

filetime( filename )
Returns a string representing the date and time that the specified file was last modified. The time is in the format "1998-05-01 12:30:15". Filenames are relative to your home directory. If the file does not exist, it returns 0.

filetype( filename )
Returns a string indicating what type the specified file is. It returns "dir" if it's a directory, "link" if it's a symbolic link, and "file" if it's a regular file. If the file does not exist it returns a 0.

flush()
Normally everything your output to the screen is buffered, which means it may not be printed immediately. Sometimes there are cases where you display something then have to wait while a task completes. Use this function to flush the output buffer, forcing everything printed so far to be displayed.

include( filename, f )
Dumps the contents of the specified file to the specified file number. "F" is a number previously returned by the open() function. If the file number is left out, then it dumps the contents to the display instead of a file. This is useful for displaying common header or footer files, or for sending a canned email message, etc.

includes( filename, f )
Works exactly like include() except that strings within the file that are enclosed within curly braces are interpretted to be M-Script II variables and they are replaced on the fly with the variable value. For example, if the variable NAME is set to "Mark", and the file named "sample.html" consisted of the line "Hello {NAME} how are you?", then includes( "sample.html" ) would display "Hello Mark how are you?"

lockf( file )
Locks a currently open file number so that other scripts (or other instances of the same script) don't attempt to write to the same file. The file is automatically unlocked when you close it or when your script stops running. Returns 0 on failure (which means that another program has it locked OR it's not a currently open file), and 1 on success. It returns immediately, it does not wait for a file to become unlocked.

mail( address )
This function opens an email message addressed to "address". It returns a file number, exactly like the open() function does. You can then use write() or include() to fill in headers and a body. As soon as you close() it the message will be sent.

move( from, to )
Moves (renames) a file or directory. Returns 1 if it is successful, otherwise it returns 0. The new location does not need to be in the same directory as the current one. File and directory names are relative to your home directory.

open( filename, mode )
Opens the specified file using the specified mode. Both the filename and the mode are strings. The default mode is "r" (Read Only). Other modes include "w" (Write only - always creates a new file), "a" (Append - opens an existing file for writing, creates it if necessary), and "r+" (Read/Write - opens a file for reading and writing). This function returns a number indicating the file number, or 0 if it fails. As many as 10 files may be opened simultaneously.

opensorted( filename, field, flags, delim )
This function can only be used to open a file for reading. The difference between this and the regular open() function is that lines are not necessarily read sequentiallty from the file. Instead, each subsequent read() call returns the next sorted line. "field" is the field number within each line to sort on, it defaults to 1 which is the first field. "flags" is an optional string of letters. Each letter turns on a sorting option as follows:

r - Reverses the sort order
n - Sort numeric data as numbers not letters
d - Use dictionary order (only letters and numbers count)
f - Fold case (treat lower/upper case letters the same)
m - Month order - data must start with "Jan", "Feb", "Mar", etc.

"delim" is the delimiter to use when sorting on a field other than 1. For example, if you have a data file that consists of first name/last name pairs separated with a colon, you could read them in sorted on the last name like this:

   if input = opensorted( "names.dat", 2, 0, ":" )
      while (line = read( input )) != 0
         print( "Name: ", nth( line, 2, ":" ), ", ", first( line, ":" ), "\n" )
      endwhile
   endif

openswish( index, words, max, tags )
This function opens the specified Swish index file and searches it for the specified keywords. You read the results of the search one line at a time using read(). "max" is optional and is used to specify the maximum number of hits to return. "tags" is an optional string indicating which tags should be searched.

The results from a swish search may begin with a hash mark, in which case they are comments and may be ignored. A line consisting of a single period means you've reached the end of the results. All other lines returned will be in the following format:

   score url "title" size

where "score" is a number between 0 and 1000 indicating how relevent the hit is (the results are always sorted with the highest scoring entries listed first). "url" is the URL of the document, "title" is the title (enclosed in a pair of double quotes), and "size" is the document size in bytes.

print( ... )
Prints one or more values to the screen. "..." represents one or more strings or numbers. For example, print( "2 + 2 = ", 2 + 2 ) will display "2 + 2 = 4".

printf( format, ... )
Prints the format string to the screen, replacing any embedded formatting codes with the string or number values supplied. Formatting codes include %s to insert a string value, %n to insert an integer value, and %f to insert a floating point value. Optional codes and values may appear between the '%' symbol and the 's', 'n', or 'f' to further control the formatting.

Normally an inserted value will take up the minimal amount of space required. You can force a value to fill up at least N spaces by inserting a number between the '%' and the 's', 'n', or 'f'. If the result is shorter than N characters, it is padded on the left with spaces. You can cause the padding to occur on the right by placing a hyphen immediately after the '%' symbol.

A string value can be truncated to the first N characters by adding ".N" just before the 's'.

You can control the number of decimal places displayed for floating point numbers by adding ".N" just before the 'f'.

Numeric values will be left-padded with zeros instead of blanks if you have a zero immediately after the '%' symbol.

For the following examples, let's assume the variable "name" is set to "Fred Flintstone" and "wage" is set to the number "7.5". We'll show printf() example followed by the output generated. I am using underscore characters to represent spaces to better illustrate what happens.

   printf( "%s was here.", name )
      Fred Flintstone was here.

   printf( "It was %30s who did it.", name )
      It was _______________Fred Flintstone who did it.

   printf( "It was %-30s who did it.", name )
      It was Fred Flintstone_______________ who did it.

   printf( "%.4s was here.", name )
      Fred was here.

   printf( "%10.4s was here.", name )
      Fred______ was here.

   printf( "%.4s makes %f an hour.", name, wage )
      Fred makes 7.500000 an hour.

   printf( "%.4s makes %.2f an hour.", name, wage )
      Fred makes 7.50 an hour.

   printf( "%.4s makes %10.2f an hour.", name, wage )
      Fred makes ______7.50 an hour.

   printf( "%.4s makes %010.2f an hour.", name, wage )
      Fred makes 0000007.50 an hour.

read( f )
This function returns the next line of text from the open filed indicated by the file number given. If there are no more lines left in the file, it returns 0. A "line" may be up to 10,000 characters in length. Lines longer than this are truncated and treated as two or more lines. All carriage returns and newlines are stripped from the end of each line. Here's is how you would read through every line of a file:

   if input = open( "filename.txt" )
      while (line = read( input )) != 0
         ; Do whatever you want with "line" here...
      endwhile
      close( input )
   endif
rewind( f )
This function rewinds the the open file 'f' so that any subsequent read() or write() calls will be relative to the beginning of the file. This is functionally equivalent to seek( f, 0, 0 ).

seek( f, offset, mode )
This function repositions the pointer for the currently open file 'f' based on the two parameters given. If "mode" is 0, then the pointer will move to "offset" bytes from the beginning of the file. If mode is "1" then it will move "offset" bytes relative to its current position. If "mode" is 3, then it is relocated to "offset" bytes from the end of the file. This function is most useful in conjunction with the tell() function.

tell( f )
This function returns the current position of the file pointer for the open file 'f'. The file pointer is the byte offset within the file where the next read() or write() will occur. This is useful to remember a location within an open file, so that you can seek() back to the same spot instantly later on.

unlockf( file )
Unlocks an open file number that was previously locked with the lockf() function. This is not necessary if you close the file or exit your script.

write( f, ... )
Writes one or more values to the open file indicated by the file number. "F" is a number previously returned by the open() function. "..." represents one or more strings or numbers.

writef( f, format, ... )
Writes the format string to the open file 'f', replacing any embedded formatting codes with the string or number values supplied. Formatting codes include %s to insert a string value, %n to insert an integer value, and %f to insert a floating point value. Optional codes and values may appear between the '%' symbol and the 's', 'n', or 'f' to further control the formatting.

For more details, refer to the printf() function.


Directory Functions

These functions allow you to create, delete, and read directories.

closedir( handle )
Closes a directory handle that was previously returned by the opendir() function.

opendir( dirname )
Opens the specified directory for reading and returns a directory handle.

mkdir( dirname )
Creates the specified directory. Directory names are relative to your home directory. Returns 1 if it is successful, otherwise it returns 0.

readdir( handle )
Returns the next filename in the directory pointed at by the directory handle. If there are no more filenames available it returns 0.

This example would simply print the name of every file in your "ms2" directory:

   if DIR = opendir( "ms2" )
      while FILE = readdir( DIR )
         printf( "%s\n", FILE )
      endwhile
      closedir( DIR )
   endif
rewinddir( handle )
Rewinds the directory handle so that the next readdir() will start at the beginning again.

rmdir( dirname )
Removes the specified directory. The directory must be empty for it to work. Directory names are relative to your home directory. Returns 1 if it is successful, otherwise it returns 0.

seekdir( handle, location )
Moves the directory handle pointer to the specified location. The location is a number that was previously obtained via the telldir() function.

telldir( handle )
Returns a number that marks the current location of the directory handle pointer which you can later pass to seekdir() to return to the same spot. Note that the return value is only good for the current session - if you close the dir and open it again the location is not guaranteed to stay the same.


DBM Functions

The DBM functions allow you to create and manipulate a UNIX DBM database. DBM databases store only two values per record - a "key" and a "value". You can use these to create an index into a flat file database by using the result from the tell() function as the value. Both the key and the value can be either a number or a string, however duplicate keys are not allowed.

dbmclose( dbm )
Closes the specified DBM database.

dbmdelete( dbm, key )
Deleted the specified key from the DBM database.

dbmfetch( dbm, key )
Locates the key in the specified DBM database and returns the corresponding value.

dbmfirstkey( dbm )
Returns the first key in the DBM database (that's the KEY, not the corresponding value). Note that the order in which keys are returned is abritrary, DBM files cannot be sorted in any fashion.

dbmnextkey( dbm )
Returns the next key in the DBM database (assumes you've already called dbmfirstkey()). Note that the order in which keys are returned is abritrary, DBM files cannot be sorted in any fashion.

dbmopen( name )
Opens a DBM database and returns a DBM handle. If the database does not exist then it is created. A DBM database consists of two files, so if you were to dbmopen( "sample" ) you'd see the files "sample.pag" and "sample.dir" get created.

dbmstore( dbm, key, value, replace )
Store the key/value pair in the DBM database. If "replace" is 0, then this will only insert the value if the key does not already exist. If "replace" is 1 then any exisiting key will be replaced. DBM files may not have duplicate keys.


MySQL Functions

SQL (pronounced "ess que ell", not "sequel") stands for "Structured Query Language". It is an industry standard database interface, perhaps the most popular in the world. MySQL is a popular SQL implementation that provides a very fast and robust database system. M-Script II has a full set of functions that allow you to access an SQL server, perform searches, and manipulate tables and indexes.

Rarely will you have permission to create a new database yourself, usually your ISP will need to create an empty database for you. Once you have a database (and a username and password to go with it) you can create the tables and indexes within it as required.

A database may contain zero or more "tables" (although you'll need at least one before it's useful for anything). A table is a set of zero or more "rows" (aka "records"). Each row within a table has the same number and type of "columns" (aka "fields").

mysqlconnect( server, username, password )
This function opens a connection to the specified SQL server. You must also supply a username and password (MySQL databases are password protected to prevent unauthorized changes to your data). This function returns 0 if it is unable to connect, otherwise it returns a database handle that you will need to reference in subsequent function calls.

mysqlclose( handle )
This function closes the connection to the specified database server. "handle" is a number previously returned by a successful mysqlconnect() call. Always close your connections when you no longer need them to free up RAM.

mysqlcreatedb( handle, database )
This function creates a new, empty database with no defined tables or indexes. You must have connected to the server with a username and password that has permission to create new databases.

mysqldropdb( handle, database )
This function drops (deletes) an entire database, including all tables and indexes. You must have connected to the server with a username and password that has permission to drop databases.

mysqlselectdb( handle, database )
Once you have opened a connection to the database server, you must select a database to work with. "database" is a string naming the database. The database must already exist, although it may not have any tables yet. This function returns 0 on failure (either the database named does not exist on the server or the username/password you connected with has no permission).

mysqlquery( handle, query )
This function sends the SQL query to the database server. SQL "queries" are not just search commands, they can also be commands to create new tables or indexes, insert or delete data, etc. "query" is a string. This function returns 0 on an error, or 1 if it is successful.

mysqlstoreresult( handle )
Depending on the the nature of a query (and whether it's successful or not), you need to call this function to actually transfer the data from the server to your program. It returns a 0 if it fails, otherwise it returns a "result handle". You need to use this handle access individual rows.

mysqlfreeresult( result )
When you are done with the results of a query, you must free the result handle returned by the mysqlstoreresult() function to release any RAM or disk space used.

mysqlfetchrow( result )
This function grabs the next row of data from the specified result handle and places each field value into the "field" array. Use the varget() function to access each field value. The variable "numfields" is also set to indicate how many fields are available. Note that all field values are returned as strings, regardless of their actual field type.

mysqldataseek( result, n )
This function lets you reposition the "pointer" within the specified set of result rows, so that the next call to mysqlfetchrow() will retrieve the specified row number. The first row is always 0.

mysqlnumrows( result )
This function returns the number of rows in the specified result.

mysqlnumfields( result )
This function returns the number of fields in the specified result.

mysqlaffectedrows( handle )
This function returns the number of rows that were affected by the last deletion or update query.

mysqleof( handle )
This function returns 1 if the last mysqlfetchrow() attempted to access beyond the last row in the results.

mysqlerror( handle )
If a mysql function fails for any reason, you can call this function to get an error message explaining what went wrong. It returns 0 if there was no error to report.


Math Functions

These functions are used in mathematical calculations. They all return numeric values and take numeric arguments.

abs( number )
Returns the absolute value of the number. For example, abs( 10 ) is 10, and so is abs( -10 ).

acos( number )
Returns the arc cosine of the specified number. The number is assumed to be in radians, not degrees.

asin( number )
Returns the arc sine of the specified number. The number is assumed to be in radians, not degrees.

atan( number )
Returns the arc tangent of the specified number. The number is assumed to be in radians, not degrees.

cbrt( number )
Returns the cube root of the specified number.

ceil( number )
Returns the smallest integer value that is greater than or equal to the specified number.

cos( number )
Returns the cosine of the specified number. The number is assumed to be in radians, not degrees.

deg( radians )
Converts radians to degrees.

exp( number )
Returns the exponent of the specified number.

floor( number )
Returns the largest integer value that is less than or equal to the specified number.

hypot( number1, number2 )
Given the length of the two sides adjacent to the right angle in a right triangle, this function returns the length of the hypotenuse.

log( number )
Returns the natural log of the number.

log10( number )
Returns the base 10 log of the number.

max( n1, n2, ... )
Returns the maximum value from the specified list of numbers.

min( n1, n2, ... )
Returns the minimum value from the specified list of numbers.

pi()
Returns the value of PI.

pow( number1, number2 )
Returns number1 raised to the number2 power. For example, pow( 10, 2 ) returns 100.

rad( degrees )
Converts degrees to radians.

random( number1, number2 )
Returns a random integer number. If no parameters are provided, it returns a number between 0 and 100. If only "number1" is provided, then it returns a number between 0 and "number1". If both numbers are provided, it returns a number between "number1" and "number2".

round( number, decimals )
Returns the specified number rounded to "decimal" decimal places. For example, round( 3.49, 1 ) returns 3.5, while round( 1.333, 2 ) returns 1.33.

sign( number )
Returns -1 if the number is less than zero, otherwise it returns 1.

sin( number )
Returns the sine of the specified number. The number is assumed to be in radians, not degrees.

sqrt( number )
Returns the square root of the specified number.

tan( number )
Returns the tangent of the specified number. The number is assumed to be in radians, not degrees.


Bit Functions

These functions can be used to manipulate bit vectors.

andbits( b1, b2, ... )
This function returns the value that results when all the numeric values are combined logically using AND.

notbits( b )
This function returns the value that results when the single numeric parameter is negated.

orbits( b1, b2, ... )
This function returns the value that results when all the numeric values are combined logically using OR.

shiftleft( b, n )
This function shifts the bits in "b" left by "n" places.

shiftright( b, n )
This function shifts the bits in "b" right by "n" places.

xorbits( b1, b2, ... )
This function returns the value that results when all the numeric values are combined logically using XOR.


Time and Date Functions

checkdate( year, month, day )
This function returns 1 if the year, month, and day combine to give a valid date, otherwise it returns 0. Leap years are taken into account.

gettime()
This function returns the current time as a number that represents the number of seconds since 00:00:00 on January 1st 1970 (the beginning of UNIX time).

leapyear( year )
Returns 1 is the specified year is a leap year, otherwise it returns 0. "year" may be either a number or a string value.

maketime( year, month, day, hour, minute, second )
This function returns a number that represents the number of seconds since 00:00:00 on January 1st 1970 (the beginning of UNIX time), based on the parameters provided.

time( format, time )
Returns a string containing the specified time using the specified format. "time" may be a number as returned by the gettime() and maketime() functions, or it may be a string in the format "YYYY-MM-DD HH:MM:SS". If you leave it out completely then the current time is used. If "format" is not present it defaults to "%Y-%m-%d %H:%M:%S". The format value may contain any text, but the following codes are replaced (case is important):

  • %%
    Same as %

  • %Y
    Year (4 digits)

  • %y
    Year (2 digits)

  • %m
    Month (01-12)

  • %d
    Day of month (01-31 - leading zero)

  • %e
    Day of month (1-31 - no leading zero)

  • %H
    Hour (00-23 - leading zero)

  • %k
    Hour (0-23 - no leading zero)

  • %I
    Hour (01-12 - leading zero)

  • %l
    Hour (1-12 - no leading zero)

  • %M
    Minute (00-59)

  • %S
    Second (00-59)

  • %p
    AM or PM

  • %a
    Day name (Sun - Sat)

  • %A
    Day name (Sunday - Saturday)

  • %b
    Month name (Jan - Dec)

  • %B
    Month name (January - December)

  • %U
    Week number (01-52 - Sunday is the first day)

  • %W
    Week number (01-52 - Monday is the first day)

  • %w
    Day of week (0-6 - Sunday is day 0)

  • %Z
    Time zone.

  • %D
    Date as %m/%d/%y

  • %p
    Time as %I:%M:%S %p

  • %T
    Time as %H:%M:%S

  • %j
    Day of year (001-366)

  • %n
    Newline character

  • %t
    Tab character

timeadd( time, number, units )
Adds the specified number of units to the specified date/time. "time" may be a number as returned by gettime() and maketime(), or a string in the format "YYYY-MM-DD HH:MM:SS". "units" may be one of "seconds", "minutes", "hours", "days", "weeks", "months", or "years". If "time" was a number, then this function returns a number, otherwise it returns a string. For example, timeadd( time(), 2, "weeks" ) will return today's date/time plus 2 weeks. You can subtract time by using a negative number.

timesub( time1, time2 )
Subtracts time2 from time1 and returns the difference in seconds. Time1 and time2 may be numbers as returned by gettime() and maketime(), or strings in the format "YYYY-MM-DD HH:MM:SS".


CGI Functions

These functions take care of dealing with the CGI interface.

decode()
This function is used in password authorization scenarios. After a call to the getauth() function, the user's browser will respond with a new request for the same URL, but with an encrypted username and password header. This function decodes these values and returns a single string of the format USERNAME:PASSWORD. You can easily use the first() and rest() string functions to extract one value or the other. For example, if a user entered "Aladdin" and "Open Sesame" as their username and password, decode() would return "Aladdin:Open Sesame".

encode( string )
Returns the "URL encoded" version of the string, suitable for use in URLs. For example, spaces are converted to + signs, and certain other characters are converted to their two digit hex value, etc.

form( varname, num )
Looks up the specified HTML form variable and returns the value as a string. If the specified form value does not exist, it returns 0. In the event you have multiple form values with the same name, you can specify which one you want by providing "num" (the default is 1). This is how you retrieve values entered by a user on your web page. Form variable names are NOT case sensitive. All form variables are string values, so you may need to use the num() function in some cases.

NOTE: If you reference the same form value more than once in your program, it is a good idea to assign it to a real variable first, then reference the variable name instead of calling the form() function each time. Once the value is stored in a variable it can be accessed much more quickly.

Handling Mulipart Forms (uploading files): M-Script II supports the use of multipart/form-type form encoding. This allows people to upload entire files as part of an HTML form. For example, consider the following HTML form:

   <form enctype="multipart/form-data" method=post
         action=/cgi-bin/ms2/LOGIN/upload>
   File to upload: <input type=file name=upload1>
   Description: <input name=description>
   <input type=submit value="Upload it now">
Note the enctype="multipart/form-data" and the type=file tags. The form above will allow the user to select a file on their computer, and type in a brief description. When they submit this form the file will be uploaded. Unlike other types of form values, an uploaded file is not accessible via the form() function. Instead, the file is given a unique number and saved in your "temp" subdirectory. For the example above, there would be four form variables available to you via form():

form( "description" ) will contain the description, this one is no different then regular input form values.

form( "upload1" ) will contain the name of the file as entered by the user. This is NOT the name of the file in your temp directory, it's the name of the file on the user's computer. For example, this might have a value like "C:\WINDOWS\DESKTOP\report.xls".

form( "upload1-type" ) will contain the mime type of the file as defined by the web browser. For example, if you uploaded a GIF image, this would have the value "image/gif". This will be blank in many cases, especially for unknown file types. Note that the BROWSER defines this, not M-Script.

form( "upload1-file" ) will contain the name of the file as it is locally stored. A sample value would be "temp/1890921".

formname( num )
This function returns the name of form variable "num", where num starts at 0. This is useful if you don't know exactly what fields the input form is providing. See formvalue() for an example.

formvalue( num )
The counterpart to formname(), this function returns the value of form value "num". Here's an example that prints every form value submitted:

   i = 0
   while (name = formname( i )) != 0
      value = formvalue( i )
      printf( "%s = %s<br>\n", name, value )
      i = i + 1
   endwhile
getauth( realm )
This function will output the necessary headers to request "authorization". This means the user's browser will normally prompt them for a username and password pair, then try and connect to the same URL again (this time passing the username and password to the CGI program via encrypted headers). For example, to require a username/password to access a given program, it may include code like this:

   if decode() != "Aladdin:Open Sesame"
      getauth( "Secret Cave" )
      print( "Sorry, you need to specify a username and password." )
      exit
   endif
   print( "Welcome..." )
The "realm" is a short string that is passed back to the browser. It is normally used in the prompt message that the user's browser will display when requesting a username and password. Please note that this is not necessarily used in the prompt message, and there is no way to specify an alternate prompt message.

Notice that after calling the getauth() function we exit the program. This is because the browser will reconnect to the program after the user enters the username and password. The error message printed after the getauth() call will only appear to the user if they cancel the username/password request.

getcookie( cookie )
If the specified cookie is set, then its value is returned as a string, otherwise it returns 0.

getenv( var )
If "var" is a string, then this function returns the string value of the specified environment variable. If "var" is a number, then it returns the Nth environment variable as a string like "NAME=VALUE". Environment variable names ARE case sensitive. Some variables you can access include:

  • HTTP_USER_AGENT
    The name and version of the browser software.

  • REMOTE_ADDR
    The IP address of the user's machine.

  • PATH_INFO
    The arguments given to the "ms2" interpreter.

  • DOCUMENT_NAME
    The name of the page that invoked this program.

  • DOCUMENT_URI
    The name of the page that invoked this program, path expanded.

  • QUERY_STRING
    The list of form values passed to the program via the GET method.

mimetype( mimetype )
This function will print a valid HTML Content-Type header using the specified mime type. You only need to use this function if you are outputting something other than text or HTML, like an image or a sound file. If you use this function, it absolutely must be called prior to any other functions that output data to the display. For example, if you were going to output a GIF image you would use mimetype( "image/gif" ).

redirect( url )
This function will cause a browser to be redirected to the specified URL. If you use it you cannot have any other output before or after it.

setcookie( cookie, value, expires )
This function allows you to set a cookie value in the user's browser. This can be used to store information between visits by the same person. If you use this function, it must be used prior to any functions that print to the screen (like print() or include()). At a minimum you must supply a cookie name and a value. For example, setcookie( "PRODUCT", "Fuzzy Pink Dice" ). If you do not provide an expiry date, then the cookie will stay in the user's browser until they close and restart it. You can make a cookie more persistent by providing an expiry date of the format "Weekday, DD-Mon-YYYY HH:MM:SS GMT". For example, "Thursday, 24-Apr-1998 19:00:00 GMT". No other date format is supported, and you must always use the "GMT" timezone (this is part of the cookie specs, not a limitation of M-Script II).


GIF Functions

These functions allow you to create and manipulate GIF images on the fly. They are based on Thomas Boutell's GD library.

arc( number, x, y, xr, yr, start, end, color )
This function draws an arc on an in-memory image using the specified color. The arc is part of an ellipse that has its center at "x,y" and has an X radius of "xr" and a Y radius of "yr". The arc is drawn starting at "start" degrees and ending at "end" degrees.

borderfill( number, x, y, border, color )
This function flood fills an in-memory image with the specified color, starting at "x,y". All pixels in all directions are changed to the new color, until a pixel of the color "border" is reached.

box( number, x1, y1, x2, y2, color )
This routine draws a filled in box on the specified in-memory image and in the specified color. "x1,y1" defines the top left corner of the box, and "x2,y2" defines the bottom right corner.

circle( number, x, y, r, color )
This function draws a circle on an in-memory image in the specified color. The center of the circle is "x,y" and the radius is "r".

closegif( number )
This routine "closes" the specified image, freeing up memory.

colors( number )
This function returns the current number of colors in the palette of the specified in-memory image. An image can have up to 256 colors total.

copy( source, x1, y1, width, height, dest, x2, y2 )
This function copies part of the in-memory image "source" onto the in-memory image "dest". A rectangle "width" pixels wide and "height" pixels high with it's top left corner at "x1,y1" is copied to the destination image at "x2,y2". If the source image has any transparent pixels, these are not copied. If the source and destination images have different color palettes, this function will convert the pixels in the copied chunk so that they fit in with the destination's palette as well as possible.

ellipse( number, x, y, xr, yr, color )
This function draws an ellipse on an in-memory image in the specified color. The center of the ellipse is at "x,y", the X radius is "xr", and the Y radius is "yr".

findcolor( number, red, green, blue )
This function will search the specified in-memory image's palette for a color entry that most closely matches the red, green, and blue values given. "Red", "green", and "blue" are numbers between 0 and 255. This is useful if you are working with an image that has 256 colors already, and you need to draw on it in a specific color and you don't know which color number to use.

floodfill( number, x, y, color )
This function flood fiils an in-memory image with the specified color, starting at "x,y". A flood fill takes the current color at location "x,y" and then changes that pixel and all adjoining pixels of the same color to the new specified color. Once it runs into a pixel of another color it stops flooding in that direction.

getpoint( number, x, y )
This function returns the color number of the specified pixel in the specified in-memory image.

height( number )
This function returns the height, in pixels, of the specified in-memory image.

interlace( number, state )
This turns on or off interlacing for the specified image. This setting only comes into affect when writing the GIF to the display or to disk. By default an image created with newgif() does not have interlacing turned on. IAn interlaced image will appear in "stages", while a non-interlaced image is displayed from top to bottom. "State" should be 0 to turn it off, or any other number to turn it on.

line( number, x1, y1, x2, y2, color )
This routine draws a line from "x1,y1" to "x2,y2" on the specified in-memory image in the specified color. The line if drawn using the current line style.

loadgif( filename )
This routine loads an existing GIF file into memory. It returns a number that indicates the in-memory image number.

newcolor( number, red, green, blue )
This function finds an empty entry in the specified in-memory image's palette and fills it with the specified color. It returns the color number, which you can then use in drawing functions. It returns -1 if there are no empty color entries (ie: the image has 256 colors in use already). "Red", "green", and "blue" are numbers between 0 and 255. For example, y = newcolor( gif, 255, 255, 0 ) creates the color yellow.

newgif( width, height )
This function will create a new blank (all black) image that is "width" pixels wide and "height" pixels high. This image exists only in memory, it is not an actual GIF file. The function returns a number indicating the in-memory image number. An image created this way starts out with a simple 32 color palette. The rest of the 256 colors are undefined. You cannot create an image larger than 1024 x 768.

rectangle( number, x1, y1, x2, y2, color )
This routine draws a rectangle on the specified in-memory image and in the specified color. "x1,y1" defines the top left corner of the rectangle, and "x2,y2" defines the bottom right corner.

setpoint( number, x, y, color )
This function plots a single pixel on the specified image using the specified color.

text( number, x, y, text, font, color )
This function writes "text" onto the specified in-memory image using the specified font and color. "x,y" indicates the top left corner where the text should begin. "Font" is a number between 1 and 16 (or you can use the special keywords FONT5x8, FONT6x9, FONT6x10, FONT6x12, FONT6x13, FONT6x13B, FONT7x13, FONT7x13B, FONT7x14, FONT8x13, FONT8x13B, FONT8x16, FONT9x15, FONT9x15B, FONT10x20, or FONT12x24).

To the left are samples of all sixteen available fonts. This image is generated on the fly by an M-Script II program.

textheight( text, font )
Returns the height, in pixels, that the text would be if drawn in the specified font.

textv( number, x, y, text, font, color )
This function works exactly like text(), except that the text is written vertically on a 90 degree angle. "x,y" specifies the bottom left corner where the text is to begin.

textwidth( text, font )
Returns the width, in pixels, that the text would be if drawn in the specified font.

transparent( number, color )
This function sets which color in the specified image should be treated as "transparent", allowing the background to show through. By default, images created with newgif() have no transparent color. To turn it off use the color -1.

width( number )
This function returns the width, in pixels, of the specified in-memory image.

writegif( number, filename )
This function writes the specified in-memory image to the specified file name as a GIF image. If you don't specify a file name, then the image is written to the display. If the image is sent to the display instead of a file, the function will automatically output an "image/gif" mimetype header if necessary.

NOTE: When an image is loaded from a GIF file, the color palette is set according to what's in the file. However, if you create a gif from scratch using newgif(), then the first 32 entries in the palette are predefined with some common colors for you to draw with. When specifying colors to a function, you normally just provide a number between 0 and 255, but if you created the image with newgif() you can use upper case constants like BLACK, WHITE, and so on. To the left is a chart showing the 32 predefined colors and the special constants you can use to specify them. If the image was loaded from a file, or if you have altered the palette in any way, "BLACK" simply becomes color #0, which may no longer be black. Likewise WHITE represents color #1, and so on.

This color chart is generated on the fly by an M-Script II program.


Miscellaneous Functions

Here's where we list any left over functions that don't quite fit in the other categories.

accepted( filename )
Returns 1 or 0 depending on if the IP number or host name of the current user is accepted or rejected according to the contents of the named file. This mechanism provides a handy way of banning certain sites from accessing your site, normally due to abusive behavior. For example, if you find that your guestbook is being filled with abusive messages from a particular site, you can add their site to the specified file without having to modify your M-Script II code to deal with them explicitly.

The file itself is an ordinary ASCII text file containing lines like this:

   accept scooby.islandnet.com
   reject 199.175.107.*
   reject *freenet.victoria.bc.ca
This example always grants access to "scooby.islandnet.com", but rejects everything else with a 199.175.107.* IP number. It also rejects all accesses from freenet.victoria.bc.ca.

Each line must either accept or reject an IP number or a host name. The wildcard '*' may be used at the end of an IP number or the beginning of a host name. The first line in the file that matches the current visitor is the one that counts.

alarm( minutes )
By default, an MS2 program will kill itself after 2 minutes, regardless of what it is doing. This is plenty of time for most CGI applications, and it protects the system against programming mistakes that cause infinite loops. In some cases you may want to override this with the alarm() function. Simply specify the number of minutes that the script should be allowed to run. A value of 0 will allow it to run as long as necessary. Use this with caution and only if you really need it.

bxparse( expression )
This function is used in conjunction with either bxteststring() or bxtestfile() to process "boolean expresions". A boolean expression is a string containing one or more "words" joined together with "and", "or", "not", or parenthesis. Each "word" may be a literal word, a wildcard pattern, or a "sounds like" word. Use bxparse() to prepare a boolean expression, then use one or both of the related functions to test the expression against strings or files as many times as necessary. You only need to call bxparse() once, or whenever you want to use a different boolean expression. The following example will test each line of a file to see if it contains the word "peanut" and either "fudge" or "choc*" (note that "choc*" is a wildcard "word"):

   if input = open( "goodies.dat" )
      bxparse( "peanut and (fudge or choc*)" )
      while (line = read( input )) != 0
         if bxteststring( line )
            print( line )
         endif
      endwhile
   endif
The "words" in a boolean expression may be any of the following:

  • A literal word like "fudge". This matches "fudge" as well as "FUDGE".
  • A literal word like "=PeaNut". This matches "PeaNut" but not "peanut" or "PEANUT".
  • A wildcard word like "choc*". An asterisk ("*") matches zero or more characters, while a question mark ("?") matches a single character.
  • A "sounds like" word like "~chokalat". The leading tilde tells it to use the SOUNDEX algorithm to check for words that sound similar.

bxtestfile( filename )
This function is used in conjunction with bxparse() to test to see if the specified file matches a boolean search expression. It returns 1 if the contents of the file match, or 0 if they don't.

bxteststring( string )
This function is used in conjunction with bxparse() to test to see is a specified string matches a boolean search expression. It returns 1 if the string matches, or 0 if it doesn't.

cctype( string )
Returns a string, one character in length, indicating what type of credit card number the string is. It returns "v" for VISA, "m" for MasterCard, "a" for American Express, "d" for Discover, "c" for Carte Blanche, and 0 if the specified string does not represent a valid credit card number. This function uses the LUHN algorithm to determine if the credit card number *could* be legitimate. There is no way to determine if the number has yet been assigned to anyone by the credit card company however.

count( filename, key, number )
This function allows you to maintain a set of counter values in a single file. Each line in the file contains a keyword/number pair. To get the current counter value for a specified key, either leave out the number or pass in a zero value. If "number" is not zero, then it is added to the counter value. Normally "number" will be 1. Negative numbers will decrement the counter value. If the specified file does not exist it is created.

crypt( string, salt )
This function returns the encrypted version of "string". "salt" is a two character string that is used to permutate the encryption in one of 4096 ways. The resulting value will always start with the salt value itself. The encryption is one-way only, useful for storing passwords for example.

currency( amount, from, to )
This function converts an amount from one currency into another. Over 170 currencies from around the world are supported. "Amount" is a numeric value, "from" is a three-character ISO currency code representing the currency you want to convert from, and "to" is a similar code representing the currency you want to convert to. For example, to convert $100 US into Canadian you would use n = currency( 100, "USD", "CAD" ).

Click here for a currency table

currencylist( code )
This function outputs a list of all the supported currencies, one per line, in this format: <option value=CAD>Canadian Dollar. It is meant to be part of a select list, but you must provide the <select ...>> and </select> tags. If you provide a currency code, then it will be marked as the currently selected option.

defined( function )
This function tests to see if the specified function is defined. This can be used in conjunction with the "@include" meta command to create optional "plug-in" functions.

gettitle( filename )
This function assumes that the filename you give it is that of an HTML file, and it attempts to extract the title (the text that appears between the <TITLE> and </TITLE> tags. If it can find a title in the first 1K of the file, it returns it, otherwise it returns 0.

hash( key, num )
This function hashes the string "key" and returns a number between 0 and "num". The hash function used is fast and good for any value of "key" and should generate a fairly even distribution.

match( n )
Returns the N'th match from a previous regular expression comparison. For example, after the expression "TEST-123" ~= "([A-Z]*)-([0-9]*)", match( 1 ) will equal "TEST" and match( 2 ) will equal "123". match( 0 ) always equals the entire string, in this example "TEST-123".

precision( n )
This function sets the default precision to use when outputting floating point numbers.

resolve( ip )
Attempts to resolve the specified IP number and returns the host name. If it is unable to resolve the IP number, it returns 0. For example, resolve( "199.175.106.1" ) returns "islandnet.com". Note that such lookups can sometimes take quite a while and might slow down your program.

sleep( seconds )
This function causes the program to sleep, or pause, for the specified number of seconds.

soundex( string, len )
Returns the soundex code for the specified string. Similar sounding words will have the same soundex code. This is useful if you need to compare two words where the spelling may be off. For example, the soundex codes for "Morley" and "Morelay" are the same. The standard, default, and minimum value for "len" is 4, but you can specify a higher number (up to 10) if you want longer soundex codes.

testurl( url )
This functions attempts to access the specified URL to see if it is valid. It returns an HTTP protocol status code to indicate what happened. If the URL is good, then a status code of 200 is what you would expect. The status code is returned as a number, not a string. Possible status codes and their meanings include:

  • 200 OK
  • 302 Moved (usually because you forgot a trailing slash)
  • 400 Bad Request
  • 401 Unauthorized (ie: password protected)
  • 403 Forbidden
  • 404 Not found
  • 500 Internal server error

A few special codes that are not part of the HTTP protocol include:

  • 1 Unable to resolve host name
  • 2 Unable to connect to host

Note that this only works for insecure URL's. If the URL begins with an "https://" it will try and access it as an insecure url instead, which may result in an error even though the URL itself may be valid. There is currently no way to test secure URLs.

varget( varname, index )
This function allows you to retrieve the value of a variable. It is the counterpart to the varset() function. The variable name must be enclosed in double quotes.

varexists( varname, index )
This function is similar to varget(), except that instead of returning the value of a variable it simply returns 1 if the variable is defined and 0 if it is not. The variable name must be enclosed in double quotes.

varset( varname, index, value )
This function allows you to set a variable value. If you don't specify an index, it is no different than using an equal sign to assign a value. The variable name must be enclosed in double quotes. For example, the following two lines are identical in function:

   x = 10
   varset( "x", 10 )
You can create an "array" by using one or more indexes. Currently there is no way other than varset() to set an array element. For example you can assign 3 different values to "x" in this way:

   varset( "x", 1, 5 )
   varset( "x", 2, 10 )
   varset( "x", 3, 15 )
The variable "x" is now an array containing three elements numbered 1, 2, and 3. Each element has its own value. Unlike arrays in other programming languages, elements do not need to be sequential. We could just have easily created a three element array with 10, 20, and 50 as the indexes. In fact, array index values do not even have to be numeric. These are also valid arrays:

   varset( "x", "john", 20 )
   varset( "x", "paul", 40 )
   varset( "x", "george", 60 )
   varset( "x", "ringo", "drummer" )
Note that variable values may be numeric or string values. You can create multi-dimensional arrays by specifying multiple indexes. If we wanted to keep track of a Tic-Tac-Toe board we would want a 3x3 array. We might initialize it like this:

   x = 1
   while x < 4
      y = 1
      while y < 4
         varset( "board", x, y, " " )
         y = y + 1
      endwhile
      x = x + 1
   endwhile
We could then set the top left square of the Tic-Tac-Toe board like this:

   varset( "board", 1, 1, "X" )
Or the bottom middle square like this:

   varset( "board", 2, 3, "O" )
This function returns the value of the array element.



Page generation time: 0.02 seconds