Tutorial000911 Eng
Tutorial000911 Eng
Tutorial
by Sylvain HUET
version 3.0
1
Foreword
For a long time, we have looked upon the computers that sit proudly on our desks as powerful calculators,
machines for word processing or drawing, high-tech TVs, mailboxes, obedient workers... For a long time, we have
thus attempted – and indeed still are attempting – to familiarize ourselves with all the functions this wonderful tool
has to offer. Better than any pen or paintbrush, we can use it to write or draw, correct, copy and print. More
sophisticated than the television, it transmits images, sound and text. More proficient than any letter or parcel, it
can move mountains of information with the click of a button. More diligent than the worker, it performs its tasks
without complaining, doesn't make mistakes and has nothing against monotony. The computer's automated role is
nothing short of spectacular, unhoped-for and hitherto unheard of; it does what we hardly dared imagine less than
a century ago. It is the ultimate conclusion to the industrial revolution.
There is always a certain degree of satisfaction in seeing old dreams come true. However this satisfaction soon
gives way to frustration, since we are not content with merely realizing yesterday's dreams; we need to imagine
those of tomorrow. Thus, these machines are not just tools to be used, but worlds in their own right. Video games
have shown us that the computer can contain its own imaginary, animated and extraordinary world. A world with
its own rules and its own story, one in which the machine asks us to take a seat. According to Philippe Quéau,
Director of the Information and Computer Division at UNESCO, humanity is entering its third image period: after
the images we look at (paintings, drawings), and the images we read (letters, books, the web), here are the images
we live in and which, thanks to network technology, we do so collectively. Just as the eye is the gateway to the
images we see, and the ear the gateway to the sounds we hear, so the computer is the gateway to this image we live
in.
It is time we considered the computer as a prosthesis, one which allows us to enter a new reality and to actually live
in these new images.
Living in an image is like living in a house: you can enter inside it and welcome others in it, you can share, work
and rest in it, build it, move it, extend it, tidy it and make a mess of it. The only difference is that the image we live
in has no substance, or rather its substance is constantly changing: a wall is not made of concrete, rather it is a
fragment of the hard disk's magnetic surface, a series of transistors inside the computer, various electrical states of
a coaxial cable and a handful of electrons in the cathode ray tube of your monitor. Real or virtual, that is not the
question, because everything you do in this image, that is to say everything you communicate in this image, is real
enough. What you do to others and what you say to others is just as real as if you were using a piece of "concrete"
equipment. When we talk of a house's spirit, we call to mind the traces left by those who lived in it previously. The
same applies to the image we live in: it is marked by the life organized within it.
As with any other image, it cannot fall within the confines of a definition. Classifying it is no small order: 3D, 2D,
text,... By "inhabiting" an image, we think of a three-dimensional place, probably the most appropriate and familiar
form that we can imagine. Nonetheless, me must not cast aside other forms that may reveal themselves to be more
adapted to certain uses. "Inhabiting" a place conjures up a building and, consequently, a certain architecture.
However, there is a fundamental difference between the building and the image, between the architect and the
painter: to build an edifice, you need sufficient resources in terms of men and material, whereas the image needs
only a nominal investment – a few pencils and some paper. And yet, the image is more powerful than the building,
since it understands, absorbs and surpasses it. As Victor Hugo once said: "the book will kill the building!".
This image we live in has an author: as such, it is no different than the image we see, or the image we read. Creating
such an image requires a diverse set of skills: appreciation and organization, architectural – but also aesthetical –
acuity: who would want to live in an ugly image? Lastly, a good measure of computer expertise to bring the image
to life. The architect can only work if he or she is familiar with building techniques, and on a more basic level,
because such techniques and technologies actually exist. Similarly, the image we can live in is only thinkable
through the techniques and the technology that make it possible.
To reach this goal, Scol technology must be unbiased in so far as the inhabitable image is concerned: just as it is
impossible to find points in common between two paintings (outside of the fact that both are flat representations,
and perhaps not even that...), so it must be impossible to find points in common between two inhabitable images.
2
This technology must therefore resolve all the purely technical problems to put the author in a situation where only
the interesting problems subsist. It must constrict the author's imagination as little as possible, and lend itself to be
adapted to constantly changing uses. In short, it must evolve, not in parallel to the creations it offers, but through
the very existence of these creations.
Only one computer element can offer this degree of flexibility: the programming language. That is why Scol
technology is above all based on a language, that of Scol. Like the language we speak, a programming language
offers the guarantee – with a mere handful of words – that its possibilities are already infinite. It also offers the
guarantee that each can define their own style, their own expressions. It thus guarantees the author's independence
and freedom.
It is compact, since it must travel through a network, and since load times need to be reduced.
It is functional, statically characteristic and polymorphic, since it is a modern language which, through its very
syntax, prevents most of the bugs you will find in other languages from being written.
It is network-oriented, containing communication-related functions at the very heart of its syntax: the developer no
longer has to worry about how to convey information (format, bottlenecks, …), just its content.
It is a 3D language, since the 3D environment is the natural context for exchanges and encounters. For this reason,
the Scol language includes an engine optimized for on-line use, i.e. one offering fluid image rendering on less
powerful machines by using scene description files that are compact.
It is a 2D language, since it is the privileged medium for text and image. The Scol language offers a complete
library to build and manage any interface using windows, buttons, text, images…
It is sound language, since the oral is the preferred means for communication: the Scol language offers all the
possibilities of playing music, recording, compressing and restoring sound.
It is an SQL language, since databases are the preferred means for organizing masses of information. The Scol
language can connect to any database and perform any SQL query.
It is a Web language, since it is a natural Internet interface. That is why Scol technology interfaces with JAVA,
JavaScript and ActiveX.
With Scol, you enter into the new age of the image.
3
Table of Contents
Foreword .......................................................................................................................................................... 2
Table of Contents.............................................................................................................................................. 4
I. Presentation ................................................................................................................................................... 7
1. Presentation of the Scol virtual machine .................................................................................................... 7
2. Link between the Scol virtual machine and the files on your computer ....................................................... 7
3. Implementing the environment .................................................................................................................. 8
3.1. Installing Scol..................................................................................................................................... 8
3.2. Special configuration .......................................................................................................................... 8
3.3. Developing ......................................................................................................................................... 8
II. Hello World ................................................................................................................................................. 9
1. First version .............................................................................................................................................. 9
2. Second version ........................................................................................................................................ 10
3. Third version........................................................................................................................................... 11
III. Principles of Scol programming................................................................................................................. 14
1. Environments and channels ..................................................................................................................... 14
1.1 Environments .................................................................................................................................... 14
1.2 Channels ........................................................................................................................................... 15
1.3 Starting the Scol machine: initial elements ......................................................................................... 15
2. Functional programming ......................................................................................................................... 15
3. Types and typing ..................................................................................................................................... 17
3.1 Introduction to types .......................................................................................................................... 17
3.2 Syntax of Scol types .......................................................................................................................... 17
3.3 Further information on types .............................................................................................................. 18
4. Syntax of the Scol language..................................................................................................................... 19
5. Basic constructions.................................................................................................................................. 22
5.1 Main elements ................................................................................................................................... 22
5.2 Using tuples ...................................................................................................................................... 24
5.3 Application to lists............................................................................................................................. 24
5.4 Using tables....................................................................................................................................... 27
5.5 Further details on certain basic constructions...................................................................................... 27
5.6 Using structures ................................................................................................................................. 27
5.7 Using type constructors...................................................................................................................... 28
5.8 Using the functions ............................................................................................................................ 29
5.9 Redefining functions.......................................................................................................................... 30
5.10 New examples ................................................................................................................................. 30
5.11 Standard library ............................................................................................................................... 32
6. Global variables of the Scol machine ....................................................................................................... 37
IV. Channels and communications .................................................................................................................. 39
1. Manipulating channels............................................................................................................................. 39
1.1 Channel manipulation API ................................................................................................................. 39
1.2 Environment management API .......................................................................................................... 39
1.3 Creating and destroying a channel ...................................................................................................... 40
1.4 Creating and destroying a server ........................................................................................................ 41
1.5 Additional functions of channel management ..................................................................................... 42
1.6 Script syntax...................................................................................................................................... 42
2. Communications in Scol .......................................................................................................................... 43
2.1 Controlling connections: particular events .......................................................................................... 43
2.2 Sending a message using the _on function......................................................................................... 43
2.3 Controlling message queues ............................................................................................................... 45
2.4 Sending a UDP message .................................................................................................................... 45
2.5 Another use for communication constructors ...................................................................................... 45
3. Methodology of network programming in Scol ........................................................................................ 46
V. File management ........................................................................................................................................ 48
1. Scol partitions ......................................................................................................................................... 48
2. File types ................................................................................................................................................ 49
2.1 Normal files ...................................................................................................................................... 49
2.2 Signed files........................................................................................................................................ 49
4
3. File management API .............................................................................................................................. 50
4. Advanced file-reading functions .............................................................................................................. 51
5. File selection interface............................................................................................................................. 52
VI. Event-driven and graphic interface programming....................................................................................... 53
1. Basic principles ....................................................................................................................................... 53
1.1 Proprietary channel ............................................................................................................................ 53
1.2 Managing events................................................................................................................................ 53
2. Examples ................................................................................................................................................ 55
2.1 Windows ........................................................................................................................................... 55
2.2 Timers ............................................................................................................................................... 56
VII. 3D programming ..................................................................................................................................... 57
1. Basic 3D concepts ................................................................................................................................... 57
1.1 Scene ................................................................................................................................................ 57
1.2 Session .............................................................................................................................................. 58
1.3 Material............................................................................................................................................. 58
1.4 Performance ...................................................................................................................................... 58
1.5 Scol 3D engine characteristics............................................................................................................ 59
2. 3D file format ......................................................................................................................................... 60
3. 3D manipulation API............................................................................................................................... 62
3.1. New types ........................................................................................................................................ 64
3.2. Session ............................................................................................................................................. 64
3.3. General object management .............................................................................................................. 64
3.4. Managing materials .......................................................................................................................... 67
3.5. Managing textures ............................................................................................................................ 68
3.6. Managing rendering and link with 2D interface ................................................................................. 68
4. Managing collisions ................................................................................................................................ 69
4.1 Principles .......................................................................................................................................... 69
4.2 API ................................................................................................................................................... 70
VIII. BigNum programming............................................................................................................................ 72
1. General introduction................................................................................................................................ 72
2. API ......................................................................................................................................................... 72
3 . Example................................................................................................................................................. 73
IX. SQL.......................................................................................................................................................... 75
1. General introduction................................................................................................................................ 75
2. API ......................................................................................................................................................... 75
3. Examples ................................................................................................................................................ 75
X. Http interfacing .......................................................................................................................................... 78
1. Http server .............................................................................................................................................. 78
a. Principles ............................................................................................................................................ 78
b. Some words of advice .......................................................................................................................... 78
2. Http client ............................................................................................................................................... 79
a. Principles ............................................................................................................................................ 79
b. POST method ...................................................................................................................................... 80
XI. Multimedia programming.......................................................................................................................... 81
XII. The Scol machine: start-up, control, standard client and server ................................................................. 83
1. Scol Engine: the supervisor ..................................................................................................................... 83
2. Starting the supervisor ............................................................................................................................. 83
3. Starting a Scol machine with a start-up script ........................................................................................... 84
3.1 Start-up script .................................................................................................................................... 84
3.2 Operating rights ................................................................................................................................. 84
3.3 Memory ............................................................................................................................................ 85
4. Starting a machine or another process with a Scol machine ...................................................................... 85
5. Communication between the Scol machine and the supervisor ................................................................. 86
6. Standard server and client ........................................................................................................................ 86
6.1 General remarks on Scol machine communication .............................................................................. 86
6.2 Standard server – version 3 ................................................................................................................ 87
XIII. Integration possibilities........................................................................................................................... 88
a. Simple interfacing ........................................................................................................................... 88
d. Sophisticated interfacing .................................................................................................................. 90
XIV. DMS Programming: Distributed Modules System ................................................................................... 93
5
1. Presentation ............................................................................................................................................ 93
2. Definitions .............................................................................................................................................. 94
3. Principles ................................................................................................................................................ 94
3.a Module architecture ........................................................................................................................... 95
3.b Tree of documents ............................................................................................................................. 95
3.c Encapsulation .................................................................................................................................... 95
3.d Inter-module links and communication.............................................................................................. 95
3.e Dynamic activation ............................................................................................................................ 96
3.f Users and UserInstances ..................................................................................................................... 97
3.g The SCS site editor ............................................................................................................................ 97
4. Downloading of resources ....................................................................................................................... 97
5. DMS site definition files.......................................................................................................................... 98
5.1 DMC file: distributed modules class................................................................................................... 98
5.2 Dms files ................................................................................................................................... 100
5.3 ‘dmi’ definition block: distributed module instance..................................................................... 101
5.4 ‘link’ definition block ................................................................................................................ 101
5.5 ‘zone’ definition block ............................................................................................................... 103
5.6 ‘def’ definition block ................................................................................................................. 103
5.7 ‘docclient’ and ‘docserver’ definition blocks .............................................................................. 103
6 API ........................................................................................................................................................ 105
6.1 server API ....................................................................................................................................... 105
6.2. Client API ...................................................................................................................................... 113
6.3. Editor API ...................................................................................................................................... 117
7. Example 1 : module running only on the server...................................................................................... 119
8. Example 2: distributed module and zone management............................................................................ 122
9. Example 3: distributed module and intra-module message...................................................................... 124
10. C3d3 Module and plug-ins................................................................................................................... 126
2. Anchors .................................................................................................................................................... 131
3. Plug-ins .................................................................................................................................................... 132
4. Examples .................................................................................................................................................. 134
6
I. Presentation
This chapter will help you take your very first steps in Scol. It includes a presentation of the Scol programming
environment.
The Scol virtual machine is the program based on Scol technology. Its Windows version is called [Link]
(which stands for ‘Universal Scol Machine for Windows’). You generally find it in ‘C:/Program Files/Scol/’.
As its name indicates, the virtual machine creates a virtual version of an 'ideal' machine whose characteristics
would be the following:
- Automatic memory management: developers do not have to reserve or free up the memory themselves.
- This virtual machine's 'machine language' is the Scol language.
- Fully integrated network communication management, since this management is masked by the Scol language.
- A number of libraries, used to connect the machine to a simple graphic user interface, to sound interfaces and
many others which we will look at later in this document.
As with any other machine, the Scol virtual machine feeds on programs, written in 'machine language', in this case
the Scol language. This means that the virtual machine also includes a Scol language compiler. The virtual
machine is said to be ‘universal’ since it is the cornerstone of any system based on Scol technology: such a system
consists of a variable number of Scol machines which communicate with one another.
Developing in Scol amounts to writing programs in the Scol language and in giving them to one or more Scol
machines for execution. It is important to note that more than one virtual Scol machine can run on the same
computer. Indeed, this will always be the case, since a special Scol machine, called ‘Scol Engine’, will always be
running as a background task on your system.
For those interested in the technical details, note that the Scol language is compiled ‘on-the-fly’ towards a
byte-code which is interpreted.
2. Link between the Scol virtual machine and the files on your computer
As with any other machine, the Scol machine needs mass memory to store the programs and data of the
applications written in Scol. The machine can therefore read and write files.
Specialists usually consider this to be a serious security problem: since Scol applications are often connected to the
Internet, the user does not want the content of his or her files to be transmitted somewhere else in the world. For
this reason, Scol's file management system has been specially designed to isolate those applications that do not use
Scol from those that do use it on the one hand, and to isolate the Scol applications from one another on the other
hand.
This system, which we will look at in further detail later on, is based on the concept of ‘Scol partition’. A Scol
partition is a directory (including all associated subdirectories) on your disk that can be used by Scol: a Scol
machine cannot access a file not present in a Scol partition from itself. A Scol machine can use a number of Scol
partitions, used in the order in which they are defined. A file which is not found in the first partition will be
searched for in the second partition, and so on. Writing is always done in the first partition.
By default, the partitions on your Scol machine running Windows are defined as follows:
c:/program files/scol/cache
c:/program files/scol/partition
When you develop your first programs, only the second will be used. The principle is as follows: the second
partition is your working directory, while the first contains all the files you have gleaned while surfing from one
site to another; consequently your files are protected from your wanderings.
7
The partitions are defined in the [Link] file (whose path is usually c:/program files/scol/[Link]). This file's syntax
will be defined later in this document.
To become a 'real' Scol developer, you must first install the development environment on your computer. To do so,
proceed via the following stages.
Before doing anything else, you must install Scol on your machine. To do so, download the latest version of the
virtual machine from the Cryo-Networks Web site: [Link]. This program is free. It is
approximately 1MB.
The SCOL machine can produce files that track its operation. These files are known as ‘log’ files. The creation of
such files tends to slow down the machine. That is why they are not produced by default. However, these files
contain information that is particularly useful for developers. In particular, they indicate syntax errors and, more
generally, compilation errors. Moreover, certain Scol language functions can be used to write directly in log files
during execution. This often helps in the efficient debugging of your programs.
You must start by reactivating the log file creation function. Proceed as follows:
- Start Scol
- Open the “Settings” menu
- Open the “Expert Mode” menu
- Replace the line ‘echo 0’ with ‘#echo 0’ (the # character is used to add comments to the line)
- Replace the line ‘log no’ with ‘log yes’
- Click OK
You can also do this by editing the [Link] file (usually located in Windows in C:\program Files\Scol).
Your system is now configured and you are ready to develop your first program.
When you want to deactivate the log file creation function, simply restore these two lines to their original status.
3.3. Developing
8
II. Hello World
We will start with a well-known program. It consists in displaying the message ‘hello world’ on-screen. We will
give several versions of this program.
The aim of this chapter is to present several examples of programs written in Scol. If some points seem obscure or
insufficiently detailed, be patient. All will be revealed in the following chapter.
1. First version
_load “Tutorial/[Link]”
main
/* commentary */
fun main()=
_showconsole;
_fooS “>>>>>>>>>>>> Hello World”;;
You see ‘>>>>>>>>>>>> Hello World’ appear. This window is the ‘console’ window and is closely linked to the
log file since messages that pass in the console are written in the log files. Thus, once you have closed this console
window, open the corresponding log file: it is a “ *.log ” file located by default in directory “c:/program
files/scol/log”, and contains the date (year-month-day_hour-minute-second). At the end of this file, you will find
the replica of what is reproduced here. Well done! You have now created your first Scol program. Now let's try to
see what happened.
Generally speaking, the *.scol files are start-up files called script files, whereas the *.pkg files contain programs
written in the Scol language. Later on, we will see that there is a close tie between these two types of files. We will
detail the syntax of the script files at a later stage.
The [Link] file contains the program start-up commands. The first line (‘_load …’) indicates that you must
load the [Link] program. The second line indicates that you must then run the ‘main’ function.
9
The [Link] file contains the program as such. In a Scol program, you will find several types of definitions:
- functions, the definition of which starts with ‘fun’
- variables, the definition of which starts with ‘var’ or ‘typeof’
- new types, the definition of which starts with ‘typedef’ or ‘struct’
- and still more things...
Each definition ends with a double semicolon ‘;;’. This is a reference to the Caml language developed by the
French National Institute for Research in Computer Science and Control (INRIA).
Comments are placed as in C between /* and */. Unlike C, you can interleave the comments, which often proves to
be most practical.
In the [Link] file, you thus define a ‘main’ function. This function's name is followed by (): it does not take any
arguments. The function's value follows the = sign. Each expression of the function is separated from the next by a
semicolon (‘;’). Here, the function thus includes two expressions : _showconsole and _fooS
“>>>>>>>>>>>> Hello World”
The definition of the function ends with a double semicolon.
The first expression calls the _showconsole function which displays the console window (which otherwise remains
hidden).
The second expression calls the _fooS function which requires a character string-type argument, and displays it in
the console window and, therefore, in the log file.
In Scol language, arguments are not placed between parentheses nor separated by commas as in C language. The
arguments follow the function, separated quite simply by spaces or new line characters. If you want to use
parentheses, you can place them around one argument, or around the function+arguments. For example, the
following three expressions are all correct:
_fooS (“>>>>>>>>>>>> Hello World”)
(_fooS “>>>>>>>>>>>> Hello World”)
(_fooS (“>>>>>>>>>>>> Hello World”))
We will come back to this important point later on. Note that if you don't like parentheses, you can use braces: they
serve exactly the same purpose.
Once the console window is displayed, the virtual machine is always in operation. It only stops when you destroy
the console window. Indeed, this is one of the ways of destroying a Scol machine.
Towards the end of the log file (4 lines before ‘hello world’), you will notice the following line:
fun main : fun [] S
This line is very important: it indicates that the virtual machine has successfully recorded (compiled) the main
function, and gives its type: a function which takes no argument and which returns a character string. Indeed, with
Scol, you will very seldom have to define a function's type (number and type of arguments, type of the result)
yourself. The Scol machine does it for you (we talk of “inference of type” ).
2. Second version
file ‘Tutorial/[Link]’
_load “Tutorial/[Link]”
main “Test”
file ‘Tutorial/[Link]’
/* [Link] */
fun end(a,b,r)=
_closemachine;;
fun main(title)=
_DLGrflmessage
10
(_DLGMessageBox _channel nil title "Hello World" 0)
@end 0;;
This time, a simple dialog box is displayed instead of the console window.
This program underscores a number of points.
Firstly, the main function uses an argument called ‘title’. Here we can see how to pass this argument from the
[Link] file. It takes the value “Test”.
The ‘main’ function in the [Link] file uses only one expression, but this expression calls a _DLGrflmessage
function (which requires 3 arguments) whose first argument is itself the invocation of a _DLGMessageBox
function (which requires 5 arguments). Without going into too much detail, let's say that the _DLGMessageBox
function creates a dialog box whose title is the 3rd argument and whose text is the 4th. This function returns the
identifier of the dialog box. The _DLGrflmessage function is used to define what will happen when the user closes
the dialog box. The first argument is the dialog box, the second is the function to call. The ‘@’ sign is used, as it
were, to send a pointer to the ‘end’ function (to use the C language terminology). Without this sign, the ‘end’
function would be called immediately (which would provoke a compilation error since the ‘end’ function requires
three arguments, whereas here only one is available).
The ‘end’ function contains a single expression that calls the ‘_closemachine’ function, which closes the Scol
machine.
A quick look in the log file (Scol/[Link]) reveals the following line:
fun main : fun [S] MessageBox
This time, the compiler has detected that the main function uses an S type argument (character string) and returns
the MessageBox type. Note that the developer has not had to specify the argument type (S), but that the compiler
has determined it itself.
3. Third version
file ‘Tutorial/[Link]’:
_load "Tutorial/[Link]"
main
file ‘Tutorial/[Link]’:
/* [Link] */
fun _end(a,b)=_closemachine;;
fun main()=
let _CRwindow _channel nil 150 150 400 300
WN_MENU|WN_MINBOX|WN_SIZEBOX "Hello World"
-> win in
let _CRtext _channel win 1 1 398 298
ET_VSCROLL|ET_HSCROLL "Hello World"
-> text in
(_CBwinDestroy win @_end nil;
_CBwinSize win @_resize text
);;
11
Here we see a number of new elements appear: _SIZEtext, let, nil, _CRwindow, _CRtext, _CBwinDestroy and
_CBwinSize.
Functions _SIZEtext, _CRwindow, _CRtext, _CBwinDestroy and _CBwinSize are graphic interface functions:
Note the ‘nil’ function. In fact, nil is a special value which has no defined type. Any variable or parameter can take
the value nil. Here, nil is used in two places:
- as the parent window of the window created by _CRwindow: this means that the window has no parent
- as the user parameter of the _CBwinDestroy function: this can mean that there is no user parameter to pass
The ‘let ... -> ... in ...’ function is used to define local variables.
Between ‘let’ and ‘->‘, you can write any given expression. As with all expressions in Scol, it returns a result (here,
it is a window in the first instance, a text field in the second).
Between ‘->' and ‘in’, you write the local variable (here, ‘win’ and ‘text’).
After the ‘in’, you write the expression in which the local variable can be used. Beyond the expression that follows
the ‘in’, the local variable is no longer recognized.
A quick word on callback functions: the functions passed as arguments of the _CBwinDestroy and _CBwinSize
functions are callback functions, since they will subsequently be called when a given event occurs. By convention,
callback functions use at least two arguments:
- the first argument gives the assigned object again (the window in the case of _CBwinDestroy, and _CBwinSize)
- the second argument is the user parameter as defined by the _CBwinDestroy or _CBwinSize function.
Possible additional arguments depend on the nature of the event. For example, the destruction callback does not
use any additional parameters, while the resizing callback uses two additional parameters which contain the new
size of the window.
12
The ‘main’ function creates a window and a text field contained in this window. The title of the window and the
content of the text field are positioned on the ‘Hello World’ value. The ‘main’ function also defines two callbacks
on the destruction and the resizing of the window.
If the window is destroyed, the program stops (_closemachine function).
If the window is resized, you must resize the text field. This is done by calling the _SIZEtext function. Note the use
of the user parameter to ‘pass’ the text field to the callback.
We will use this little program in the next chapter, since it can be used to define a simple display area.
13
III. Principles of Scol programming
1.1 Environments
An environment is a list (in the computer sense of the word) of variables and functions. In the previous chapter's
‘hello3’ example, in the Scol machine there was an environment containing the main, _resize and _end functions
and all the variables defined in the locked/lib/const file. Moreover, this environment contained all the Scol API
functions (_CRwindow, _Crtext, ...).
Files written in Scol are always compiled in a certain environment. The program thus compiled can refer to the
environment's functions and variables; those defined in this file are added to the environment at the start of the list
of variables and functions: by compiling the ‘[Link]’ file, we added the main, _resize and _end functions at the
start of the environment. This means that any file compiled afterwards will be able to refer to these three
functions.
By definition, a minimal environment is one that only contains the Scol API.
The originality of the Scol machine is that it can manage several environments at the same time: several lists of
variables and functions coexist in the machine's memory. That is why it is important to know – at any time – in
which environment you are working. These environments are not necessarily independent. As we said, an
environment is a list. You can have two lists with the same end part. For example, lists (1,2,10,11,12) and
(3,4,5,10,11,12) have the same size 3 end: (10,11,12). Similarly, in Scol, two environments can have the same end.
In fact, each environment ends with the minimal environment. This means you can share certain resources
between the environments: functions and variables can be pooled. A variable that is local to an environment is
one that is defined in a non-shared part of the environment's list.
14
1.2 Channels
A channel is a pair (environment, network connection). This association is an original feature of Scol. At its
minimum, the environment is the minimal environment. The network connection is usually a TCP/IP socket-type
connection. However, you define a special type of channel, called unplugged, which does not contain any network
connections.
Thus when you create a channel, you must specify its initial environment as well as the possible network
connection. A channel's environment can develop over time:
- You can enlarge an environment by compiling new Scol files.
- You can delete elements from an environment by removing the functions and variables located at the start of an
environment.
- You can substitute one environment for another, and in particular reinitialize a channel by replacing its minimal
environment.
When you start the Scol machine, an unplugged channel is automatically created with the minimal environment.
The *.scol file is used to define the operations to perform on this channel. These typically consist in compiling one
or more Scol files, then in starting the execution of a function. The files will be compiled in this first channel, and
the function searched in its environment.
2. Functional programming
The Scol language is a functional language, even if it authorizes imperative programming and all side effects.
The base unit of the Scol language is the function: a function is a computer object which uses a certain number of
arguments (possibly reduced to zero) and which produces a single result.
Any function returns a result, even when this result is not "significant." For example, in the hello1 example, the
_showconsole function returns a result (an integer). However, this result is not “important”; what the developer
is interested in is the fact that the _showconsole function initiates the display of the console window. Any
effect of a function other than the result of the function is called a side effect. A side effect must not make you lose
sight of the fact that the function which produced it itself returned a result.
With its functional approach, Scol encourages function interleaving. We have already seen one example of
interleaving in the hello2 program. Here is a second example. Others will follow.
Here, function f calculates what follows (x+1), function g calculates the double (x*2), function gof calculates
the compound of g and f ( (x+1)*2 ).
If we want to use parentheses for better readability, we could write:
fun gof(x)= g (f x);;
fun gof(x)= (g f x);;
fun gof(x)= (g (f (x)));;
However we could not write:
fun gof(x)= (g f) x;;
Other example:
fun f(a,b)=strcat a b;;
fun g(a)=strcat a “.”;;
fun h(a,b)= f g a b;;
15
The strcat function is one which concatenates two character strings. For example (strcat “a” “b”) equals
“ab”.
In this example, the h function takes two character strings and returns a string consisting of two arguments
separated by a point.
We could write :
fun h(a,b)= f (g a) b;;
fun h(a,b)= (f (g a) b);;
But we could not write:
fun h(a,b)= f((g a) b);;
And especially not:
fun h(a,b)= f(g(a),b);;
Thus, the parentheses enclose the expressions, and not – as is the case with C – the list of a function's arguments.
Since each argument is itself an expression, you can enclose an argument in parentheses. You can replace the
parentheses with braces: they are completely equivalent.
16
3. Types and typing
As was indicated in the “Hello World” examples, the Scol machine automatically determines the types of the
functions during the compilation. However, in some cases, developers will have to create certain types themselves:
definition of structures, of type constructors, of certain variables and sometimes of function prototypes. Moreover,
to be able to read the documents on the Scol APIs, you need to be able to understand the types.
The type of an element in your program can be diverse: integer, character string, table, tuple, function... In Scol,
types are simply there to help the developer: the types are only used when compiling to detect most of the errors at
that stage. Thereafter, when you run your program, they are no longer used since the program has already been
proved to be correctly typed.
Typing is the operation whereby the types in your program are verified. This operation is performed at the same
time as the compilation (it is said to be static). For example, it detects that you are using a character string with a
function which requires an integer, but it can be much more subtle than that. When a type error is detected, the Scol
machine stops and displays an error message on the console window (and thus in the log file) explaining the nature
and position of the type error.
In Scol, typing is done by inference of type: this means that the compiler calculates the type of your functions
itself; you will not usually have to specify it. Scol typing is also said to be polymorphic. Certain functions do not
impose any type conditions on certain arguments, or certain parts of certain arguments.
The Scol language defines a syntax to write the types. This syntax is defined by the table below:
Type = B | un | rn
| tabType | [Type*] | fun [Type*] Type
TypeMono = B | rn
| tabTypeMono | [TypeMono*] |fun [TypeMono*] TypeMono
B = Basic type
un = dependent variable
rn = level n recursion
17
Here are some comments on the table in case you are not familiar with this notation.
The first line defines the Type expression, which is actually the Scol type. You then find the different ways of
writing the expression, separated by ‘|’: this can be:
- B, defined on the third line: it is a basic type, like I, S, F, ... Thus since I is a basic type, B can be written I, and
since Type can be written B, I is a type in Scol.
- un with integer n: u0, u1, u2, u3, ... are types: they correspond to the dependent variables (which we will detail at
a later stage).
- rn with integer n: r0, r1, r2, r3, ... are types : they define the recursions in the types (which we will detail at a later
stage).
- tab Type: table type. The word tab is followed by the type of the elements in the table. For example, tab I is the
type of a table of integers.
- [Type*]: tuple type. Between square brackets, you write several Types (represented by the asterisk *). For
example, [I S] is a tuple of two elements, the first of which is an integer, and the second a character string. The
tuple may be empty: [ ]. The tuple can itself contain tuples: [I [S I]]
- fun [Type*] Type: function type. The word fun is followed by a tuple containing the arguments of the function
then the type of the result. For example ‘fun [I I] S’ is a function which takes two integers as arguments, and
returns a character string.
The expression TypeMono defines the monomorphic (non-polymorphic) types: the only difference with Type is the
absence of dependent variables un.
3.3.a Polymorphism
Let's take another look at the polymorphism example fun f(x)=0;; If you compile an example containing this
function, you will see in the log file that the type detected by the compiler is: fun [u0] I.
u0 represents ‘Unknown 0’. This means that the type could not be determined and that it is immaterial. The 0
means you can differentiate the unknown types.
3.3.b Recursion
We have seen that tuples can be interleaved [I [S I]]. What happens with an infinite interleaving?
Let's look at the concept of a list in Scol. The List type does not exist in Scol; by convention, you define lists as a
tuple of two elements, the first of which is the first element in the list, the second the next in the list. Nil is the end
of the list.
In Scol, you will write the list of integers from 1 to 5 as follows: 1::2::3::4::5::nil, or equally:
[1[2[3[4[5 nil]]]]].
The type of a list of integers should be: [I[I[I[I ...]]]]
Note [I r1] the type of this kind of list: tuple whose second element is a level 1 recursion.
Other example: take an alternating ‘list’: [I[S[I[S ...]]]]. This ‘list’ alternates integers and character
strings. Note [I[S r2]] the type of this kind of list: tuple whose second element is a tuple whose second element
is a level 2 recursion. Note: this is not a real list, since a real list will normally only contain elements of the same
type.
18
Generally speaking, the only recursive types you will have to deal with will be lists, thus [I r1] for a list of
integers, [S r1] for a list of character strings, etc. However, it is possible that you will create – whether by
mistake or otherwise – functions whose type contains different recursion elements.
For those who want to take this matter further, you can represent a type by an oriented graph. The nodes are:
- the basic types (these are therefore end-nodes)
- the polymorphic types (these are therefore end-nodes)
- the tables: there is therefore 1 child which represents the type of the elements in the table
- the n-tuples: there are therefore n children each corresponding to one of the tuple's elements
- the functions: there are therefore 2 children, the first corresponding to the argument tuple, the second to the result
This graph actually looks like a tree. However, a branch can sometimes go from a node to a node which is itself, its
parent, its grandparent, or others besides. This is where the recursion comes into action: r1 for a branch going to
itself, r2 for a branch going to its parent, etc.
The nil constant has no defined type, or rather it has all the types at the same time.
A type is only valid if it does not contain any free variables: while “u0” and “fun [ ] u0” are syntactically
correct, they are invalid.
Typically, if you write a function whose type returns a result containing a un (for example fun [ ] u0), this
means that your function returns nil in all cases. You must simply replace one nil by 0.
There is a restriction to polymorphism due to side effects: variables are necessarily monomorphic, whereas
functions can be polymorphic.
Like any other programming language, Scol uses a very precise syntax. The table below defines this syntax
completely. If you are unfamiliar with this type of notation, refer to the previous chapter dealing with types: the
syntax for types uses the same notation, but is simpler. Remember that the * indicate that the element is repeated a
certain number of times (which may be zero). The braces leave the choice between several elements. For example,
{I,S}* corresponds to any given series of I and S. The characters in bold correspond to the syntax elements found
in the source file of a Scol program, while the elements in italics are rewrite elements whose meaning is given
elsewhere in the table.
A file written in Scol language simply contains the Scol element as defined in the table. The Scol element is simply
a series of definitions (Definition in the table).
There are 8 sorts of definitions:
- fun: function definition
- typeof: definition of a variable by its type
- var: definition and initialization of a variable
- struct: definition of a type of structure
- typedef: definition of type constructors
- defcom: definition of a communication constructor
- defcomvar: definition of a variable communication constructor
- proto: definition of a function prototype
19
You can skip the following table for now, but it will no doubt come in useful later on.
Scol = Definition*
Definition = fun Function (Args) = Program ;;
| typeof Var =TypeMono ;;
| var Var = Val ;;
| struct NewType = [ Fields ] Function ;;
| typedef NewType = TypeConstr ;;
| defcom Com = string {I,S}* ;;
| defcomvar Comvar = {I,S}* ;;
| proto Function = Type ;;
20
TypeConstr = TypeConstr’ | TypeConstr’ | TypeConstr
TypeConstr’ = Constr TypeMono | Constr0
- decimal : 12349
- hexadecimal : 0x3fe
- binary : 0b10011
- octal : 0o234235
They are coded on 31 signed bits.
The chars are used to retrieve a character's ASCII code: 'A is an integer equal to 65.
The character strings are written between quotes. The \ character is used to access certain commands:
\n : carriage return
\z : NULL character
\" : quote
\\ : \
\decimal number : \132 is the Ascii character 132
A \ at the end of the line tells the compiler to disregard the new line.
The (Program), (Program ;), {Program} and {Program ;} constructions are all equivalent.
21
5. Basic constructions
5.1.1 Variables
You can modify the value of a variable using the construction: set Var = Arithm
For example: set x=a+b
This produces a side effect: it is not the result of the set function you are interested in, it is the fact that the value of
x has changed.
5.1.2 Functions
To define a function, place fun in front of the name of the function followed by the list of arguments between
parentheses and separated by commas. Then the ‘=‘ sign precedes the body of the function which ends with a
double semicolon. For example, the sum function:
fun sum(x,y)=x+y;;
The typing will determine the type of the function: fun [I I] I
Here the function takes two integers and returns one integer.
You can write arithmetic expressions as standard: (x+y)*z/w. You can also use logical C operators: &,|, ^, <<,
>>, ~, &&, ||, !, ==, !=, <, >, <=, >=.
Arithmetic operations and comparison operations are also available for floating numbers (type F), however you
must place a point after the operator: +., -., >., ...
One of the most important constructions in programming is the conditional construction, i.e., the traditional ‘if ...
then ... else ...’. This construction exists in Scol in the same format:
if C then T else F
where C is a condition, T (respectively F) is the expression to perform if the condition returns true (respectively
false).
In Scol, you must always define the ‘else’ expression.
The condition is necessarily an expression that returns an integer. The result of the condition is considered to be
“true” if the integer is other than zero, and false if it equals 0. In the condition expression, you can use C Boolean
operators: && and ||. As in C, the expression is not necessarily completely evaluated:
-A && B : if A is false, B is not evaluated (the result is inevitably false)
-A || B : if A is true, B is not evaluated (the result is inevitably true)
The T and F expressions must return the same type, i.e. the type returned by the construction.
Indeed, the ‘if ... then ... else ...’ construction is a function which returns the value of T or of F according to the
value of the condition. The type of this function is:
fun [I u0 u0] u0
You can integrate the construction in an expression:
1+if x==0 then 1 else 3
22
This expression would equal 2 if x equals 0, 4 otherwise.
The same applies for the following function:
fun f(x)=if x then “a” else “b”;;
The f function returns the “a” string if x is non-null, “b” otherwise. In imperative languages such as C, you do not
have this type of operation.
5.1.4. Example
To allow you to carry out your tests, we will modify the hello3 program presented in a previous chapter.
file ‘Tutorial/[Link]’:
_load "Tutorial/[Link]"
main
file ‘Tutorial/[Link]’:
/* [Link] */
/* My tests */
fun sum(x,y)=x+y;;
fun mymain()=
itoa sum 10 30;;
/* Common part */
fun _end(a,b)=_closemachine;;
fun main()=
let _CRwindow _channel nil 150 150 400 300
WN_MENU|WN_MINBOX|WN_SIZEBOX "My Test"
-> win in
let _CRtext _channel win 1 1 398 298
ET_VSCROLL|ET_HSCROLL ""
-> text in
(_CBwinDestroy win @_end nil;
_CBwinSize win @_resize text;
_SETtext text mymain
);;
In this example, you simply display a text window in which you write (function _SETtext) the result of the
mymain function.
The mymain function must always return a character string. If you are using integers, use the itoa function to
convert them into character strings before returning them. Using itoa and strcat (which concatenates two
character strings), you can display all the results.
Here we are testing the sum function on two integers 10 and 30.
In the examples that follow, we will simply give the functions that are to be inserted in place of mymain and sum.
You can carry out your tests yourself.
23
5.2 Using tuples
Tuples are a very practical way of handling heterogeneous sets of data. Their use hides an automatic memory
allocation; that is why tuples do not exist in C. Only a language that automatically manages the allocation and
deallocation of the memory can really use tuples.
The term [Arithm*] constructs a tuple from different expressions present between square brackets. For example:
[ 1 2 nil [ 3 4 ] ]
is a size 4 tuple, whose last element is a size 2 tuple.
In this example, you start by creating a tuple called tupletest. The mutate function replaces the values 2 and
nil of the tuple with 5 and 6 respectively, without affecting the other fields (where you have inserted an
underscore ‘_’). This function is ‘dangerous’ since it modifies all the variables that refer directly or indirectly to the
tuple. It is better to recreate a tuple.
Example: we will create a size 3 tuple, modify the second element using mutate and display its status before and
after the modification.
/* My tests */
fun Tuple3toStr(t)= let t->[a b c] in
strcat strcat strcat strcat strcat strcat
"[" itoa a " " itoa b " " itoa c "]\n";;
fun mymain()=
let [1 2 3]-> mytuple in
strcat Tuple3toStr mytuple
(mutate mytuple <- [_ 10 _];
Tuple3toStr mytuple);;
You will notice that the value of the expression (Arithm1 ; Arithm2) is the value of the last Arithm2 term. This
means that the result of the first Arithm1 term is lost. This imperative approach (non-functional) is usually due to a
side effect: here, the mutate function creates the side effect. You can thus see the disadvantage of this approach:
the result of the first term is lost, which means that information has been lost. This information has therefore not
been verified during the typing, which renders the program more fragile.
When you run this program, you obtain the following result on the text window:
[1 2 3]
[1 10 3]
As we mentioned previously, lists in Scol are managed in the form of size 2 tuples. The first element of the tuple is
the first element in the list, the second element of the tuple is the next element in the list. For example, let l be a
list:
let l->[val next] in ...
This expression is used to respectively retrieve the first element in the list and the next element in the list in the
val and next local variables. The function which returns the first element in the list is called hd. The function
24
which returns the next element in the list is called tl. These functions are present in the Scol language, however
you can write them in Scol as follows:
The list always finishes with the empty list, equal to nil.
The easiest way to build a list is to use the ‘::’ list builder. For example, the expression
1::2::3::4::5::nil builds a list of the first five integers. The type of the ‘::’ function is:
fun [u0 [u0 r1]] [u0 r1]
Lists are a very important element in terms of functional languages because they are data structures of unlimited
size (the automatic memory management facilitates their use). They are also data structures which go well with
recursive processing.
Let us take a closer look at the lists and study the following examples:
In the following example, the mysizelist function calculates the size of a list. This function is recursive:
- the nil list has a size of 0
- any non-empty list has a size of 1 + the size of the list without its first element
/* My tests */
fun mysizelist(l)=
if l==nil then 0
else let l -> [_ next] in 1 + mysizelist next;;
fun mymain()=
itoa mysizelist 1::2::3::4::5::nil;;
In actual fact, the sizelist function is already defined in the language: you do not therefore have to rewrite it
yourself, but it offers a good example.
The conc function takes two lists p and q and returns a new list which concatenates both lists in this order. It is a
recursive function:
- if p is the empty list, the concatenation of p and q equals q
- otherwise the concatenation of lists p and q is a list in which:
- the first element is the first element in list p
- the rest of the list is the concatenation of list p without its first element or list q (recursion).
25
The dividelist function is a little more complicated: its role is to divide a list into two sublists according to an
integer called the ‘pivot’. The elements in the list are placed in one of the two sublists depending on whether they
are less than or greater than the pivot. Here is an important tip: the dividelist function returns two lists, where
normally a function can only return a single result. The solution is to use tuples: the dividelist function
returns a tuple with two elements which are the two sublists. Thus, in Scol, tuples are basically used for two
purposes: to manage lists, and to group elements together to form a single element, which is easier to manage.
The dividelist function is not polymorphic, since it supposes (through the use of the > function) that it is
processing a list of integers.
The quicksort function thus works on the basis of a very simple recursive principle:
- the sorted empty list is always the empty list
- if the list is not empty, by taking the first element in the list for the pivot, the sorted list is the concatenation of:
- the sorted list of elements less than the pivot
- the pivot
- the sorted list of elements greater than the pivot
The quicksort function is not polymorphic since it calls the dividelist function.
The display function is simply used to create a character string representing the list, where the elements are
separated by ‘::’ and which ends with ‘nil’. This function is not polymorphic, since it supposes (through the use of
the itoa function) that it is processing a list of integers.
Later on, we will see a quicksort variant which works on ordinary lists.
/* MyTest */
/* concatenation */
fun conc(p,q)=
if p==nil then q
else
let p -> [a n]
in a::conc n q;;
/* quicksort */
/* display list */
fun display(l)=
if l==nil then "nil"
else
let l->[a n]
in strcat strcat (itoa a) "::" display n;;
fun mymain()=
26
display quicksort 3::5::2::8::6::nil;;
Tables are rarely used in a functional language. Lists are used as a preference for three reasons:
- Tables are less suitable for recursive algorithms.
- Tables are not expandable; you define their size once only.
- You cannot prevent the developer from writing a program that attempts to use a cell in the table outside its limits.
This index overflow cannot be detected during the compilation, and is thus a source of error.
However, the table holds one advantage over the list: elements are all accessed in constant time.
A table can in particular be created using the mktab command, which takes the size of the table and an
initialization value as arguments.
The i-th element in the table T is accessed by writing: T.i
If the table T is a table of tables, the j-th element of the i-th element of T is accessed by writing: T.i.j (indexes
can be accumulated without limit).
To modify a value in the table, you simply write: set T.i = ...
The “ set X = V ” function returns the value V (the storage of V in X is merely a side effect).
The “ while Condition do Expression ” function calculates the condition (which must be an integer). If this integer
is true, the expression is calculated and the condition evaluated again until it is false. It returns the result of the last
expression calculated (nil if no expression was calculated, i.e., if the condition was false right from the first
evaluation).
The “ let X -> N in Y ” function calculates X, creates the local variables contained in N then calculates Y and
returns the result of Y. The static scope of variables contained in N is limited to expression Y.
Structures are used a bit like in C. A structure is a particular type containing one or more fields. Each field is
defined by a field name and an associated type. For example, a structure Rec containing three integers and a string
is written:
In this example, the developer chooses the names Rec, xRec, yRec, zRec, nameRec and mkRec. The only
constraint is that the name of the new type (here Rec) must begin with an uppercase letter.
Where x is an object of type Rec, the different fields are accessed by writing [Link], [Link], [Link] or
[Link]. The names of the fields are considered as functions: for example, xRec is a function of type “ fun
[ Rec ] I ”. For this reason, if two structures use the same field name, there will be an overlap: the second
definition will hide the first.
To build an object of type Rec, you need a constructor: this is the role of mkRec which, in this case, is a function
of type “ fun [[I I I S]] Rec ”. Example:
fun main()=
let mkRec [1 2 3 "abc"] -> r
in [Link];;
27
To modify the value of a field, simply write:
set [Link] = ...
In some cases, it can be useful to use a variable with several different types: in variable x, you sometimes want an
integer, other times a character string, and other times a tuple. Typing forbids this type of operation. To make it
possible, you must use the equivalent of the union in C: these are type constructors. Take an example:
typedef U =
xU I
| sU S
| tU [I I]
| nU ;;
This defines a new type U, which can contain either an integer, a string, a two-integer tuple or nothing at all. The
names xU, sU, tU and nU are called type constructors. They are considered as functions. For example, xU is a
function of type “ fun [ I ] U ”.
We refer to them as constructors since only they can be used to construct an object of type U. The object
constructed in this way contains two pieces of information: the name of the constructor used, and the useful value.
The last nU constructor is special since it does not use a value; it is called constructor0.
fun numconstr(x)=
match x with
(xU u -> 0)
|(sU v -> 1)
|(tU [u v] ->2)
|(nU -> 3);;
This function takes an element x of type U, and returns 0, 1, 2 or 3 respectively for x constructed with xU, sU, tU or
nU. You can define one line of cases by default:
fun from_sU(x)=
match x with
(sU u -> 1)
|(_ -> 0);;
This function takes an element x of type U and returns 1 if x was built with sU, 0 in all other cases.
If the program does not define any cases by default (_->…), the compiler “adds” the line (_->nil).
The match function is not content with merely finding a variable's constructor, it also retrieves the value of the
construction, as illustrated in the following example:
/* MyTest */
typedef Node =
Int I
| Add [Node Node]
| Mul [Node Node];;
fun EvalNode(n)=
match n with
(Int x -> x)
|(Add [a b] -> (EvalNode a)+(EvalNode b))
|(Mul [a b] -> (EvalNode a)*(EvalNode b));;
28
fun mymain()=
itoa EvalNode Mul [Add [Int 1 Int 2] Int 3];;
In this example you define a Node type used to code trees of expressions containing integer constants, additions
and multiplications. The EvalNode function calculates the values of such a tree.
Here, the mymain function calculates the tree corresponding to the expression: (1+2)*3
Scol can handle functions in the same way as integers or character strings. To do so we use language commands.
The '@' operator is used to convert a function name to a function object. Thus, the compiler considers that a
function name not preceded by '@' represents a call to the function, with the parameters that follow. When
preceded by '@', the compiler considers that a function object must be created for a subsequent operation.
In order for the handling of functions to be useful, you need to be able to apply a function object to a set of
arguments and calculate the result. For this purpose you use the exec...with... function. Example:
The three main1, main2 and main3 functions return the same result.
The type of the foo function is noteworthy:
foo : fun [u0 u1 fun [u0 u1] u2] u2
Indeed, the foo function takes two ordinary arguments x and y and a function f which is not ordinary: it is a
function which takes two arguments of the same type as x and y (types u0 and u1). The foo function returns a result
of the same type as the f function.
Here you will note that the use of functions in Scol is done in a manner completely controlled by typing.
Another way of using functions consists in creating a function from another function and from an argument. We
will call this a node. Scol provides a function that performs this operation:
Example:
The g function defines an h function which is equal to the f function, an argument of which we will have set (here
the second).
- the type of f is: fun [ S I ] I
- the type of h is: fun [ S ] I
To generalize the mknode function, you define functions mkfun1, mkfun2, ..., mkfun8. For example mkfun8 takes
a function with 8 arguments and an argument, and returns a function with 7 arguments.
29
Note that the mkfun2 function is the same as the mknode function.
In a Scol file, you can only declare a name once. Furthermore, an f function referenced in a g function must be
defined upstream of the g function.
When compiling several Scol files in succession, you can redefine a name defined in a previous file, with the
exception of type names.
In some cases, it can be useful to predefine the type of a variable or function. This is essential for variables that
include types other than tuples, lists, integers and character strings. It is also essential when two functions call each
other.
Example 1:
/* definition of an integer list-type variable */
typeof x = [ I r1 ];;
var x= [1 [2 [3 nil]]];;
/* without the typeof, the language would determine the type of x as [I [I [I
u0]]], which contains a free variable */
Example 2:
/* functions which refer to each other */
proto g= fun[I] I;;
Example 3:
/* definition of an empty integer list variable */
typeof x=[I r1];;
fun f()= set x = [1 [2 [3 nil]]];;
Conversely, you can define a variable, a prototype, a type constructor or a structure calling on a type which has not
yet been defined. You will be able to define this type later (in a subsequent package for example), but only once.
You are now familiar with all the Scol language calculation principles. We shall now present a variant of the
quicksort program; this time it will be polymorphic, and will be used to delete duplicates (elements present twice in
the list).
The idea is fairly simple: you give the quicksort function a list to sort and a function for comparing two elements in
the list.
This function – which has two arguments (the two elements to be compared) – must return:
- a strictly positive number if the first element is greater than the second
- a strictly negative number if the first element is less than the second
- zero if both elements are equal and provided you want to delete the duplicates from the list. If you do not want to
delete the duplicates, simply return any non-null integer when two elements are equal.
The following program performs two sorts: one on a list of integers, another on a list of character strings. The
display functions are not polymorphic: there is one to display the list of integers, and another to display the list of
character strings.
30
Here, the type of the quicksort function equals:
fun [[u0 r1] fun [u0 u0] I] [u0 r1]
In the mystrcmp comparison function, note the use of the strcmp function. This function, which you will find
in most programming languages, compares two character strings. It returns 1 if the first is greater (in alphabetical
order) than the second, -1 if the first is less than the second, 0 if the two strings are equal.
/* MyTest */
fun conc(p,q)=
if p==nil then q
else (hd p)::conc (tl p) q;;
fun quicksort(l,f)=
if l==nil then nil
else let l->[vl nl] in
let dividelist vl nl f->[va na] in
conc quicksort va f vl::quicksort na f;;
/* display list */
fun displayIntList(l)=
if l==nil then "nil\n"
else
let l->[a n]
in strcat strcat (itoa a) "::" displayIntList n;;
fun displayStrList(l)=
if l==nil then "nil\n"
else
let l->[a n]
in strcat strcat a "::" displayStrList n;;
fun myintcmp(a,b)=a-b;;
fun mystrcmp(a,b)=strcmp a b;;
fun mymain()=
strcat
displayIntList
quicksort 3::5::2::8::6::5::nil @myintcmp
displayStrList
quicksort "ab"::"abc"::"xy"::"www"::"pqr"::nil @mystrcmp;;
You will notice that the duplicates have indeed been deleted, i.e., the number 5 which appeared twice in the list to
be sorted.
31
5.11 Standard library
In this section, you will find the list of basic functions in the Scol language. The type is indicated for each function.
The functions are grouped into several categories:
- functions on integers
- functions on character strings
- functions on lists
- functions on tables
- functions on floating numbers
- time functions
- console functions
Besides the classic functions found in all programming languages, you will notice in particular the following
functions:
- zip and unzip: compression and decompression of a character string.
- strextr and strbuild: breakdown of a string into a list of lines, whereby each line is a list of words. This simplifies
all problems relating to parsing.
- _getlongname: function for hashing (or signing) a character string.
rand : fun [] I
Returns a random integer, between 0 and 32767.
max : fun [ I I ] I
Returns the max of two integers.
min : fun [ I I ] I
Returns the min of two integers.
abs : fun [ I ] I
Returns the absolute value of an integer.
mod : fun [ I I ] I
Returns the remainder of the division of one integer by another.
strlen : fun [ S ] I
Returns the size of a character string.
For example, strlen “12abc345de” returns the integer 10
strcat : fun [ S S ] S
Concatenates two character strings (the two initial strings are not modified).
For example, strcat “12” ”abc” returns the string “12abc”
strcmp : fun [ S S ] I
Compares two character strings (using the standard C function). Returns 0 if the two strings are identical, 1 or –1
else.
32
strfind : fun [ S S I ] I
Searches for the first string in the second string from the position passed as a parameter (the first character is in
position 0). Returns nil if the string was not found, or else the position in which the string was found.
strfindi : fun [ S S I ] I
The same as above, but without taking into account the differences between upper and lowercase characters.
strtolist : fun [ S ] [ I r1 ]
Reverse of the previous function.
For example strtolist “ABC” returns the string 65::66::67::nil
atoi : fun [ S ] I
Interprets a character string as an integer.
For example, atoi “53” returns the integer 53
itoa : fun [ I ] S
Reverse of the previous function.
For example, itoa 53 returns the string “53”
ctoa : fun [ I ] S
Creates a character string containing a single character of ASCII code.
For example, ctoa 65 returns the string “A”
htoi : fun [ S ] I
Interprets a character string as an integer coded in hexadecimal (unsigned).
itoh : fun [ I ] S
Reverse of the previous function.
substr : fun [ S I I ] S
Returns a substring of the string passed as an argument.
The first integer gives the substring's initial position, whereby the first character is in position 0, and the second
integer gives the substring's size.
For example, substr “abcdef” 2 3 returns the string “cde”
strdup : fun [ S ] S
Creates a copy of a character string in the memory. This is only useful when you modify a character string "on the
spot" using the set_nth_char function defined below.
strlowercase : fun [ S ] S
Creates a copy of a character string, replacing the uppercase letters with lowercase ones.
struppercase : fun [ S ] S
Creates a copy of a character string, replacing the lowercase letters with uppercase ones.
strcmpi : fun [ S S ] I
Compares two character strings without considering upper/lowercase (using the standard C function).
nth_char : fun [ S I ] I
Returns the n-th character of a string.
set_nth_char : fun [ S I I ] S
Modifies the n-th character of a string (danger: the string is modified "on the spot", all the pointers to the string are
affected by this modification; this is a side effect).
33
zip : fun [ S ] S
Compresses a character string.
The compression rate is 60\% on average.
unzip : fun [ S ] S
Reverse of the previous function.
strtoweb : fun [ S ] S
Converts an ordinary character string into one only containing alphanumeric symbols as well as ‘+’ and ‘%’:
alphanumeric characters are retained
spaces are replaced by ‘+’
other characters are replaced by a ‘%’ followed by 2 hexadecimal digits.
webtostr : fun [ S ] S
Reverse of the previous function
This function returns the concatenation of S2, of the signature's specific character and of the signature of the S1
string.
For example, strextr “abc def\n1 23 456” returns the double list
(“abc”::”def”::nil)::(“23”::”456”::nil)::nil
35
5.11.5 Functions on floating numbers
itof : fun [ I ] F
Transforms an integer into a floating number.
ftoi : fun [ F ] I
Transforms a floating number into an integer (by rounding the floating number).
ftoa : fun [ F ] S
Transforms a floating number into a character string.
atof : fun [ S ] F
Reverse of the previous function.
absf : fun [ F ] F
Calculates the absolute value of a floating number.
PIf : fun [ ] F
Returns the constant pi.
cos : fun [ F ] F
Cosine function.
sin : fun [ F ] F
Sine function.
tan : fun [ F ] F
Tangent function.
acos : fun [ F ] F
Arc cosine function.
asin : fun [ F ] F
Arc sine function.
atan : fun [ F ] F
Arc tangent function.
atan2 : fun [ F F ] F
Arc tangent function with two arguments: “atan2 y x” returns the signed angle formed between the axis of the
abscissa and the point (x,y).
Ef : fun [ ] F
Returns the constant e.
log : fun [ F ] F
Logarithm function.
log10 : fun [ F ] F
Logarithm function in base 10.
exp : fun [ F ] F
Exponential function.
pow : fun [ F F ] F
Power function: ``pow x y'' returns x to the power of y.
sqr : fun [ F ] F
Calculates the square of a floating number.
36
sqrt : fun [ F ] F
Calculates the square root of a floating number.
rootn : fun [ F F ] F
Calculates the n-th square of a floating number: “ rootn x y ” returns x to the power 1/y.
time : fun [] I
Returns the number of seconds passed since January 1st 1970.
ctime : fun [ I ] S
Returns a character string giving the time and date in the following format: ``Tue Jan 21 11:24:53 1997''. The
parameter is the number of seconds passed since January 1st 1970, typically issued from the previous function.
_tickcount : fun [] I
Returns the number of milliseconds passed since the machine was started.
_showconsole : fun [ ] I
Displays the console.
_hideconsole : fun [ ] I
Hides the console.
The Scol machine manages a list of resource variables which we will simply refer to as ‘resources’. These
variables are defined by their name, and are associated with a character string. They are independent of the channel
management, and in particular outlive the channel which defined them.
_setress : fun [ S1 S2 ] S
Defines the resource S1 with the value S2 and returns S2. If the resource did not exist, it is created. If it existed, the
new value is assigned to it. If S2 equals nil, the resource is destroyed.
37
Scol uses a resource initialization file, called [Link], located in the Scol directory (usually C:/Program
Files/Scol). This is a text file containing lines of two words, whereby the first is the name of a resource and the
second the corresponding value.
This file is analyzed at the start of the SCOL machine's operation using the following function:
fun multiress(res)=
if res==nil then 0
else let res ->[[l n] nxt] in
(if strcmp l "#" then _setress l hd n else nil;
multiress nxt);;
...
multiress strextr _loadressini;
...
There are two special variables which can be considered to be resources: the version number and name of the
SCOL machine:
_version : fun [ ] I
Returns the version number.
_versionname : fun [ ] S
Returns the version name.
38
The order in which the following chapters are presented is of no special importance. It is up to you to establish your
own order according to the topics that interest you. If you are interested in the details of the Scol language, start by
reading the sections on Channels and communications and File management.
If you are impatient to start developing your first programs, go straight on to the section dealing with event-driven
programming.
1. Manipulating channels
We saw at the beginning of the previous chapter that the Scol machine is based on the notion of the channel. The
Scol machine is multi-channel. Each channel is a pair (environment, network connection). The network connection
is usually a TCP/IP or UDP socket-type connection. However, there may be no network connection, in which case
it is called unplugged.
Channels and environments are objects that can be easily manipulated in Scol. Two types are therefore associated
with them:
- the Chn type represents a channel.
- the Env type represents an environment.
39
_removepkg : fun [ Env ] Env
Returns the environment from which you retrieved the package located at the start (i.e., the last package compiled).
Since a channel is a pair (environment, network connection), to create a channel you have to specify both elements
of the pair. To do this you use the _openchannel function. This function creates either an unplugged channel or
a channel with a TCP/IP connection.
The function returns the channel created. This is nil in the event of an error.
The _openchannel function operates as follows: a new channel is created with the environment passed as a
parameter and the possible network connection. Then the script is run on this new channel.
Example: you want to create an unplugged channel which inherits the environment of the current channel, and in
which you want to compile the package “[Link]” and run the main function located in this package. You need to
write:
_openchannel nil “_load \”[Link]\”\nmain” _envchannel _channel
In order to open a channel to port 2000 of a machine whose IP address is [Link], give it the minimal environment,
compile on it the package “[Link]” and run the main function located in this package, you need to write:
_openchannel “[Link]:2000” “_load \”[Link]\”\nmain” nil
You can create a channel whose network connection is a UDP listening socket:
_setUDP : fun [ Env I S ] Chn
This function takes an environment, a port number and a script. A UDP channel is created on the port whose
number is given, with the specified environment in which you begin by running the script.
40
Remember that UDP messages are not totally reliable: transmission and order of arrival are not guaranteed.
However, because there is no buffering, the latency of transmission is negligible.
The UDP channel is not connected to another channel: several correspondents can send messages to this channel,
and there is even a broadcast potential.
_closechannel : fun [] I
Closes the current channel.
_closemachine : fun [] I
Closes all channels, and therefore stops the SCOL machine.
We have just seen how to open TCP/IP channels using the _openchannel function. To do this, we saw that you
have to specify the correspondent’s IP address and port number. This means that the correspondent “waits for” this
type of connection. In network terminology, the correspondent is said to have opened a server on this port.
Obviously, the Scol language can be used to open and manipulate these servers. These are Srv-type objects.
When a connection to this server is requested, i.e., when another machine has run the _openchannel function
with this server’s address, a new channel is created. This channel inherits the environment defined with the server.
The script defined with the server is then immediately run in this new channel.
Once created, a server channel is indistinguishable from a client channel. This is one of Scol’s key concepts: once
the connection is made, communication is symmetric.
For example, let us suppose that the following function is called on Alice’s machine:
_setserver _envchannel _channel 2000 “_load \”[Link]\”\nmain”
A server is created on port 2000. The environment defined with the server is the current environment. The script
defined with the server compiles the “[Link]” file and runs the main function.
When a connection is opened from another machine, let’s say Bob’s, a channel is created on Alice’s machine,
which inherits the environment and in which the script is run. There is now on Alice’s machine a channel that is
connected to a channel on Bob’s machine. This connection is symmetric and allows data to be exchanged between
both machines.
41
1.5 Additional functions of channel management
_hostname : fun [] S
Returns the host name. If the host has no defined name, returns ``localhost''.
_hostIP : fun [] S
Returns the host’s IP address: if the host does not have one, returns “[Link]”.
As we indicated earlier, here we specify script syntax. Scripts are used in a number of cases:
- start-up *.scol files on the Scol machine.
- _script functions and _scriptc.
- the functions which create channels and servers, such as environment initialization scripts.
In the character string, the backslash character (\) has a particular significance:
\n: 10 character
\z: 0 character
\ decimal number (three figures at most): any code character
\other: the backslash is ignored and you skip to the next code character greater than or equal to 32
Thus for the \ character, we shall use \\. For the " character, we shall use \".
Each line of script is interpreted as a command followed by arguments. These arguments may be either integers,
character strings, or NIL (the only possibility for the other types).
42
NB:
*.scol files must not be too long: in fact, their size is limited by the size of the command line accepted by Windows.
Restrict yourself to three or four lines. In other uses of scripts, there is no limit to the size of the script.
2. Communications in Scol
Opening a channel with the _openchannel function takes a certain amount of time (up to a few seconds). The
computer has to find its way through the network, then communicate with the other machine to check that a server
is indeed open. This raises the question: when is the connection really established?
The _openchannel function is in fact virtually instantaneous: the channel is created immediately, the network
connection is started and the program continues before the connection becomes fully active.
When the connection is made, the Scol machine looks for a ‘_connected’ name function of the type:
fun [ ] ?
(The question mark means that the machine is not concerned with the result type of the _connected function.)
If the _connected function has not been defined, nothing happens and the machine continues as normal,
otherwise the _connected function is run.
The same thing happens on the server: a channel is created on the machine that hosts the server, the script is run on
it, and the possible _connected function is then triggered on it.
Another network event may occur unexpectedly: disconnection. This may be due either to the correspondent
destroying the channel or shutting down the machine, or it may be due to a network problem. In this case the Scol
machine closes the channel which lost its correspondent, but before it does so it looks for a ‘_closed’ name
function of the type:
fun [ ] ?
If the _closed function has not been defined, nothing happens and the machine continues as normal, otherwise
the _closed function is run.
Similarly, if the server has reached the maximum number of simultaneous connections that it can handle (10 with
the free version of the Scol virtual machine), the _fullserver function is run in the server’s environment, and
the message '__FullServer' will be sent to the client just before closing the connection.
Once a channel is created, messages may be sent in both directions. The messages that circulate are always in the
form of “command arguments”. In fact, they take the form of a single-line script. When a message arrives, the Scol
machine looks in the environment of the channel for a function whose name is “__command” (the double
underscore is added by the receiving machine and ensures that only functions beginning with a double underscore
can be activated by the correspondent). If this function exists, the Scol machine checks the type of arguments. If
everything corresponds, the function is run and the result is lost: only the side effects will count.
43
The Scol language provides a simple solution for using the channel in the send direction. Let’s take the following
example: Bob wants to send on the channel AliceChannel the foo command with three parameters: two
integers, 123 and 345, and a string, "bar".
The function you use is called “_on”, it is of the type: fun[Chn Comm] I.
To make it simpler to write, the same name may sometimes be given to the command and to the communication
constructor:
NB: messages produced by communication constructors for sending using the _on function should not be too long
(less than 8 Kb).
There is a variant with defcomvar. This variant is particularly good for the use of “callbacks”. For example, let
there be a “call” function which takes a string and an integer at the start and has to send a message with an
argument that is the integer and a command that is the string. The static definition of the command name with
defcom cannot solve this case. The defcomvar function must then be used:
defcomvar Y = I;;
fun call(s,i)=
_on AliceChannel Y s [i];;
The Y function created here has the type “fun[S [I]] Comm”. The string that it waits for will be used as a
command.
44
2.3 Controlling message queues
When a message is sent by the _on function on a TCP/IP-type channel, it is placed in a queue particular to the
channel. The Scol machine tries to send it as quickly as possible. The size of the queue (called fifo: First In First
Out) can usefully be controlled by means of two functions:
Note: the Scol fifo is located between the Scol application and the computer’s network layer fifo, whose size is
difficult to calculate. Restricting the size of fifos is primarily to protect the Scol machine from having insufficient
memory, since channel fifos and Scol applications coexist in the same memory strip.
We have seen how to create a UDP channel with the _setUdp function. This channel is actually a UDP server: it
listens on a particular port for UDP messages that are sent to it. These messages are also Comm-type objects, and
when a message arrives, the Scol machine looks in the environment of the channel for a function whose name is
“__command”, exactly as with the _on function.
You can also send a UDP message via a UDP channel (created by _setUDP), using the following function. This
may be useful for getting past some proxies in the outer to inner direction: in fact, some links remember that an
internal UDP “server” sent a message to an external UDP server, and then authorize it to respond, which enables
UDP messages to get past the link in the outer to inner direction:
_sendUDPchn : fun [ Chn S Comm ] I
The string contains the correspondent’s address (in the same format as for _openchannel). A broadcast address
may be used.
In contrast to a TCP/IP channel, a UDP channel is not associated with a single machine: everyone can send it a
message. It may be useful on the UDP channel to know the IP address of the person who sent it a message. For this
you use the _channelIP function described above. In fact, the value returned by this function is updated every
time a message is received.
Above we mentioned the similarity of syntax between Communication (Comm) messages and scripts, specifying
that a communication is in fact a single-line script. Moreover, we saw that on the one hand communication
constructors make it particularly easy to define a Comm message, while on the other hand the syntax of scripts is
rather complicated.
A program might need to build a character string itself that will be used as a script. It would not be easy to build it
“manually” using functions on character strings, especially if the script contains character-string arguments that
include special characters such as “ and \, or if the script contains integer arguments to be written in hexadecimal
notation.
45
To simply this task, the Scol language provides a link between Comm objects and S character strings; the
following function is used to convert a Comm structure into a string that can be used by a script:
The principle of communication in Scol is thus as follows: machines exchange messages with each other on
channels. When a machine receives a message on a channel, it looks to see if this message is of a sort that will
trigger a process: for this, a function is needed that corresponds to the message, with the right number and the right
type of arguments.
One of the axioms of Scol technology is that it is impossible to be sure of the correspondent’s integrity. In concrete
terms, what this means is that if A sends B a message X supposedly to receive a response Y, there is no guarantee
that response Y will in fact be sent. The only thing A is certain of is how it processes the messages it receives. In
this sense, communication in Scol assumes a human character: when you speak, you can never be sure that you are
understood, regardless of the effort you make. It may be objected that often machines A and B are programmed by
the same person and that, in this sense, the developer knows very well that B will respond with message Y when it
receives message X. However, even in this case, the precautionary principle should apply since you will thereby
guard against:
- your own errors. In the previous example, if you programmed A and B yourself so that A sends message X
and B responds with message Y, it is quite possible that you made an error and that B does not respond. This is
all the more likely given that communications, being side effects, cannot be verified statically.
- acts of malice. One or other of the correspondents A or B may have been modified with an intent to cause
damage. In this case, A may receive a message Y in "response" to a message X that it has not sent. Similarly,
B may receive a message X at a time other than that anticipated by the developer.
1. Do a communications diagram, i.e. write a list of the messages exchanged between correspondents. Specify the
function, number and type of arguments. Your diagram should clearly show the dialog between machines, rather
like the script for a play.
2. Specify how the machine should behave when it receives a message. Your specification should not presuppose
the time at which the message is received: it should cover every eventuality, even if this seems unnecessary, for the
simple reason that a message may arrive at any time, either because of a malfunction or through a malicious act.
Quite often, this behavior will specify that one or more messages be sent which might wrongly be considered as a
response.
4. Write down the functions in Scol which code this behavior. The situation is reversed in some way by appearing
to consider the Scol program as a side effect of the message received.
46
In the log file, you can review all the messages received, preceded by the word "exec". When an error occurs, the
file indicates that the message cannot be interpreted either because it does not correspond to any function, or
because the number or the type of arguments is incorrect. In this case, the message is simply ignored.
47
V. File management
The Scol machine has limited access to the files on your computer. Access is established by defining one or more
directories known as Scol partitions. The Scol machine can only access files located in one of these directories or
in one of their subdirectories. At a given moment, only one of the Scol partitions will be accessible in write mode.
1. Scol partitions
A Scol partition is simply a directory of the disk to which the Scol machine has access. It may also access all of its
subdirectories.
Several partitions may be defined. You are recommended to define at least 2, as the first one has a special role.
These are usually as follows:
- The first partition is the cache partition: when a user visits a site, this is the partition in which the files
downloaded from this site will be stored. A quota may be defined for this partition: the system will check that the
number of files present in this partition does not exceed the quota.
- The second partition is your working partition: this is the partition in which your tools and your own creations are
located. Your tools may write in this partition.
- The subsequent partitions are additional caches.
Thus the underlying security mechanism is clear: each time a user connects to a site, the cache partition will be
activated: all files will be written in this partition. As this operation cannot be reversed, the site cannot deactivate
the cache partition and write in the other partitions.
Partitions on the Scol machine are also defined in the [Link] file located in the Scol directory (usually C:/Program
Files/Scol). This is a text file in which the lines beginning with ‘disk’ each define a partition: a path, which may be
followed by a decimal number indicating the quota. As we have just seen, the order is important: the first partition
defined will be the cache partition.
The figure 0 opposite the /partition/ partition indicates that the working partition is accessible in write mode.
_cacheActivate : fun [ ] I
You can modify the path of a partition dynamically. This can only be done in a highly specific way, by extending
the partition path. For example, if the partition was C:\Scol\A, you can change it to C:\Scol\A\1, but you cannot
obtain C:\Scol\B. You use the _refine function, which just extends the path of the first partition (possibly by
adding the missing ‘/’). This suffix must not contain some character sequences (‘..’,’ ~’,’//’, ...).
48
_refine : fun [S] S
This function is useful for managing a multi-user system. Several Scol machines can thus operate simultaneously
in different partitions by being connected to the same Scol Engine (see the Scol Engine section further on). The
Scol Engine starts the users’ machines simply by inserting at the beginning of the start-up script for these machines
a _refine function with the subdirectory dedicated to the user as an argument.
2. File types
SCOL provides two file types: normal files and signed files.
In this mode, the user gives the file name without restriction. In read mode the file is searched in the different
partitions, while in write mode the file is placed in the partition which is accessible in write mode (cache partition
or working partition). This mode provides a low level of security: a file is accessible in read and write modes as
soon as its name is known. Characters that may be used to write a file name are: alphanumeric characters, period,
underscore, space, tilde, dash and slash. For security reasons, the system has the following restrictions:
In this mode, the user gives a clear text file name, as defined above, to which the system appends a
cryptographic-type signature on the file’s contents. This signature starts with a special character that determines
the type of signature (in the first signature implemented, the '#' character), then continues and ends with a
succession of alphanumeric characters.
It is therefore virtually impossible to guess the name of any file if its contents are unknown. Furthermore, the
contents of a file of this type cannot be modified: any modification results in a change of signature, and hence a
change of name. Signed files thus provide a high level of security.
Another useful feature of the signature is that it quickly and accurately determines whether a file has already been
loaded; usually, when users contact a Scol server, they are given a list of the packages they will need. By using the
signature, users can find the exact packages they already have in their partitions. In particular, this automatically
solves the problem of updating.
You can sign a file with any word: it will be separated from the clear text file name by the ‘;’ character. This word
will be called the ‘cookie’ word. A Scol machine can define a ‘cookie’ word once by using the following function:
Given that you cannot redefine a ‘cookie’ word, this function is used to protect certain files. Usually, a machine
used in standard client mode will use the server’s IP address as the cookie word, even before it compiles the
packets indicated by the server. Files signed with this cookie will be inaccessible to clients of other servers.
49
For security reasons, when a Scol machine which has activated its cache starts another Scol machine, this new
machine:
- automatically activates its cache itself on start-up
- defines the cookie ‘__’
The P type has been created to use files (P is for Path). It remains globally invisible to the user. For special
operations in write mode, the W type is introduced.
To read a file you need to know its name relative to the Scol partitions (S-type character string). The
_checkpack function is used to search for this file in the different partitions and to return a P-type object which
actually contains the exact path of the file. You can then use this P-type object for read operations. The only
exception is the _load function, which is used to compile a package; it performs both operations itself (looks for
the file and reads).
To write a file, you need to know its name (S-type character string). If you already have the contents of the file to
be written (in a character string), you use the _storepack function. If you want to write the file in several stages
(streaming), you use the _getmodifypack function to obtain a W-type object which will be used by the
_createpack and _appendpack functions.
In Scol there is no means of knowing the complete path of a file; indeed, this would pose a security problem.
_storepack : fun [S S] I
Saves the first argument with the second as a name. When this name has a signature, the signature is checked. The
result is 0 if successful. The subdirectories contained in the name are automatically created if necessary.
_createpack : fun [S W] I
Opens the W file in write mode, by reinitializing it and writing the S string.
Returns 0 if successful, -1 in the event of an error.
_appendpack : fun [S W] I
Opens the W file in write mode and adds the S string at the end of the file.
Returns 0 if successful, -1 in the event of an error.
50
Converts W type to P type. The opposite is not possible, for security reasons.
This function returns the complete name (name in clear text possibly followed by the signature).
This function has already been described in the standard library relating to character strings.
fun main()=
let _checkpack "[Link]" -> path
in if path==nil then -1
else let _getpack path -> n
in if n==nil then -1
else let _getlongname n "bar" "#" -> n2
in if n2==nil then -1
else _storepack n n2;;
It is useful to have more refined functions for reading files. For this purpose, a File type is defined which
corresponds to an open file in read mode. This object is obtained using the _FILEOpen function from a P-type
object. This object is also associated with a channel: it will be automatically destroyed when the channel is
destroyed.
51
I _FILESize (file File)
Returns the file size.
You can call the file selection graphic interface in read mode or in write mode. Refer to the reference manual for
details.
52
VI. Event-driven and graphic interface programming
Here we shall describe the basic principles of event-driven and graphic programming:
- event-driven programming: how to manage the events that the Scol machine receives (timers, human-machine
interface, etc.)
- graphic programming: creating graphic and, more generally, multimedia objects
We shall use two examples to illustrate these principles: windows and (a non-graphic example) timers.
The Scol graphic interface is the machine’s largest API. It is used to manage windows, text zones, buttons, lists,
menus, character fonts, bitmaps, etc. It is described in detail in the reference manual.
1. Basic principles
We refer to an object to designate any resource (graphic or otherwise) "external" to the Scol language: window,
button, bitmap, timer, etc.
In Scol, a channel, said to be proprietary, corresponds to each object. Thus, when you create an object (window,
button, timer, etc.), you must specify the object’s proprietary channel. The object’s existence is linked to the
channel’s existence. The existence of the object will be associated with that of the channel. When you close a
channel, all the associated objects are quite simply destroyed.
In the File management section we saw the example of File-type files. To create such an object, we used the
_FILEOpen function, type fun [Chn P] File. Here you can see how the proprietary channel has been
specified: it is the first argument.
Similarly, the type of the CRwindow function encountered in the ‘Hello World’ examples is:
_CRwindow : fun [Chn ObjWin I I I I I S] ObjWin
The ObjWin type corresponds to a window object. To create a window, you thus specify the proprietary channel,
followed by the parent window, then by various arguments that define the window’s position, size, type and title.
The role of the proprietary channel goes beyond merely destroying objects when the channel is closed. It also
involves the management of events.
Most objects are likely to receive events. For example, you can click on a window. You can move a window. You
can press a button. Each of these actions corresponds to an event which the program must process. Similarly, the
role of a timer is to initiate an event at regular intervals.
The following question arises: how does a Scol program receive the events?
This question is posed for any operating system; however, the answers are often different.
In Windows, the program defines a function which is called each time an event is produced by the system,
whatever the event. In UNIX, with X-Window (X11), the principle is similar, but users can choose which events
their function is to receive. In both cases, the function "sorts" the events and, according to the type of event,
processes it accordingly. In C, this function can often be summed up by a giant ‘switch’.
53
With Xt Intrinsics (high-level X-Window programming model, used for example for Osf-Motif), the developer
defines one function per type of event. Such a function will only be called when a given type of event occurs. Such
a function is called a ‘reflex’ or a ‘callback’. This method offers two advantages: on the one hand, you no longer
have to write the ‘switch’ function; on the other hand, the event’s parameters are passed more simply. For example,
three parameters characterize a click event: the coordinates of the click and the button number. No parameters
characterize a timer event. One parameter characterizes an event such as ‘the content of a text field has changed’,
i.e., the new text. Processing all these events by the same function poses a problem in terms of passing parameters:
you often (Windows, X-Windows) have to take liberties with the typing, which is a major cause for error. The
advantage of the system of reflexes is to be able to define one reflex function type per event type. As you will no
doubt have guessed, this is the way in which events are managed with Scol.
In Scol, you can therefore define a reflex function for each object and each type of event. This reflex function must
take at least two arguments:
- the first is the object affected
- the second is a given user parameter
Depending on the events, the reflex function will have additional arguments: 3 integers for a click, two integers for
a ‘resize window’ event, no additional arguments for a timer event.
To define a reflex, function, you will use the function with the appropriate definition. For example, in the ‘hello3’
program described in the ‘Hello World’ section, you will find the following line:
_CBwinDestroy win @_end nil;
The _CBwinDestroy function is used to define the reflex associated with the ‘destroy window’ event. It takes
three arguments:
The type of the reflex function is: fun [ObjWin?]?, whereby the second argument is the user parameter. The
type of the result is irrelevant. The type of the _CBwinDestroy function is therefore:
_CBwinDestroy : fun [ObjWin fun [ObjWin u0] u1 u0] ObjWin
You will notice how the typing ensures that the user parameter supplied when the reflex is defined has the same
type as that of the reflex function (here ‘u0’). Here, Scol holds an advantage over Xt-Intrinsics: the user parameter
in Xt-Intrinsics is not typed: it forces the developer to play around with types, which is always a major cause of
errors.
Other examples:
A click event on a window requires three parameters: the coordinates of the click and the number of the button. The
associated reflex function is of the type: fun [ ObjWin u0 I I I]?
If you define a reflex with nil as the second argument (instead of the reflex function), this deletes the reflex.
Similarly, you can redefine a reflex at any time, including in the reflex function itself.
54
1.2.3 Processing an event
When an event occurs, the Scol machine searches for the object concerned by the event, then the reflex function
associated with this event. If this reflex function has been defined, the Scol machine runs this function and forgets
the result, except in certain highly specific cases where the result is interpreted by the system. This function must
be run in a channel (indeed, this function may call the _load or _closechannel functions). It is the
proprietary channel that is selected. This explains the second role of the proprietary channel.
You can change an object’s proprietary channel; more exactly, you can assign all the objects of a channel to
another channel using the following function:
_chgchn : fun [Chn1 Chn2] Chn2
Assigns all the objects of the Chn1 channel to the Chn2 channel.
This function is used in particular to save a channel’s objects just before the channel is destroyed (subsequent to the
_closed event, for example).
2. Examples
2.1 Windows
Here, we will illustrate in windows the principles that have just been expounded. You will find the complete
documentation for the following functions in the reference manual.
55
Reflex of the Focus event. No special argument.
2.2 Timers
You can define timers, whose period is defined in milliseconds. A timer with a period of 1000 will initiate a timer
event every second. Timer objects are of ‘Timer’ type. Three functions are used to manage the timers:
56
VII. 3D programming
The Scol machine contains a library that is capable of processing and displaying 3-dimensional scenes. This library
is called a ‘3D engine’. Very simply, it is used to add 3D functionalities to your programs. One of the key features
of the Scol language is its skillful combination of Internet communication capacities with powerful 3D
functionalities.
Scol’s 3D engine was carefully developed for on-line use: the scene description files are not large and scenes are
rendered fluidly on less powerful machines. Indeed, it is worth pointing out that many Internet users, unlike the
users of video-games, don’t have up-to-the-minute machines. Similarly, it is impossible to force users on the
Internet to acquire a 3D card, or even to be sure that they have the latest driver for their card.
To be able to understand this chapter, you should already have some familiarity with the concepts linked to 3D
(scenes, polygons, materials, textures, rendering, etc.), even though most of these terms will be explained again.
Moreover, to fully understand the examples, you should have at least read through the Scol documentation
concerning graphic interfaces: to display a 3D image, you need to create a window and a surface object and then
copy the surface object into the window. Three functions will be sufficient in the first instance.
The chapter will be divided into four sections. In the first section, we shall review basic 3D concepts. In the second
section, scene definition files will be discussed. In the third section, we shall describe the manipulation and
rendering functions. In the fourth section, we shall address the tricky issue of collisions.
1. Basic 3D concepts
1.1 Scene
The scene is the fundamental concept of 3D. A scene is a group of elements such as 3D objects, cameras or
collision objects. This group is not organized in a random fashion: it fact, it is arranged as a tree structure. Each
node of the tree is a 3D object, a camera, or a collision object. The node which has no parent is called the tree’s
root. The concepts of parent node, child node and sibling node are logically defined.
Geometrically speaking, each node defines a location. The location of the root will be called the global location.
A location is characterized in relation to the parent node’s location by position and orientation coordinates, and
by a scale parameter.
3D objects here will be groups of polygons. The polygons will either be triangles or convex quadrilaterals. For
example, a cube will be formed of 6 polygons: a square for each face of the cube. On each polygon (or face), you
will be able to apply either a uniform color to the face or a texture, i.e., an image. 3D objects will be called ‘mesh’.
There is a special case of 3D object: the empty 3D object, which does not contain any polygons. This object will be
called ‘shell’. Thus a ‘shell’ is used to define an empty location to which you can link different elements. By
moving this ‘shell’, you will move all the attached elements.
Cameras resemble real cameras: in particular, a focal length is defined. Cameras will be called ‘camera’.
Collision objects are groups of spheres, rectangular parallelepipeds, or triangles which define space-filled zones.
These objects will be called ‘coll’.
The main purpose of the 3D engine is to calculate the image that a particular camera “sees”. To do this, you need to
specify a camera and a surface in which the image will be calculated. The scene thus taken into account will be the
scene to which the camera belongs.
57
1.2 Session
The 3D engine is used to manage several scenes simultaneously. Indeed, the concept of the scene is replaced by the
concept of the session. A 3D session is a group of elements such as those described above (mesh, shell, camera,
coll). Each element possibly has a parent; there are as many scenes as there are orphan elements.
1.3 Material
A material can be ‘flat’; this means that a uniform color is applied to the face. This color can vary according to the
lighting, i.e., according to the face’s orientation with respect to the light source. This color can also be translucent:
it acts as a color filter. The strength of the filter varies between total transparency and complete opacity.
A material can be ‘textured’: this means that an image is applied to the face. This image can be a drawing or a
photo. The material can be transparent: this means that the dots in a color (which the user can determine) will be
considered to be transparent. You can assign a transparency coefficient to the others.
On a textured material, you can apply various colorimetric filters: filters towards a color, color rotation, change in
saturation, etc.
The materials are elements of the session. They are not geometric elements: thus they are not attached to locations
and, of course, they have no parent.
1.4 Performance
It is always difficult to be precise about levels of performance, but we can give the general principles that are used
to optimize scenes.
Speed of execution primarily concerns speed of rendering. Other operations (movement, rotation, etc.) are very
fast.
- The fewer the polygons, the faster the rendering (avoid exceeding 15,000).
- At a constant number of polygons, rendering is faster if there are lots of meshes in the scene.
- Flat material is much faster than textured material.
- Transparency (both for flat and textured) is particularly memory-hungry, especially when transparent faces are
superimposed.
The space used in your computer’s memory is an important parameter: if the scene is too large, your computer will
have insufficient memory and will use swap mechanisms, which are time-hungry. It is important to distinguish
between the size of your 3D files and the space used to store them in the memory. For example, a file containing a
jpeg-format image with a resolution of 256x256 can have a size of 6 Kb (if it is sufficiently compressed), but will
still take up 128 Kb of memory. This latter figure is the important one and is obtained as follows: 256x256x2, since
two bytes are needed to store the color of a dot.
The size taken up by information other than textures is negligible: 2 Mb will normally be used to manage scenes of
15,000 polygons.
Above 10 Mb of textures, your scene will have difficulty rotating on a computer that has 32 Mb of random access
memory. Therefore, use your judgement.
58
1.5 Scol 3D engine characteristics
The engine uses a dedicated memory strip to store all its data, except for textures. This memory strip is also used to
generate rendering.
The engine manages a list of materials and a list of textures. Cleaning up is done automatically by means of a
“reference counter”-type GC (Garbage Collector).
In this way, you cannot copy a material without specifying at least one object that uses the copy. Similarly, you
cannot copy a texture without specifying at least one material that uses the copy.
1.5.2 Scene
The objects in the scene are organized as tree structures. The objects are of four types:
. “shell” type: empty object
. “mesh” type: group of points and polygons
. “camera” type: visualization camera
. “coll” type: collision object
The move, create and delete functions are applied to objects in general, without distinguishing type, which
simplifies the API.
1.5.3 Materials
There are two general types of material: textured materials and untextured materials. Every material has an
untextured mode. You can load textures at any time.
Rendering is in 15 bits unpaletted. Textures are in paletted 8-bit bmp format (no longer recommended as it is
cumbersome to download and of mediocre quality) or in jpeg format. You are advised to use jpeg only, since this
format offers the best performance in terms of compression.
Textured materials have a transparent mode. For textures in bmp format, the color 0 is the transparency color. For
textures in jpeg format, the transparency color can be specified.
Texturing can be done in ‘environmental mapping’ (allow reflection effects, such as metal rendering)
59
- Saturation filter: calculates for each dot the barycenter between the dot’s saturation and the filter’s saturation. The
barycenter coefficient is variable.
- Rotation filter: causes a color’s shade to be turned from a specific angle.
Materials can use a level of transparency that varies between 0 (opaque) and 255 (transparent). With the software
engine (do not use any 3d hardware device), textured materials can have only two levels of transparency:
- from 0 to 127: opaque
- from 128 to 255: 50% transparency
2. 3D file format
In order to define a scene, you need to define different elements: meshes, camera, collision objects, materials, etc.
It is convenient to have a file format that can be used to describe a scene or part of a scene simply and
comprehensively. We will see that the 3D engine possesses manipulation functions that can subsequently be used
to modify virtually any characteristic defined by the scene files. The format of Scol 3D files is called M3D.
The M3D format is used to describe hierarchically-arranged scenes containing materials, meshes, cameras, and
other files to be included. An M3D file is a text file which can be opened using any editor. The file’s basic element
is the line. The file is divided into blocks of types:
No line here is indispensable. However, it goes without saying that the minimum you must define is a flat color
(‘color’ line) or a texture file (‘texture’ line).
The color is given in 6-digit hexadecimal RGB (8 bits R, 8 bits G, 8 bits B). For example, bright red is coded
ff0000.
The texture is a file name which can be preceded by a filter, placed between ‘%’. The filter is a character string
which consists of a list of processes:
C[6 color characters][2 rating characters]: color filter (expressed as 24 bits hexa) with a rating varying between
0 and 255 (2 characters hexa)
X: changes colors Red->Blue->Green->Red
Y: changes colors Red->Green->Blue->Red
60
A[6 color characters][2 distance characters]: attractor. Every dot close to the color expressed is forced to this
color. This color becomes the transparency color for jpeg textures.
R[4 rotation characters]: shade rotation (Hsv model). The angle is between 0 and 65535.
S[4 value characters][2 rate characters]: saturation filter. The restricted saturation value is given on 4 bytes and
is between 0 and 65536. The rating varies between 0 and 255.
Example : %Cd0000080X%[Link]
In this example, a red filter at 50% followed by a color rotation X will be applied to the texture [Link].
The lines of types are: NOLIGHT, TRANSPARENCY120. You can put in as many type lines as you wish. The
coefficient which follows the word TRANSPARENCY is between 0 (opaque) and 255 (transparent). It is only
useful during an untextured rendering.
The vertices are lines of three coordinates x, y, z, which are whole or floating integers.
Light l is optional and should be between 0 (very dark) and 31 (value used by default).
The polygons are described in the form of blocks comprising:
. a line giving the name of the material to be applied to the polygons to follow
. lines of polygons comprising 3, 4, 6, 8, 9 or 12 integers, according to whether you define 3 or 4 apices, with 0, 1
or 2 texture coordinates.
Following the polygons are the means to insert other meshes, cameras..
camera name_of_camera {
x y z a b c scale
distx disty sx sy
zclip zfog zback
}
The camera’s position is given by the coordinates x, y, z and angles a, b, c (between 0 and 65535). The scale
parameter is optional.
The distx and disty parameters give the distance from the screen on the x-axis and on the y-axis (used in the
projection formulas X=distx*x/z et Y=disty*y/z).
The sx and sy parameters give the screen’s half-width and half-height.
Shell refers to an empty object (neither camera nor mesh) which is used only for attaching other objects to it. The
syntax of a Shell object is as follows:
shell name_of_shell {
x y z a b c scale
}
Following the shell coordinates are the means to insert other meshes, cameras
Example :
61
# cube
material wood {
color c04000
texture [Link]
}
material stone {
color 00c040
texture [Link]
type TRANSPARENCY
}
mesh cube {
0 0 0 0 0 0
light 10
wood
0 0 0 1 255 0 2 255 255 3 0 255
1 0 0 5 255 0 6 255 255 2 0 255
5 0 0 4 255 0 7 255 255 6 0 255
stone
4 0 0 0 255 3 3 255 255 7 0 255
3 0 0 2 255 0 6 255 255 7 0 255
1 0 0 0 255 0 4 255 255 5 0 255
}
In this example, we have defined a cube with an edge of 200. There are three faces which use the material ‘wood’
and three faces which use the material ‘stone’.
3. 3D manipulation API
file ‘Tutorial/[Link]’
_load "Tutorial/[Link]"
main
file ‘Tutorial/[Link]’
/* MyTest 3d */
typeof win=ObjWin;;
typeof buffer=ObjSurface;;
typeof session=S3d;;
typeof shell=H3d;;
62
typeof camera=H3d;;
fun _end(a,b)=_closemachine;;
fun _paint(a,b)=_BLTsurface win 0 0 buffer 0 0 400 300;;
fun main()=
set win=_CRwindow _channel nil 150 150 400 300
WN_MENU|WN_MINBOX "My 3d Test";
_CBwinDestroy win @_end nil;
_CBwinPaint win @_paint nil;
set buffer=_CRsurface _channel 400 300;
set session = MX3create _channel 1024 1024 1024 1024 1024*1024;
if session==nil then _closemachine
else
(set shell = M3createShell session;
M3load session "Tutorial/scene.m3d" shell;
set camera=M3getObj session "camera";
M3recursFillMatObj session shell;
MX3render session buffer camera 0 0 0;
_paint nil nil;
0);;
file ‘Tutorial/scene.m3d’
# cube
material wood {
color c04000
texture Tutorial/[Link]
}
material stone {
color 00c040
texture Tutorial/[Link]
}
mesh cube {
0 0 0 0 0 0
wood
0 0 0 1 255 0 2 255 255 3 0 255
1 0 0 5 255 0 6 255 255 2 0 255
5 0 0 4 255 0 7 255 255 6 0 255
stone
4 0 0 0 255 3 3 255 255 7 0 255
3 0 0 2 255 0 6 255 255 7 0 255
1 0 0 0 255 0 4 255 255 5 0 255
camera camera {
200 300 -400 7000 -5000 0
200 200 200 150
10 10000 10000
}
}
63
If you try the example, you will obtain a window containing a cube seen three-quarters on. The faces are colored.
To obtain textures, you must create two graphic files, ‘Tutorial/[Link]’ and ‘Tutorial/[Link]’. You can also
rename these files at the start of the Tutorial/scene.m3d file and replace them with jpeg files.
In the example, we notice a few new functions whose name begins with ‘M3’ or ‘MX3’: these are Scol 3D engine
API functions. Below we outline these functions before moving on to give an exhaustive list.
Note: functions that start with MX3 have been introduced to support 3D cards and pass in software mode if there is
no 3D card. Thus the older functions M3create and M3scanline are now obsolete.
3.2. Session
Initializes a 3D session by specifying the maximum number of materials, textures, objects and lines of rendering
and the size of the memory strip to be allocated for storing the meshes and calculating rendering.
I M3destroy(session H3d)
Destroys the 3D session.
64
I M3loadString(session S3d, contents S, parent H3d)
Loads an object from a character string in M3D format by specifying the parent handler (nil if none).
67
Returns the reference counter associated with the material.
H3d MX3render(session S3d, buffer ObjSurface, objet H3d, xplot I, yplot I, col
I)
Calculates rendering of a scene from the ‘object’ handler camera in a rendering buffer. You specify the background
color col (nil for transparent). The function returns the handler of the object located at the point of the (xplot,yplot)
coordinates, nil if none. NB: the camera’s rendering size should not exceed the buffer bitmap size. A camera’s
rendering size is double the camera’s half-heights and half-widths. Use M3setCamera to modify these values.
68
[H3d HMat3d] MX3renderm(session S3d, buffer ObjSurface, object H3d, xplot I,
yplot I, col I)
Calculates rendering of a scene from the ic handler camera in a rendering buffer. You specify the background color
col (nil for transparent). The function returns the handler and the material of the object located at the point of the
(xplot,yplot) coordinates, nil if none.
4. Managing collisions
4.1 Principles
The 3D engine of the Scol machine contains a collision management system. This system is based on collision
elements, which the user can define in a number of ways: spheres, boxes, or polygons. Boxes will in fact be OBB
(Oriented Bounding Boxes): an OBB is any rectangular parallelepiped. Its axes are not necessarily the scene’s
axes.
These collision elements have no direct relation with the scene’s mesh elements. In fact, it is important to be able to
define invisible collision elements (e.g. invisible walls at the edge of a link in empty space to prevent users from
falling into the void) as well as mesh elements which will not be taken into account in calculating collisions, either
because the user has to be able to pass through these elements, or in the interests of optimization (perhaps users
cannot be located near the element in any way, or you may want to replace complicated geometry with a simple,
all-encompassing box).
An intersection and collision detection system is not only applicable to testing the position of a camera in relation
to a set. In fact, it is also generally applicable to the testing of two groups of collision elements.
From the collision elements, the engine is used to detect two types of event:
- intersection: do two groups of collision elements A and B intersect?
- collision in translation: given a movement vector u and two groups of collision elements A and B, will there be
intersection between A and B when A is moved according to vector u? If so, at what moment during the movement
and according to which plane will the collision take place?
We shall distinguish between primary collision elements and secondary collision elements.
69
A primary collision element is the basic collision element: these are the spheres, boxes, and polygons considered as
the scene’s solid elements, with which you carry out intersection and collision tests.
Some primary collision elements can be grouped in binary tree structures (each node has at most two child
elements). In fact, the primary collision elements are located in the leaves of a tree. The nodes which are not leaves
are secondary collision elements. They are of the same kind (sphere, box, or polygon), but they are not real
collision elements: they incorporate primary collision elements and are used to optimize calculation. The
algorithm (of intersection or collision) is derived from the principle that if there is intersection or collision with the
parent, then there can be intersection or collision with the child. Conversely, if there is no intersection or collision
with the parent, then there cannot be intersection or collision with the child.
In each node of the tree we find not a (primary or secondary) collision element but a list of collision elements of the
same kind (spheres, boxes, or polygons). The algorithm moreover supposes that if a child is of a different type
from its parent (for example, the child is OBB type and the parent Sphere type), then the child is an only child.
The scene’s collision elements are in fact trees of this kind, which may be reduced to a single leaf containing a
single collision element. You can thus define as many collision objects as you wish in a scene. These objects, like
others, are defined in relation to the location of their parent and may themselves have child objects. For example,
you can define an OBB-type collision object having the size of an object (e.g. a table). The collision object will be
defined as a child of the table, which simply means that the table only has to be moved for the collision object to
follow.
The intersection or collision algorithm takes at the start two of the scene’s nodes; let us call them A and B. It carries
out its calculation taking into account all the collision objects located under A and all the collision objects located
under B. If A belongs to a descendant of B, the calculation will be performed between the objects located under A
and the objects located under B except for those located under A. Usually, you can provide the algorithm with the
object that is moving and the whole of the scene.
It is one thing to detect an intersection or a collision, and quite another to manage this kind of event, in other words,
to propose a movement, more generally a transformation, that will allow the scene to quit this state of intersection
or collision. This problem is particularly complex since it is specific to the application and requires the selection of
a “physical” model for the scene. This is not purely a geometric problem. The 3D engine, however, provides help
in resolving collisions. The M3testColl collision function between A and B returns supplementary information
connected to vector u:
- the movement that is geometrically possible: a vector .u with between 0 and 1.
- the collision axis v, such that u+v is a vector that transports object A to a guard distance from B in such a way as
to cause A to slide along B. In doing so, A may enter into collision with another object C, or even with another part
of B.
4.2 API
[H3d H3d [I I I] [I I I]] M3testColl (session S3d, objectA H3d, objectB H3d,
vector [I I I], guard I)
Collision test between subtrees A and B. If A (resp. B) is a subtree of B (resp. A), the test is carried out between
subtree A (resp. B) and subtree B (resp. A) without subtree A (resp. B). The collision test is carried out on A’s
movement according to a vector passed as a parameter, and expressed in the global location. Returns nil if no
collision, otherwise returns both objects in collision and two vectors:
- the first is collinear to the movement vector and gives the movement up to the collision
- the second is:
- nil if A and B are already in intersection before the movement
- otherwise a perpendicular vector in the plane of collision, such that, added to the movement vector passed
as a parameter, a vector is obtained which suggests resolution of the collision.
71
VIII. BigNum programming
1. General introduction
The BigNum library is used for handling big whole numbers (up to 128 bits).
It offers a variety of operations such as addition, subtraction, Euclidean division, multiplication, exponentials, etc.
The library provides conversion functions between character strings and BigNums, which, among other things,
allows these numbers to be saved. The library is also used to convert a complete text to a list of BigNums, and vice
versa.
2. API
Conversion functions:
72
BigMod : fun [x BigN, n BigN] BigN
Performs the operation: x mod n
3 . Example
The following example shows how to code the RSA algorithm. Let us suppose that the public exponent is 3.
The three API functions are:
RSAcreate3: calculates a public key-private key pair.
RSAcrypt3: encrypts a text using the public key.
RSAdecrypt: decrypts a text using the private key.
NB: check that you have the necessary legal authorization before attempting to integrate this example in one of
your applications.
/*
RSA library - jul 97 -
*/
73
fun RSAcryptone3(l,n,i1)=
if l==nil then nil else
let l->[m nxt] in
(BigToStringn (BigMuln (BigMuln m m n) m n) i1)::RSAcryptone3 nxt n i1;;
fun RSAcutstring(s,i,n)=
let substr s i n -> z in
if strlen z then z::RSAcutstring s i+n n
else nil;;
fun RSAdecryptone(l,k,n)=
if l==nil then nil else
let l->[m nxt] in
(BigExpn BigFromString m k n)::RSAdecryptone nxt k n;;
/* API */
/* decrypting a message s with the private key n,k -> returns a string */
fun RSAdecrypt(s,k,n)=
let ((RSAsize n)-1)>>3 -> nbyte in
BigListToString (RSAdecryptone (RSAcutstring s 0 nbyte+1) k n) nbyte;;
/* creating a public key-private key pair of approx i bits (between i and i-1)
returns the pair [n k]*/
fun RSAcreate3(i)=
let [BigFromAsc "1" BigFromAsc "3"] -> [one three] in
let [BigPrimal i>>1 BigPrimal i-(i>>1)] ->[p q] in
if ! BigCmp p q then RSAcreate3 i
else let BigMul p q ->n in
let BigMul BigSub p un BigSub q un -> phi in
let BigInvn trois phi -> k in
[n k];;
74
IX. SQL
1. General introduction
The SQL library is used for handling any database using the ODBC support and SQL queries. The SQL library is
not supplied in the basic Scol Engine since it requires the ODBC support, which is not found on every machine.
This library is supplied as a Scol plug-in, "[Link]", and the following line must appear in the [Link] file:
plugin plugins/[Link] SCOLloadSQL
In order for it to operate, the database must be defined and named in the Windows configuration panel (menu
odbc32bits). The name then given to the pair (database file/associated driver) will be the database’s determinant,
enabling Scol to access it.
2. API
This function returns nil if the connection fails. The name of the database is that defined in the configuration panel,
menu odbc32bits. The login and password are authentication parameters used to connect to the database. If you
have not defined access rights to your database, the “admin” login and the “ ” password should work.
Disconnection function:
I SqlDestroy (connection SqlDB)
This function closes the connection.
Request function:
[[S r1]r1] SqlRequest (connection SqlDB, SQL_request S, parameters [SqlParam
r1])
The SQL request is in text format. The request’s parameters appear in the form of the ‘?’ character. The list of
parameters (the SqlRequest function’s third argument) respects the order and number of the ‘?’ in the SQL query.
The result is a list of character strings corresponding to the list of responses to the request, where each response is
a list of columns.
The parameters are passed as a list of SqlParam-type parameters. The SqlParam type is defined as follows:
typedef SqlParam =
SQL_BIGINT S | SQL_BINARY S | SQL_BIT S | SQL_CHAR S |
SQL_DATE S | SQL_DECIMAL S | SQL_DOUBLE S | SQL_FLOAT S |
SQL_INTEGER S | SQL_LONGVARBINARY S | SQL_LONGVARCHAR S | SQL_NUMERIC S |
SQL_REAL S | SQL_SMALLINT S | SQL_TIME S | SQL_TIMESTAMP S |
SQL_TINYINT S | SQL_VARBINARY S | SQL_VARCHAR
3. Examples
75
The following example opens the “MyBase” database and performs a password search as a function of a “Foo”
login.
typeof db=SqlDB;;
fun main()=
set db=SqlCreate _channel "second" "admin" "";
SqlRequest db "SELECT Password FROM Table WHERE [Link]=?;"
(SQL_CHAR "Foo")::nil;
SqlDestroy db;
0;;
The following example opens the “MyBase” database and performs a login search on the basis of a telephone
number “1234”.
typeof db=SqlDB;;
fun main()=
set db=SqlCreate _channel "second" "admin" "";
SqlRequest db "SELECT Login FROM Table WHERE [Link]=?;"
(SQL_NUMERIC "123")::nil;
SqlDestroy db;
0;;
The following example opens the “MyBase” database and outputs the list of logins and telephone numbers on the
(_fooS strbuild) console.
typeof db=SqlDB;;
fun main()=
set db=SqlCreate _channel "second" "admin" "";
_fooS strbuild SqlRequest db "SELECT Login,Tel FROM Table;" nil;
SqlDestroy db;
0;;
typeof db=SqlDB;;
fun main()=
set db=SqlCreate _channel "second" "admin" "";
SqlRequest db "INSERT INTO Table VALUES(?,?,?);"
(SQL_CHAR "Titi")::(SQL_CHAR "xyz")::(SQL_NUMERIC "789")::nil;
SqlDestroy db;
0;;
typeof db=SqlDB;;
fun main()=
set db=SqlCreate _channel "second" "admin" "";
SqlRequest db "UPDATE Table SET Password=? WHERE Login=?;"
(SQL_CHAR "123abc")::(SQL_CHAR "Titi")::nil;
SqlDestroy db;
0;;
76
The following example deletes Titi’s form.
typeof db=SqlDB;;
fun main()=
set db=SqlCreate _channel "second" "admin" "";
SqlRequest db "DELETE FROM Logins WHERE Login=?;"
(SQL_CHAR "Titi")::nil;
SqlDestroy db;
0;;
77
X. Http interfacing
The Scol machine integrates the http protocol both on the server side and on the client side. This means that, in a
few lines of Scol, you can not only create a small http server but also make http requests as a client to any http
server in the world. Similarly, two Scol machines can communicate via http, one acting as server, the other as
client. This is extremely useful for connecting to a Scol site when you yourself are behind a firewall which only
allows the http protocol to pass.
1. Http server
a. Principles
For example :
startHTTPserver _channel 8080 @callback nil
The callback function is called when the server has received the complete request. It takes three arguments:
- the http connection
- the user parameter
- a character string containing the request
It must return a character string which is the response to be transmitted. This is synchronous mode: the callback
function immediately returns the response to be transmitted.
There is an asynchronous mode, which allows the server to postpone its response. For this the callback function
needs to return ‘nil’. The server program can then:
- send the response, packet by packet, using the HTTPsend function
- close the connection after the last packet, using the closeHTTPcon function
- it can also send the contents of a file, which will be transferred directly from the disk to the http connection
without passing through the Scol machine’s memory. At the end of the transfer, the http connection will be
automatically closed. This is done with the HTTPsendFile function.
78
The simplest way of parsing such a request is to use a strfind to find the header ending and to apply the strextr
function to the header.
The response to an http request must also begin with a header. For example, you can take the following header for
a text message:
HTTP/1.0 200 OK\13\10Server: SCOL HTTP server\13\10Content-Type: text/html\13\10\13\10
People often forget to send this header, so make sure you don’t waste time by making such a careless mistake.
Example:
fun http_onrequest(con,db,req)=
let hd strextr req -> l in
let l->[com [url _]] in
if (!strcmpi com "GET") then strcat http_header "GET"
else if (!strcmpi com "POST") then strcat http_header "POST"
else "";;
...
startHTTPserver _channel 8080 @http_onrequest nil;
...
In this example, you return a page depending on the verb in the request. You will note how it has been parsed. If the
verb is neither GET nor POST, you return an empty string. The client will therefore receive this empty string,
without a header, which will cause an error, which may be deliberate, as here.
2. Http client
a. Principles
To make an http request, the client must specify the verb, the URL, and possibly a message body.
In the case of a GET, only the URL needs to be specified, hence a simplified API in this case. You will use the
following function:
INETGetURL : fun [Chn S I fun [INET u0 S I] u1 u0] INET
The arguments are:
- the proprietary channel
- the URL
- a flag (leave at 0)
- a callback
- a user parameter
The function returns an ‘INET’ type corresponding to a request in progress, which can be interrupted if you no
longer want to receive the response.
The simplest solution in the majority of cases is to call the callback only after the response has been fully received.
However, there are some Internet applications (particularly pseudo-streaming) which return the response in several
chunks: several minutes can elapse between the start and end of the response. For this reason, we considered it
preferable to inform the Scol program every time data has been received. The callback thus takes the following 4
arguments:
- INET request
- user parameter
- data received
- state of the request:
- 0: data has been received, it is in the third argument
- 1: this is the end of the request (the third argument is nil)
- 2: network error (the third argument is also nil)
79
Example :
fun cbgethttp(inet,z,s,reason)=
let z->[content] in
if reason==0 then (mutate z <- [strcat content s];nil)
else if reason==1 then (_fooS content; _fooS "OK");
else _fooS "ERROR";;
...
INETGetURL _channel "[Link] 0 @cbgethttp [nil];
...
It is difficult to detect network errors. Indeed, when an http client is behind a proxy and requests a non-existent
URL, the client in effect requests the proxy for this URL, and the proxy is then responsible for requesting it from
the Internet server corresponding to the URL. If the page does not exist, the proxy will be informed. The proxy then
often creates a quite valid html page with a few lines of text explaining that an error has occurred. However, for the
http client, the response is in order, not an error message.
If you are developing an application in which you are managing the http client and the http server, you are advised
to ensure that clients can easily determine whether the page they received was indeed the one they expected, for
example by having a ‘magic number’ precede it.
b. POST method
Having just seen how to perform a GET request, let us now move on to the POST method. This enables you to pass
a message body, by using the function:
INETGetURLex : fun [Chn S S S I fun [INET u0 S I] u1 u0] INET
The arguments are:
- the proprietary channel
- the verb (POST)
- the URL
- the message body
- a flag (leave at 0)
- a callback
- a user parameter
Response reception – and callback operation – are exactly the same as for the INETGetURL function.
80
XI. Multimedia programming
Scol provides a number of multimedia possibilities in addition to 3D and the classic 2D interfaces.
You should note, however, that some of these possibilities are very much platform-dependent. Some APIs are not
implemented on UNIX platforms: in this case the functions are present in their empty form (same type, but the
function always returns nil).
1. RealPlayer API
This API is used to read a RealPlayer flow (audio and/or video). The program simply defines the URL of the
document to be read and is then notified of the state of progress. Sound is processed automatically and transmitted
to the loudspeaker. Images are passed to the program in a bitmap, and the program then does what it likes with
them: 2D display, use of bitmap as texture to apply the video to a 3D object, etc.
The API also has tools to control the flow (read, pause, position, volume, etc.).
In addition, the API is used to operate the login/password system defined by Real.
2. Quicktime API
This API applies the same principle as for RealPlayer. The functions are different, however, since both
technologies are presented in a fundamentally different way as far as the developer is concerned.
This uses multimedia players present on the system to play classic multimedia files such as Wav, Avi, Mpeg, etc.
In fact, the Scol machine transmits files to the operating system, which will run them if it has the right drivers.
4. Audio API
a. Mono recording/playback
This API is used to record sound by specifying the sampling frequency and sample size. It is also used to play back
these samples by further specifying the frequency and size.
This API makes use of full-duplex possibilities if your hardware has them. If not, the playback start or record
functions will return errors if you try to run both simultaneously.
b. Audio compression/decompression
This API is used for compressing and decompressing audio samples. The compression method is suitable for very
low outputs since it goes down to a coding of 8 Kb/s, which represents a sixth of the pass band of a 57.6 Kb/s
modem.
This API (using DirectSound in Windows) is used to play back several samples simultaneously, while being able
to specify a 3D position for each one.
81
5. Video API
The Scol machine is able to use a video camera via this API and to capture images by specifying the desired
capture frequency.
Users define a callback function that will regularly receive the images. They can then:
- convert them to bitmap in order to display or save these images
- compress them for possible transmittal.
The library provides extremely useful video compression/decompression functions for this purpose.
6. Printing
At the other end of multimedia are printing functionalities. Scol enables two types of printing: raw text printing and
bitmap printing.
For raw text printing, you will simply pass the character strings to be printed.
For bitmap printing, you will pass the bitmap and the print coordinates and size (with micron precision).
82
XII. The Scol machine: start-up, control, standard client and server
Up to now we have described the internal operation of the Scol machine. Now we shall present a more global
overview, encompassing the start-up and control of a Scol machine. Moreover, a standard connection method has
been developed to define the notion of browser, and we shall use this section to describe it in detail.
When you start one of your Scol programs, another Scol machine always starts, characterized by the display of a
window called Scol Engine. The Scol Engine allows the user to perform certain operations, but above all it acts as
a supervisor, enabling the different SCOL machines present on the machine to be managed through a graphic user
interface.
The supervisor automatically starts up when the first Scol machine is started. Each Scol machine is connected to
the supervisor via a local TCP/IP socket, called life-socket: when this socket is closed by the supervisor the Scol
machine shuts down. Conversely, when this socket is closed by the Scol machine, the supervisor is informed that
the Scol machine has shut down. This socket is also used by the supervisor to communicate with local Scol
machines, for example to command the console window to open or close.
The supervisor is a normal Scol machine. What distinguishes it is that other Scol machines automatically try to
open a channel to it.
The files that need to be present in the Scol directory (usually ‘C:/Program Files/Scol’) are:
- [Link]: text file containing the initial definition of the resource variables
- [Link]: text file containing “hard” parameters:
- echo: display mask
- port: port used by the supervisor (1200 by default)
- log: activation of log files
- logwin: console display in the event of a runtime error. If adjusted to ‘no’, the machine stops immediately if
there is an error (this is useful when you are working on a remote Scol machine)
- forcedIP: forces the definition of the local IP address (this is useful when a server does not know its apparent
IP address from the Internet)
83
- HTTPproxy: http proxy
- update: Scol version date
- scol: name of the Scol dll in use
- plugin: name of a Scol plug-in (this line may appear several times)
- disk: Scol partition (this line may appear several times)
The command line of the Scol machine may contain up to three arguments (only the first is indispensable):
the first gives the start-up script,
the second gives the machine’s rights (see below),
the memory size to be assigned to the virtual machine (obsolet).
The Scol machine uses a start-up script file, which can be either a file or a character string. The script syntax was
defined in the Channels and communications chapter.
On start-up, the machine creates an initial unplugged channel with a minimal environment. The script is then run
in this channel.
The start-up script is on the face of it very short: loading one or more Scol packages, then running a command.
In this mode you simply pass the script file name with the *.scol suffix. For example:
C:\Program Files\Scol\[Link] C:\Program Files\Scol\Partition\[Link]
In this mode, you directly pass the contents of the script, expressed in a rather special way:
- alphanumeric characters are retained
- spaces are replaced by ‘+’ signs
- the other characters are replaced by a ‘%’ followed by 2 hexadecimal figures
This “script” is preceded by the name of the machine surrounded by $ signs.
For example:
C:\Program Files\SCOL\[Link]
$Tutorial/[Link]$%5fload+%22locked%2flib%2fconst%2epkg%22%0d%0a%5fload+%22Tutorial%2fmyte
st%2epkg%22%0d%0amain%0d%0a
The second argument of the command line gives the machine’s rights (these are rarely used). It is a character string
such as: CSDMRWK
The SCOL machine has certain rights, each represented by a letter:
C: client-networking (access to the _openchannel function with an address different from nil)
S: server-networking (access to the _setserver function)
D: distant-networking (access to the _openchannel function with a remote address)
M: opening new machine without cache (starting a machine without its cache being activated)
84
R: normal file reading (access in read mode to unsigned files)
W: normal file writing (access in write mode to unsigned files)
K: signed file writing (access in write mode to signed files)
The C_Rights, S_Rights, ..., K_Rights constants are defined in the Scol language (they are whole masks). A Scol
machine can know its parameters:
_getrights : fun [ ] I
Returns the machine’s rights (to be used with the previous masks).
_setrights : fun [ I ] I
Defines new rights in the direction of the restriction (necessarily below those of the machine).
3.3 Memory
The third and final argument of the command line gives the size of the memory used by the Scol machine. This
parameter is now obsolet, since the virtual machine adapts dynamically the size of its memory. It always starts with
1Mo, and get more memory when it is required.
_sizememory : fun [ ] I
Returns the size of the SCOL machine’s memory (counted in words of 32 bits).
_freememory : fun [ ] I
Returns the size of the SCOL machine’s free memory (counted in words of 32 bits). This function triggers a
Garbage Collector and is thus relatively slow.
One SCOL machine can start another by means of the following command:
_newmachine : fun [ S1 S2 I1 I2 ] I
Creates a new machine whose name is S1, with a start-up script S2, and with rights I1 and memory size I2.
Obviously, the new machine’s rights are at most equal to those of the old machine.
If I1 or I2 are nil, the new machine inherits the old machine’s values.
_newmachineS : fun [ P I1 I2 ] I
Creates a new machine with the script file P, and with rights I1 and memory size I2. Obviously, the new machine’s
rights are at most equal to those of the old machine.
If I1 or I2 are nil, the new machine inherits the old machine’s values.
Examples: there’s no need to write a program to use the _openbrowserhttp function; use the Scol Engine and
enter the following examples as URLs:
[Link]
[Link]
[Link]
85
5. Communication between the Scol machine and the supervisor
The Scol machine is linked to the supervisor by a normal channel. This channel is defined as being the
_masterchannel, and the corresponding socket is called socklife.
The _masterchannel Scol variable is accessible to users. They can make use of it to send messages to the
supervisor.
Example:
defcom Copen=open S;;
...
_on _masterchannel Copen ["[Link]
...
The ‘open’ message asks the supervisor to open a connection to a URL (http or Scol).
The ‘goto’ message does the same thing, then closes the sending Scol machine.
The socklife socket has one distinguishing feature: when it is closed (shutdown or error), the SCOL machine stops.
Scol machines communicate by exchanging messages in the form of command+arguments (see the section on
Channels and communications). When a message reaches its target, the latter searches to see if a function bears the
same name as the command; if so, it executes this command.
In fact, when a Scol machine sends a message to another Scol machine, there is nothing on the face of it to
guarantee that its correspondent has defined a function which bears the name of the command contained in its
message. You can define a ‘vocabulary’ notion: a Scol machine’s output vocabulary corresponds to the group of
commands that it is capable of producing. A Scol machine’s input vocabulary corresponds to the group of
commands that it is capable of interpreting, namely, the group of functions starting with a double underscore.
In order for two machines to communicate with each other, it is essential that the output vocabulary of one
corresponds to the input vocabulary of the other, and vice versa. Otherwise, the messages sent by one machine will
not be interpreted by the other: if Alice sends Bob a message ‘f 1’, Bob has to have the __f function on his
machine (more specifically, in the environment of the channel which connects him to Alice).
Scol’s distinguishing feature is that a machine’s vocabulary is dynamic: you can at any time modify the
environment of a channel, either by adding packages, or by subtracting packages. What this means is that you can
modify the machine’s input and output vocabulary at any time.
When Alice calls Bob’s machine, Alice does not know then what vocabulary Bob is using, but as soon as Bob has
told her which files to compile on her channel, Alice can modify her vocabulary and make it compatible with
Bob’s. Unfortunately, Bob cannot tell Alice which files to compile as he needs a common vocabulary to do this.
To solve this problem, we have defined what we call the standard server and client, which are in fact files written in
the Scol language. Their role is to initiate a communication between two Scol machines. When Alice calls Bob, the
following operations occur:
- Alice uses the standard client on the connection channel to Bob.
- When Bob receives Alice’s connection request, he places the standard server on this channel.
- The standard server then gives the client the list of packages necessary to proceed further.
- The standard client checks that it possesses these packages.
- If there are some missing, it informs the server, which sends them to the client.
- When the requisite packages are in the client’s possession, the server sends the client a start-up script.
- When the script has been sent, the server withdraws the standard server package and runs a script, called server
script.
86
- Similarly, the client withdraws the standard client packages and runs the script that has been sent by the server,
called client script.
- At this time, Alice’s and Bob’s vocabularies are fully synchronized (as long as Bob has sent the right packets).
Bob’s real server application can now begin.
As we have just seen, the server that uses the standard server must supply several elements:
- It must initially place the standard server version 2 on the channels that connect it to its clients. This is done in the
_setserver declaration. Example for a server on port 1285:
_setserver _envchannel _channel 1285 "_load \"locked/[Link]\"";
- It must supply a server script. You need to declare the scriptserver variable:
var scriptserver="_load \"fs/[Link]\"\n_contact";;
- It must supply a client script. You need to declare the scriptuser variable:
var scriptuser="_load \"fs/[Link]\"\nmain
- It must supply the list of packages required by the client. You need to declare the packsusers variable, which
is a list of type [[S S S] r1]: the first string is the name of a package, the other two must be empty strings.
var packsusers=["fs/[Link]" "" ""]::nil;;
- It must supply the minimal version number of the Scol Engine of the clients supported by the site.
var versionuser=0;;
This version number will be compared with the number returned by the _version function.
Example:
The client needs the file “sample/[Link]”. The client’s script is _load “sample/[Link]”\nstart. The server’s script
is _load “sample/[Link]”\nstart. Then the server is written:
/* server */
var packsusers=["sample/[Link]" "" ""]::nil;;
var scriptserver="_load \"sample/[Link]\"\n_contact";;
var scriptuser="_load \"sample/[Link]\"\n_contact";;
var versionuser=0;;
fun main()=
_setserver _envchannel _channel 1285 "_load \"locked/[Link]\"";;
We will see in the ‘Integration in a Web page’ section how to start the standard client “manually”, but in fact the
Scol Engine takes care of it for you when you enter a URL without a prefix or starting with scol://
Note : Versions 1 and 2 of the standard server exist; their file names are "locked/[Link]" and
"locked/[Link]". Version 3 is similar to version 2, but uses the new ‘zip’ compression instead of
‘mzip’.
87
XIII. Integration possibilities
This is of course the most obvious method, which is used mainly on the server side: since the Scol machine has
access to all the files contained in the Scol partitions, all that is required is for the technology that you want to
interface with Scol to produce or use files in these partitions, and for your Scol server to produce or use the same
files.
This is used only on the server side: the server accesses data from another information system via SQL databases
(using Odbc technology)
On the Scol server side, the two libraries are used indiscriminately:
- http client: the technology that you want to interface with Scol is a web technology (cgi, asp, etc).
Consequently, your Scol server can itself become a client of this web technology by performing http requests
itself thanks to the client http library.
- http server: the technology that you want to interface with Scol is a web client technology (often used in
payment systems for example: the payment server makes an http request either itself or via the surfer's web
browser, indicating the result of the operation: success or failure). Your Scol server can thus receive and
process these requests by opening an http server thanks to the server http library.
On the Scol client side, the client http library will mainly be used. This allows the Scol client to access any given
web services, in other words to make a request and analyze the reply. For example, to represent in 3D the result of
a search on an engine such as Altavista or Yahoo, the Scol client will make the search request, receive the reply,
analyze it and convert it into a 3D representation.
a. Simple interfacing
Scol can be run as a Netscape plug-in or as an ActiveX component for MSIE or visual Basic.
To integrate Scol in a Web page, simply enter the following code (the example here describes a 500 by 400 point
zone):
<script LANGUAGE="JavaScript">
<!--
function Load()
{
if([Link]=='Netscape')
{
[Link](‘$browser$%5fload+%22locked%2fstduser%2epkg%22%
0amain+%22scol%2ecryopolis%2ecom%3aCryopolis%22+ffffffff+NIL CSDMRWK
262144’,1,0);
}
else
{
[Link](‘$browser$%5fload+%22locked%2fstduser%2epkg%22%0amain+%2
2scol%2ecryopolis%2ecom%3aCryopolis%22+ffffffff+NIL CSDMRWK 262144’,1,0);
}
}
//-->
</script>
There are in fact differences between Netscape and MSIE in the way Scol is started, but in both cases you use a
LaunchMachine function, by passing the command line as an argument, here a "standard user" client, to port
[Link]:3005
You will notice the syntax of the Launchmachine functions' argument. It consists of a character string containing
three words separated by spaces:
- the machine start-up script: ‘$name$script’ type, the script being in “ strtoweb ” format.
- the machine’s rights (generally CSDMRWK)
- the size of the memory given to the machine.
_load "locked/[Link]"
main "url" ffffffff NIL
Which, by applying the strtoweb function (replaces spaces with + and all non-alphanumeric characters with
%ascii_code_in_hexadecimal) for the [Link]:Cryopolis url, gives:
%5fload+%22locked%2fstduser%2epkg%22%0amain+%22scol%2ecryopolis%2ecom%3aCry
opolis%22+ffffffff+NIL
However, since the Scol machine applies the webtostr function on this string, a function which only looks for the
characters + and % and leaves the others unchanged, it can be written more clearly:
_load+”locked/[Link]”%0amain+”[Link]:Cryopolis”+ffffffff+N
IL
Which gives:
...LaunchMachine(‘$browser$_load+”locked/[Link]”%0amain+”[Link]
[Link]:Cryopolis”+ffffffff+NIL CSDMRWK 262144’...
N.B. the quote mark (") character can only be used provided the apostrophe (‘) is used as a delimiter of the
character strings in Visual Basic or Java Script : …LaunchMachine( ‘ $browser…)
- the script starting the Scol machine in autonomous mode (the Web page starts a Scol machine that is not
integrated in the page, but that is not destroyed when you change pages or close the browser):
_load "locked/[Link]"
main "url"
89
This will produce the following script string:
_load+”locked/[Link]”%0amain+”[Link]:Cryopolis”
Which gives:
...LaunchMachine(‘$browser$_load+”locked/[Link]”%0amain+”[Link].c
om:Cryopolis” CSDMRWK 262144’...
If your site uses DMS architecture (site created with SCS or with Cryonics), the url can also be used to pass
parameters to machines (this involves resource variables that the Scol machine will be able to read thanks to the
_getress function).
The form of the url is then:
Name_machine:port_or_name_service/resource1+value1/resource2+value2…
For example, you want to pass the resource variable ‘login’ with the value Alice, and a resource variable
‘authorization_number’ with the value 123456, for the Cryopolis site. The associated url is:
[Link]:Cryopolis/login+Alice/authorization_number+123456
The Scol machine will be able to read the values ‘Alice’ and ‘123456’, naming them _getress "login" and
_getress "authorization_number" respectively.
Comment: if the value contains special characters, such as + or ', you should remember that your string will be read
in “ webtostr ” format and therefore replace these characters with %ascii_code_hexadecimal.
Furthermore, if you have used characters such as spaces, carriage returns, etc., bear the following in mind:
- the program assumes that between two “ / ” characters in the url, it can apply the webtostr Scol functions then
strextr to obtain a list (resource: :value: :nil) : :nil
If your site does not use DMS architecture (which should be quite rare), you recover all these resource definitions
in the form of a list [[S r1] r1] containing one line per definition, in the “ parameters ” variable.
Instead of _getress "login", you will be able to use switchstr (strextr _getress "parameters") "login"
The Scol machine started as above as an ActiveX component can use the zone which the container allocates to it by
using the following function:
_GETactiveXWindow : fun [Chn I S] ObjWin
The integer is the window’s flag, the string is the window’s name. This function returns nil if the window is not
available, which is the case if:
- the Scol machine has not been started as an ActiveX component or a Netscape plug-in
- the component’s zone has been defined in an invisible web page (only for certain browsers)
d. Sophisticated interfacing
In some applications it is useful to have a Web page communicate with the Scol component that it contains by
using JavaScript in the Web page. This is perfectly possible with Scol.
The starting of the component is different in Netscape, because to make this communication possible the
component must be started by Java (and not JavaScript). The basic Web page is therefore the following:
90
<EMBED name=scol
type=application/x-scol
border="0"
width=500
height=400>
</EMBED>
<SCRIPT LANGUAGE="JavaScript">
<!--
function Message(txt)
{
selectmsg(txt);
}
//--></SCRIPT>
<applet name="myscol" code="[Link]"
width=5
height=5
mayscript>
</applet>
</OBJECT>
<script LANGUAGE="JavaScript">
<!--
function Load()
{
if([Link]=='Netscape')
{
[Link](‘$browser$_load+”locked/[Link]”%0amain+”[Link]
[Link]:Cryopolis”+ffffffff+NIL CSDMRWK 262144’,document);
}
else
{
[Link](‘$browser$_load+”locked/[Link]”%0amain+”[Link]
[Link]:Cryopolis”+ffffffff+NIL CSDMRWK 262144’,1,0);
}
}
//-->
</script>
<script language="JavaScript"><!--
function selectmsg(msg)
{
...
}
//--></script>
<script language="VBScript"><!--
Sub scol_Message(msg)
call selectmsg(msg)
end sub
--></script>
In this example, the selectmsg function receives the messages sent by the Scol machine. These messages are sent
by the function :
_onX : fun [Comm] I
N.B.: For reasons known only to Netscape’s developers, the JavaScript code processing the message must specify
complete URLs rather than relative ones, otherwise the Java machine crashes without warning.
To send a message to the Scol machine, the latter must first define the channel supposed to receive them: for this
definition you use the function:
_setX : fun [Chn] Chn
91
Then you just write in JavaScript, for example:
if([Link]=='Netscape')
{
[Link]('_f 1 "abc"');
}
else
{
[Link]('_f 1 "abc"');
}
This message will be received by the channel defined by the_setX function. The Scol machine will then search
for a _f function taking two arguments, an integer and a string. The message’s format is that of Scol messages and
therefore that of the scripts.
ActiveX technology is a Microsoft technology, available only with Windows. It is based on the concept of
components and container:
- a component is any given functionality that is relatively autonomous and which generally requires a window
in which it can offer a graphic interface, and which can communicate externally via an incoming and outgoing
API (sending/receiving of messages, which are in fact sets of calls to functions and callbacks)
- a container is a document (typically a window), in which you define a certain number of zones (sub-windows)
in which you activate ActiveX components. Once the components have been activated, the container can
communicate with them via the component’s API.
Scol technology is both an ActiveX component and container. The ActiveX component mode is used to integrate
Scol in the Internet Explorer browser (which is itself an ActiveX container). The ActiveX container mode can be
used on both the client side and the server side:
- On the client side, it is used to integrate - in the Scol client interface - functionalities available in the form of
ActiveX components. For example, a Web page (Internet Explorer is also an ActiveX component), a
particular viewer, etc. However this presents two limitations (which only exist if your service is open to the
public):
- Since ActiveX technology is only available on Windows, only visitors to your site who use Windows will be
able to access these functionalities
- Scol does not handle, for security reasons, the downloading of your ActiveX components. You therefore have
to perform this operation yourself. However, the Scol program can detect the presence of an ActiveX
component.
The Scol machine has a Telnet API (client BSD sockets). This can be useful on the server or the client side:
- on the server side, you can open a connection to any given TCP/IP service.
- on the client side, you can also connect to any given TCP/IP service. However, most firewalls block this type
of connection, and there is no way of getting round it. It should be noted however that the Scol Telnet library
is compatible with SocksHost type proxies.
It is always possible to connect to a Scol machine by passing yourself off as another Scol machine. This makes
interfacing far simpler, as it takes advantage of the parsing and channel management that are already integrated in
a Scol machine. Traditional TCP/IP sockets are used for this with the following protocol:
- each message consists of two parts:
- a two-byte header coding the size of the message body (in the order low byte, high byte)
- a message body which is in fact a line of Scol script (refer to the relevant chapter for details about the syntax).
92
XIV. DMS Programming: Distributed Modules System
This chapter describes the architecture of programs referred to as DMS. This is a “component” type architecture;
as such, its purpose is to save developers from having to redevelop everything with each new application, by
allowing them to use components from other applications. For this reason, we cannot give a complete example of
its use. We will content ourselves with presenting some examples of components. To create applications from
components, you will need the SCS development kit, based on the DMS architecture.
1. Presentation
Scol technology is based on a programming language that integrates Internet communication possibilities
associated with a certain number of graphic, 3D, multimedia, SQL, etc. libraries. The first objective of the Scol
technology is therefore reached: to provide developers with a simple and powerful tool that makes development
faster and more reliable. The technical difficulties are resolved by the technology; consequently developers need
only concentrate on the real problems, those specific to the application they are developing.
The technology’s second objective is more ambitious: Scol technology can also be of interest to creative users who
are not necessarily experienced in programming techniques, in other words, users who would adopt an integrator
approach, taking a graphic element here, an interfacing element or part of a program there, to subsequently build a
distributed-type application, a virtual world for example.
For this purpose alone, it would have been possible to program a kind of Wizard that would ask users for their
preferences, suggest some options and build a ready-to-use application. This approach would soon have proved
limited and disappointing, since such a tool would offer no flexibility.
The solution chosen was to define a particular method of using Scol technology. This method makes it possible to
homogenize programming developments by introducing the concept of the “module”. Since the modules are
distributed (in the IT sense of the word), the programming method is known as DMS: Distributed Modules System.
A module is part of a program that performs a given function. Seen from the outside, modules all resemble one
another, a bit like an integrated circuit: the case is the same, the pins are all similar, only the number, the direction
(incoming or outgoing) and the function of the pins are different. To create an application, all you need to do is
assemble the modules and create links between the pins. This is done with the mouse and without
programming.
The modules are distributed: one part runs on a machine called the ‘Server’, the other part runs on user machines
called ‘Clients’. Deciding what should be calculated on the server and what should be calculated on the clients is a
complex IT problem, which is out of the general public’s reach. The module therefore removes this problem: it is
not up to the person who assembles these modules to determine the question, but to a module’s developer.
There are other systems based on modular programming. The original aspect of DMS is twofold:
- Modules are assembled by creating links between the modules, and not using a programming language, often
referred to as a script language. Having to use such a language, even if simple, puts the use of these architectures
outside the reach of the general public
- The modules are distributed, but the user does not need to concern him or herself with it. He or she does not need
to define one assembly of modules for the server and another for the clients; only one assembly needs to be
defined.
DMS architecture is not only useful for the general public, it also saves the developer a lot of time. Developing a
DMS module is easy. Transforming a simple function into a DMS module means you do not have to develop
functionalities already present in other modules: log files, console windows, passwords, statistics, etc. In this way
the DMS constantly evolves, for everyone’s benefit, as new modules are developed.
93
- the module editor: this editor will integrate itself in the editor of the DMS sites (SCS)
Each of these parts of programs uses an API the details of which are given further on.
2. Definitions
Dms Site
Distributed application complying with the architecture described in this document
Client
Software running on the computer of a Dms site user
Server
Software putting users into contact. There is one server for each Dms site.
Module
Constituent element of a Dms site. Usually distributed, it has a server part which runs on the server side, and a
client part which is duplicated on the client machines. To make discussion simpler we will say ‘server module’ for
‘server part of a module’, and ‘client module’ for ‘client part of a module’.
Similarly, we will say ‘associated client module and server module’ for ‘client and server parts of a module’.
User
Generalizing concept of a user present in the site. This user is either real (in which case it corresponds to a client),
or virtual (meaning an entity stored on the server). The users move along the links.
Exactly one user corresponds to each client.
Event
Signal leaving a module. The event is either a client event (the source of the event is a client), or a server event (the
event is produced on the server): this localization is decided by the module’s author. A User is generally associated
with such a signal: in fact the signal is the sign that the User is “moving”.
Action
Signal entering a module. The action is either a client action (the action is usually processed by a client module), or
a server action (the action is processed by the server module): This localization is decided by the module’s author.
Message
Message sent between a server module and an associated client module (in either direction).
Link
Association of an event of one module with an action of another module, possibly subject to conditions. You can
assign a parameter to a link. This will be referred to as the ‘link’s parameter’.
Zone
Rectangular graphic zone used by a module to present a result, an interface, etc.
Document
Graphic window in which one or several zones can be defined. The documents are organized in a hierarchy. This
hierarchy defines two types of child windows: “ popup ” child documents (opening above the parent document),
and simple child documents, corresponding to a zone of the parent document. A main document is one which
doesn’t have a parent document.
A Dms site uses two main documents, the server document and the client document.
3. Principles
94
3.a Module architecture
The architecture of a Dms site is modular: a site is made up of a variable number of modules, connected to each
other via links. Each module manages one or more functionalities: log, authentication, 3D space, etc. Each module
can have a distributed operation: one part of the processing is performed on the server, another on the clients.
The role of a Dms site’s author is therefore to select a certain number of modules and assemble them by creating
links between them.
One of the major problems in creating an application which puts different users into contact is to establish how the
processing will be divided between the server and the clients. This problem is eminently technical, and therefore
beyond, a priori, someone who would be building a Dms site. The problem of distribution will therefore be
resolved within a module, by whoever has developed the module.
Generally, each module will be divided in two, one part running on the server, another on the clients. The
communication between the client part and the server part of a module will be managed exclusively by the author
of the module, using the traditional communication techniques included in Scol.
Communication between the modules will be in the form of links, and will therefore be defined by the site’s author.
The modules each have a name, the only restrictions on which are that:
- two sibling modules must have different names (see encapsulation later on to know more about sibling
modules)
- a name must not start with the character ‘.’
A module can at any time request the use of one of a document’s zones, or on the contrary, stop using a zone. The
system manages the display of the documents in such a way that the document is visible as soon as at least one of
its zones is currently being used by a module. A document that no longer has a zone in use is destroyed, except for
the main document, which is the parent of all the others, and shows the application’s presence.
3.c Encapsulation
The modules can be encapsulated: a set of modules can be grouped together and replaced by a black box which
contains them. The modules are therefore organized in a tree of modules whose non-leaf nodes are black boxes.
Each module can then be linked to a sibling module, a child module or the parent module. The black box acts as a
transparent relay: actions are directly connected to events, in both directions.
A link joins one of a module’s events to one of another module’s actions. The number of links attached to a given
event or a given action is not limited. The links are directional: from the event to the action. A default parameter
and/or a condition is associated with each link.
A module can trigger an event at any time. The system converts it, according to the links, into actions for other
modules. Each module concerned by the action is informed of the sender’s identity, and can reply, if the sender has
provided for this, using a system of “ tags ”.
95
- communication by a reply:
When a module issues an event, it can associate it with a reply “ tag ”, which is actually a callback function that
expects to receive a parameter and/or a list of Users. The module that receives an action associated with this event
can then reply to this “ tag ” by providing a parameter and/or a list of Users.
In fact an event represents the “ movement ” of a User, leaving a module via a particular pin. Links leading from
this pin take the User to other modules. This doesn’t mean however that the User quits the module that has
produced the event: a User can be ubiquitous, meaning he or she can be present in several modules at the same
time.
Each of these elements is optional and can be replaced by nil. However, it is extremely rare for the User argument
to be nil, since an event is in fact the movement of a User.
If an event is produced by a client module, the associated User is implicitly the one that corresponds to the client
module.
If an event leads to an action that is usually located on a client module, the routing carried out depends on the
associated User:
- if the User is real (i.e. corresponds to a client), the action is processed by the module of the associated client
- if the User is virtual, the action is processed by the server module
This means that an event's User parameter allows all routing problems to be resolved.
Creating a site consists in assembling a set of modules. Each machine (client or server) has an approximate copy of
this site: this means that certain modules are not represented on each machine. For example, only the 3D space
module where a user is located is represented on this user's machine; however, all the site’s 3D space modules are
represented on the server. This observation brings up the question of the dynamic activation of the modules: while
the modules are all active on the server side, only a few modules are active on the client side: the number and
nature of the active client modules varies according to the time and the client.
In fact, it is the server module that triggers the activation of the client module on a given client machine. For each
server module, the system manages the list of activated client modules, which allows it in particular to filter
messages, thus guaranteeing security in the exchange of messages. Activation is not therefore automatic: the fact
that an event is linked to one of a module’s actions does not mean that that this module will be created if the event
occurs. If the event occurs when the module receiving the action has not been created, the event is simply ignored.
To activate a module, a certain amount of data must be transmitted to the client, and the client must, if necessary,
download a certain number of files (in particular Scol source files describing the operating of the client module).
Activating a module on a client is therefore a complex operation that may take some time. During this time, the
client module is “ dormant ” and buffers the messages and actions it receives until it can be properly started: once
all the necessary files are present, the client module is compiled, started, and all the buffered messages are
processed.
96
3.f Users and UserInstances
We have seen that Users are the mobile elements of the DMS architecture: they move along the module graph
when events occur. A module therefore receives a flow of Users.
When the module considers it useful, it can define a structure known as a UserInstance. For a given module, only
one UserInstance can be defined per User. The UserInstance object is an object:
- associated with a User,
- distributed and synchronized between the client and server parts of a module, and offering highly practical
possibilities for communication between these different parts.
The site editor (whose commercial name is SCS for Site Construction Set) is the tool linked with the DMS
architecture. It is used to:
- select modules to be integrated in the site: create, remove
- define server and client documents
- define links between modules
- assign zones to the modules: indicate in which zone the 3D will be displayed, a button, an image, etc.
- start the module editors
Indeed, each module usually contains an editor that is used to define its parameters. For example:
- defining a 3D space for a module managing 3D space
- defining the texts of a display banner module
A distinction will be made between the two types of editor: site editors and module editors. The module editor is
usually written by the module developer.
4. Downloading of resources
The server also plays the role of resource distributor. A resource is a given set of bytes. A resource is named and
belongs to the module that is its owner. Resources are the data that the clients will be able to download: files
containing the client module’s program, graphic, 3D or sound files, etc. It is important that each module records
the resources that the client may need, as this ensures automatic update and mobile code possibilities: otherwise
only clients that already have these files will be able to operate normally. This may be an oversight or a deliberate
omission to select clients. When a module is being developed, it is important to check that when a “first time”
client connects to the site, it will indeed download the client data specific to the module.
A resource is usually accessible to any client whose client module corresponding to the proprietary server module
has been activated. However, the resource can be protected by limiting access only to authorized clients.
On the server side, the resource may be present in the server’s memory or stored on disk. Only in the first case can
it be compressed before being downloaded by the client. In the second case, the data will be directly transferred: it
is therefore recommended that the file already be compressed (jpeg graphic file for example).
On the client side, the resource can be stored in the cache under a given name that would show – when
subsequently used - whether the resource needs to be downloaded or if it is already present. The resource can also
be provided directly to the client, without saving it to the disk first.
The server calculates the signature of the resources submitted to it. This signature is transmitted to the client
module when it is created. The client module checks the signature of the file bearing the name of the resource and,
if it doesn’t correspond, downloads the resource again. Checking that a client does indeed have a given file is done
by comparing the signature of its content, and not by looking at its creation date, as this latter method is much less
reliable.
97
A server module can:
- record a resource by specifying its name
- unrecord a resource by specifying its name
- unrecord all the resources
- authorize a client to access a resource
A client can also transfer a resource to the server, through an upload mechanism.
N.B.: when you are developing a module and are working on the client part, remember to restart the server in order
for the changes made to the client code to be accepted. Indeed, the server calculates the signature of the resources
when it is started. If you change a resource without restarting the server, the signature of the old resource stays in
its memory. If you then start a client, the server will transmit to it the old resource, which will be placed in the
cache partition. This will mask the new resource, and you will be left wondering why your changes have not been
accepted.
Dmc (Distributed Modules Class) files define a module class: for example, a log management module, a 3D
management module, a text interface module, etc. A Dmc file contains the list of files used by the module class
-typically parts of programs - which will be automatically recorded as resources on the server, then the module
start-up scripts, one for the server, one for the client, and one for the editor.
Note that the DMS system creates an unplugged channel for each module, whether this is on the server, the client
or the editor. This channel inherits APIs described further on. Consequently, communication between modules
always takes place through the API.
It may be noted that in the previous version of SCS, the site was defined using two types of file:
- the Scs file containing the module graph and the definition of the documents
- the dmi files each containing a module’s parameters.
The files for the ‘…Load’ lines do not need to be rewritten in the ‘…Needed’ lines: the system assumes that they
must be necessary for the module to start (since they have to be compiled).
To determine the list of files that are useful to the site (with a view to duplicating the site on another server for
example), the system concatenates the lists register, registerF, serverNeeded, serverLoad, clientNeeded and
clientLoad.
Let us now describe the start-up mechanism of a server module. When a server module is created, the system
checks for the presence of the ‘serverNeeded’ files. It then creates an unplugged channel that inherits the server
API, successively compiles the files for the serverLoad line in this channel, then runs the IniDMI function (see
further on).
Now let's turn our attention to the start-up mechanism of a client module. When the module is activated on a client
machine, this machine starts by checking that it has the Dmc file. If this isn’t the case, it downloads it from the
server. This file does not have to be declared in the list of resources (‘register” and ‘registerF’ lines), as this is done
automatically for all the modules that are present on the server.
Then, the client makes sure that it has all the files for the ‘clientNeeded’ line. If any are missing, it asks the server
to supply them. This is only possible if these files appear on the ‘register’ or ‘registerF’ line. If only one file is
missing, a dialog box appears on the client, which is subsequently interrupted.
When all the required files are present, the client module is created as follows: an unplugged channel is created,
inheriting the client API, then the files for the clientLoad line are successively compiled, then the IniDMI function
(see further on) is called.
As regards the editor, to start the module editor, the site editor checks that the ‘editorNeeded’ files are present. If
only one is missing, a dialog box appears to indicate that the editor cannot be started. If all the files are present, the
editor creates an unplugged channel that inherits the editor API, successively complies the ‘editorLoad’ line files,
then calls the ‘IniEditor’ function (see further on).
In the previous version, there were the lines serverScript, clientScript and editorScript, which defined the start-up
script for the server, client and editor parts. These scripts were always a series of _load. Consequently, this system
has been replaced by the lines serverLoad, clientLoad and editorLoad, which are easier to use and offer the
possibility of defining relative paths. However, upwards compatibility is guaranteed.
The help file defined on the ‘helpFile’ line can be in HTML format (.htm or .html extensions) or in text format (all
other extensions). The HTML files are supposed to be localized, i.e. the loaded file will match to language
parameterized in the SCOL engine (english by default).
99
Example : if helpFile ./help/[Link] is present in the dmc file, the help file which will be opened
when the user click on the help button will be ‘./help/[Link]’ if the SCOL engine is configured in
english.
The Dms file represents a module tree. Each node contains a number of named definition blocks, and no two
blocks can have the same name. A definition block consists of a list of ‘name {value1 {value2 … {valueN}…}}’
lines. The values are strings of bytes.
The site’s main node is in fact the “black box” that contains the whole of the site. It contains the site’s global
definitions (name, port, documents, etc.).
The syntax of the dms file is as follows (the file is in strextr format):
Module : :=
module name server_number
(Definition)*
(Module)*
endmod
Definition : :=
def name
(Line)*
enddef
Line : :=
> name (value)*
A dmi definition block describes the basic parameters of a module instance, or a black box.
The fields defined above are standard fields. Some modules will define additional fields that are specific to them:
advertisement texts for a display banner, address of a directory for an automatic recording module. However, a
more elegant solution would be to put this specific data in different definition blocks.
Events and actions are defined either on the server or on the client, which is why there are the lines event/eventC,
action/actionC. Determining whether an event (or an action respectively) needs to be defined in the event or the
eventC line (or the action or actionC line) is very simple: everything depends on the module that causes the event
(resp. that processes the action), server or client.
The register and registerF lines must contain the files specific to the instance. Here it is pointless to redeclare the
files contained in the Dmc. The same comments will be made on the ‘register’ and ‘registerF’ files as for the Dmc
files.
The serverNeeded line is for determining the files that are useful to the site and are not already in the register and
registerF lines.
For a black box, the following fields will appear in the dmi definition block:
name [name]: name of the black box
in [name]: incoming pin
out [name]: outgoing pin
The ‘link’ definition block only contains lines in the following form:
[event] [destination] [action] [param] [reply] [condition]: description of a link assigned to a module event
- The destination module is defined by the ‘destination’ field as follows:
- .. : parent
- .name : child
- name : sibling
The reply parameter here is for upwards compatibility.
101
The conditions for links are a string intended to be used by the strextr function. Each line corresponds to an
activation condition: there is a logical OR between the lines.
Each line is made up of a list of basic conditions. Each condition corresponds to one or more words in the line. All
the basic conditions of a line must be filled in: there is a logical AND between each basic condition.
The first word of a basic condition shows what type of condition it is, the words that follow give the arguments.
102
There are nine conditions:
!: reverse condition of the rest of the line
login: does the login have a particular value (1 parameter)?
notlogin: is the login different from a particular value (1 parameter)?
ip: does the IP address have a particular value (1 parameter)?
notip: is the IP address different from a particular value (1 parameter)?
item: does the user have a particular object (the parameter is the object’s reference)?
noitem: does the user not have a particular object (the parameter is the object’s reference)?
items: does the user have a particular object in a particular quantity (2 parameters: object reference and
quantity)?
items: does the user not have a particular object in a particular quantity (2 parameters: object reference and
quantity)?
ActiveX: the client uses Scol in ActiveX component mode (0 parameter). In this mode the browser should not
usually be started from Scol, as this would change the current page (the one that Scol is running in), and would
therefore destroy the client. It is better for the Web page to be programmed (javascript/vbscript) to open a new
frame.
The timeout is used to detect clients who have disconnected themselves accidentally. The TCP/IP protocol means
the timeout may last several minutes before the server detects the disappearance of a client. Here, a signal is sent at
regular intervals to all the clients. The clients simply need to reply to this signal with another signal. When the
server sends a signal, it checks that it has received the previous signal, otherwise it disconnects the client itself.
These definition blocks have the same syntax and define the client and server documents respectively.
doc [nom] [type] [resizeFlag] [x1] [y1] [x2] [y2] [w] [h] [bitmap] [bitmapFlag] [color] :
(definition of a document, possibly with a document background image)
zone [nom] [resizeFlag] [x1] [y1] [x2] [y2] [w] [h] [color]
(definition of a zone of the document previously defined)
... recursion
enddoc: end of the document definition (compulsory)
A main document must be defined for each definition block: this means the ‘client’ and ‘server’ documents
respectively.
To make the download bar appear, a ‘download’ zone must be defined in the ‘client’ document.
Server
module 1 (channels structure)
unplugged module 2
module n
dhdms
client 1
client 2
internet
client n
104
6 API
1.a Structures
Modules:
I _DEFsave
Saves the site
105
Inter-module messages: triggering of events, direct sending of messages
I _DMSevent this DMI concerning CLIENT event S param S reply S
Activates an event by specifying a parameter and a reply. If the parameter is nil, the default parameter is used. The
reply field should be left at nil.
I _DMSeventTag module user User event S param S others [User r1] [callback
fun[param S others [User r1]] I flag timeout]
Causes an event possibly accompanied by a tag. The flag is unused.
Clients:
Each client has a list of variables, called resources variables. The API can be used to define the value of any
variable.
Users:
The Users are the mobile entities in the graph. They are of several types:
- client/virtual: corresponds either to a client, or a resident
- global/local: defined for everyone/only on a given client
Each User has a list of items (this was previously managed on the CLIENT structure, the former functions remain
valid). This list is an "inventory" containing objects defined by a reference, a name in clear text, a quantity and a
date.
S _ITEMname Item
Returns the name in clear text
I _ITEMquantity Item
Returns the quantity
I UclearItem user
Clears all a user’s items
UserInstances:
UserInstances are a service offered to each module for defining an object linked to a User and providing concepts
of distribution, communication and security.
UserInstances are created at server or client level, but a client can only create local instances. Instances are created
by specifying:
- a module
- a user
- a class
- parameters
- visibility
The concept of visibility is important: a global instance is only broadcast on clients whose instance associated with
this client (i.e., the instance associated with the User corresponding to the client) can ‘see’ it.
At the moment there is only one type of visibility: by tree. Each instance is placed in a tree. Visibility is then
defined by a path in a tree (the list of node names starting from the apex), and a commutativity flag. The rules for
visibility are as follows.
- an instance "sees" all the instances that are in its sub-tree (same node or descent)
- if an instance has its commutativity flag set to 1, all instances that it can see can also see this instance.
UserI UcreateUI module DMI user User class S parameters [[S r1] r1] visibility
Visibility
Creates a user instance. Nil as a visibility parameter indicates zero visibility. You will usually use 'treeNew nil nil'
to define maximum visibility (instance at the apex of the tree)
Zone management:
Localization functions:
The Dms architecture integrates a localization kit used to display text messages in different languages. The
messages are stored in resource files.
For each module, one resource file per language must be created.
The resource files thus created must be put in a /module lang subdirectory.
The files will respect the following syntax:
- the name of the file takes the name of the module (name of the .dmc file without its extension)
- a first extension indicates the name of the language of the resource file
(language in English, example: .english, .french,...)
- a second extension, .lang, identifies the resource files.
Each line of the resource file corresponds to a reference and to the translation of the corresponding message in the
language specified in the file’s name.
On the client, the resource files are stored in the form [Link] directly in the module’s directory.
110
Within a message, \n is used for the carriage return.
Spaces at the beginning of a message, at the end of a message or two or more spaces in succession will not be taken
into account. You can use \[space] as a solution to this but it is better to add spaces directly into the program code,
as this stops them from being overlooked when the resource files are translated.
* SERVER API:
111
Other services:
I _DMStime
Returns the time of the server
I _DMStickcount
Returns the tickcount value of the server
ObjFont Font
Site’s main font.
S DMSpath
Dms file path
S _DMSgetpath nom_fichier S
Returns the path of a file name
S _adderror message S
Adds an error message to the logbook. If this occurs when the server is started, the server will stop as soon as the
initialization of each module is complete.
S _addwarning message S
Adds a warning message to the logbook
S _logBook
Returns the content of the logbook
IniDMI (param S)
Function called when the instance is initialized. The parameter that was previously the name of the Dmi file is no
longer used.
Client
module 1 (channels structure)
unplugged module 2
module n
dhdms
server112
internet
6.2. Client API
2.a Structures
USER_global
USER_client
USER_changeClass
USER_changeParam
USER_changeAll
113
I _DMStagForget tag Tag
Indicates that the tag can be forgotten.
Users:
User UcreateUser
Creates a local virtual user.
UserInstances:
UserI UcreateUI module DMI user User class S parameters [[S r1] r1]
Creates an instance for a local User (this is not widely used).
UserI UcbMessage ui UserI liste_de_messages [[S callback fun [ui UserI action
S param S] I] r1]
Defines callbacks on receipts of messages. These callbacks are simply concatenated with the list present and may
mask previous definitions.
Zone management:
Requests the downloading of a resource by giving its name, the file in which the resource must be stored and the
callback when the download has finished. The priority parameter indicates a download command: 0 priority
requests come first.
The salve parameter is obsolete.
115
If the file is already there, with the right signature, the callback can be called synchronously. The _RSCdownload
and _RSCdownloadP functions return:
- nil if the callback has been called,
- otherwise an RSC object: the download is in progress. It is possible to abort it.
If the name’s value is nil, it is a synchronization download whose callback will be called when all the downloads
previously requested (and of lower priority) have been carried out.
If the file’s value is nil, the resource is still downloaded, is not stored on disk and is passed to the callback, whereas
otherwise it is the name of the file that is passed to the callback (nil if download is impossible).
I _RSCabortDMI module
Aborts the downloads in progress for a module
116
Localization functions:
Other services:
I _DMStime
Returns the server time (approximation)
I _DMStickcount
Returns the server’s tickcount value (approximation)
ObjFont Font
Site’s main font
ObjCursor StdCursor
Standard cursor
ObjCursor HandCursor
Hand cursor
ObjCursor CrossCursor
Cross cursor
S _DMSgetpath nom_fichier S
Returns a file name path
IniDMI (param S)
Function called when the instance is initialized. The parameter is that sent by _DMScreateClientDMI.
Writing a module editor is not very complicated: remember that the only purpose of a module editor is to create
definition blocks (at least one "dmi" block).
You will use a library called 'templateEdit1' which offers a simple API and a clean and homogeneous graphic
interface:
- You must define the IniEditor which will be the editor's initialization function
- From the start this function will call the startEditor function with the appropriate parameters, and in particular
the definition of two callbacks:
- load: callback called when the module is loaded. This function has access to the current values of the
module’s definition blocks
- save: callback called when saving takes place and which much define the new definition blocks.
117
- The IniEditor function will then initialize the graphic interfaces specific to the module.
- Lastly it will finish by calling the openDMI function which will call the load callback.
IniEditor(param S)
Function called when the editor is started. The parameter is no longer used.
118
7. Example 1 : module running only on the server.
The following example is of a module that manages an automaton able to receive messages, analyze them and
reply to them. Usually, this automaton is used by connecting it on a chat cell: the automaton "hears" and can reply
either to a single user or to all of them.
File: Dms/Tutorial/Bot0/[Link]
name Bot
serverNeeded ./[Link]
serverLoad ./[Link]
editorLoad _load\ "Dms/L/[Link]"\n_load\
"locked/lib/[Link]"\n_load\ "./[Link]"
bitmap ./[Link]
tree ./[Link]
helpFile ./[Link]
version 2 2
fun hear_bot(from,u,action,text,ulist,tag)=
if !strcmp text "foo" then
(private u "<Bot> bar\n";
0)
else if !strcmp text "time" then
(broad strcat "<Bot> " ctime time;
0)
else let hd strextr text -> l in
if !strcmp hd l "square" then
(let atoi hd tl l -> x in broad strcat "<Bot> " itoa x*x;
0)
else nil;;
fun IniDMI(file)=
_DMSregister this nil nil nil;
_DMSdefineActions this ["in" @in_bot]::["out" @out_bot]::["hear"
@hear_bot]::nil;;
typeof bannerll=ObjText;;
typeof ll=ObjList;;
typeof addll= ObjButton;;
typeof delll = ObjButton;;
typeof links=[S r1];;
fun updatel2(s,b)=
_ADDlist ll 1000 s;;
fun updatel()=
_RSTlist ll;
apply_on_list links @updatel2 0;;
fun addr(s)=
if s==nil then nil
else
(set links=conc links s::nil;
updatel);;
fun _rem(x,b)=
let _GETlist ll ->[i _] in
let nth_list links i -> a in
if a==nil then nil else
(set links=remove_from_list links a;
updatel);;
fun fdlink(a,b)=
if strcmp hd a "botevent" then 0
else (set links=conc links (hd tl a)::nil; 0);;
fun suppevent(l)=
if l==nil then nil
else let l->[a n] in ("botevent"::a::nil)::("event"::a::nil)::suppevent n;;
120
fun save (filename, n)=
("action"::"in"::nil)::
("action"::"out"::nil)::
("action"::"hear"::nil)::
("event"::"broad"::nil)::
("event"::"private"::nil)::
suppevent links;;
fun IniEditor(s)=
let [315 340] -> [w h] in
let startEditor
_channel nil nil nil 315 340 WN_NORMAL-WN_SIZEBOX EDITOR_NORMAL
s nil nil nil
@load @save nil
-> ed in
let getEditWin ed -> editWin in
(
_CBwinSize editWin @rflSizeEditWin 0;
The Dmc file holds no surprises, it corresponds point for point with what was explained during the description of
the Dmc format. You simply need to take note of which files are used by the module and how the scripts are
defined.
The [Link] file is at the heart of the program: it works on the server. The IniDmi function simply defines the
callbacks on the three actions the module recognizes: in, out and hear:
- in: this entry informs the robot that someone has just arrived
- out: this entry informs the robot that someone has just left
- hear: this entry informs the robot that a message has just been "heard"
The module consequently calls three functions, in_bot, out_bot and hear_bot. The idea is this: if the bot module is
correctly connected, the in_bot function will be called each time a visitor enters the world; the out_bot function
will be called each time a visitor leaves the world; the hear_bot function will be called each time a visitor says
something.
These three functions have a User-type u argument. To retrieve a user’s name, you will convert the User into
CLIENT with the CtoU function and you will use the _DMSgetLogin function, which takes a CLIENT-type as an
argument and returns a character string type (see server API )
In the hear_bot function, the text heard is passed in the ‘text’ argument. To split this argument into words for a
syntactic analysis, you simply apply the two ‘hd strextr’ functions to it. The result is a list of character strings (type
121
[S r1]). To analyze this list, you use the classic functions hd and tl. You can also use the nth_list function (see
standard library).
The [Link] file illustrates how to define an editor based on functions predefined in the
Dms/L/[Link] file. In this already complex editor example, it is a question of offering to the
user the possibility of creating new events. The important function is startEditor. This function creates the
editor’s standard window (returned by the getEditWin function), with the Ok, Apply and Cancel buttons, icon,
etc. Two parameters of this function define the callbacks load and save.
The load callback is called when the Dmi file is loaded: it takes as an argument the content of the Dmi file to which
you have already applied the strextr function. The argument’s type is therefore [[S r1] r1].
The save callback is called when the Dmi file is saved. It must return a sequence of lines describing the events, the
actions, the zones, and the specific parameters of the module. This result must be the [[S r1] r1] type.
startEditor
channel nil 0 0 315 340 WN_NORMAL-WN_SIZEBOX EDITOR_NORMAL
s "Dms/Bots/Bot0/[Link]" "Dms/Bots/Bot0/[Link]"
"Dms/Bots/Bot0/[Link]"
@load @save nil;
The rest of the [Link] file manages a list type graphic object, as well as 2 buttons. For this you can use the
API 2D functions on the ObjWin returned by the getEditWin function. For example you can define a callback in
order to reposition the graphic objects when the user resize the editor window .
Exercises:
quicksort: ask the robot to sort a word list
calculator: rather than calculating a square number, take an arithmetical expression (in reverse polish notation
to make it simpler)
guide: ask the bot to teleport you somewhere
good manners: automatically teleport a visitor who has said ‘shit’ to jail
successfully take the Turing test.
The following example is a distributed module. It defines a button on the interface of the client and/or server.
name Button
register ./[Link]
serverNeeded
serverLoad ./[Link]
clientNeeded
clientLoad ./[Link]
editorLoad _load\ "Dms/L/[Link]"\n_load\ "./[Link]"
bitmap ./[Link]
tree ./[Link]
helpFile ./[Link]
version 2 2
File: Dms/Interf/Button/[Link]
/* Button Server - DMS - march 98 - by Sylvain HUET */
/* Rev. 0101 - Aug. '98 - by Marc BARILLEY */
122
fun start(from,u,action,param,ulist,tag)=
if _DMScreateClientDMI this UtoC u nil then
_DMSeventTag this u "started" nil nil nil
else nil;;
fun end(from,u,action,param,ulist,tag)=
if _DMSdelClientDMI this UtoC u then
_DMSeventTag this u "ended" nil nil nil
else nil;;
fun IniDMI(file)=
_DMSregister this nil nil nil;
_DMSdefineActions this ["start" @start]::["end" @end]::nil;;
typeof button=ObjButton;;
fun _end(s)=
_DMSdelete this;;
fun _resizeI(x,s)=
let x->[win x y w h] in _SIZEbutton button w h x y;
0;;
fun IniDMI(param)=
let _DMSgetZone this "Button" @_end @_resizeI @_end ->[win x y w h] in
if win==nil then nil else
set button=_CBbutton _CRbutton _channel win x y w h 0 _DMSgetName this
@pressbut 0
;;
fun IniEditor(s)=
let startEditor
_channel nil nil nil 315 0 WN_NORMAL-WN_SIZEBOX EDITOR_NORMAL
s nil nil nil
nil @save nil
-> ed in
if s==nil then nil else openDMI ed;
0;;
The following example is a module capable of asking the user a question in the form of a message box. We are
particularly interested in the exchange of messages between the client module and the server module.
fun removecli(l,c)=
if l==nil then nil else let l->[a n] in
if [Link]==c then removecli n c else a::removecli n c;;
fun logout(cli)=
set qu=removecli qu cli;
0;;
fun in(from,u,action,param,ulist,tag,i)=
let UtoC u-> cli in
let if i==nil then param else nth_list quizz i -> txt in
(_DMScreateClientDMI this cli nil;
_DMSsend this cli Cquizz [txt i];
set qu=(mkQz[cli txt i])::qu;
0);;
fun getQuizz(l,i)=
if l==nil then nil
else let l->[q n] in
if !strcmp hd q "quizz" then
(_DMSdefineActions this [strcat "in" itoa i mkfun7 @in i]::nil;
124
(hd tl q)::getQuizz n i+1)
else getQuizz n i;;
fun IniDMI(file)=
let _DMSgetDef this "dmi" ->l in
(set quizz=getQuizz l 0);
_DMSregister this nil @logout nil;
_DMSdefineActions this ["in" mkfun7 @in nil]::nil;;
fun IniDMI(param)=0;;
fun res(x,i,r)=
_DMSsend this Canswer [i r];;
fun __quizz(s,i)=
_DLGrflmessage _DLGMessageBox _channel DMSwin "Question" s 2 @res i;;
typeof editWin=ObjWin;;
typeof quizz=tab ObjText;;
fun onequizz(i,x)=
_CRtext _channel editWin 5 25+i*25 10 20 ET_ALIGN_CENTER itoa i;
_CReditLine _channel editWin 20 25+i*25 290 20 ET_DOWN+ET_AHSCROLL "";;
fun createQuizz()=
set quizz=create_tab 8 @onequizz 0;;
fun getQuizz(l)=
if l==nil then nil
else let l->[q n] in
if !strcmp hd q "quizz" then (hd tl q)::getQuizz n
else getQuizz n;;
fun setQuizz(l,i)=
if l==nil || i>=8 then 0
else let l->[a n] in
(_SETtext quizz.i a;
setQuizz n i+1);;
/* SCS editor */
fun load (l) =
setQuizz getQuizz l 0;
0;;
fun getText(i)=
if i==8 then nil
else
("action"::(strcat "in" itoa i)::nil)::
("event"::(strcat "yes" itoa i)::nil)::
("event"::(strcat "no" itoa i)::nil)::
("quizz"::(_GETtext quizz.i)::nil)::getText i+1;;
125
("action"::"in"::nil)::
("event"::"yes"::nil)::
("event"::"no"::nil)::
getText 0;;
fun IniEditor(s)=
let startEditor
_channel nil nil nil 315 230 WN_NORMAL-WN_SIZEBOX EDITOR_NORMAL
s nil nil nil
@load @save nil
-> ed in
(
set editWin = getEditWin ed;
_CRtext _channel editWin 20 5 290 20 ET_ALIGN_CENTER "Prompt";
createQuizz;
if s==nil then nil else openDMI ed
);
0;;
In this example, the server module sends a message to the client module containing the text of the question as well
as a question identifier:
_DMSsend this cli Cquizz [txt i];
The message is created from the Cquizz communication constructor, defined by:
defcom Cquizz=quizz S I;;
When the client module receives it, it executes the __quiz function. This opens a dialog box with the question’s
text. When the user replies, the res function is called and transmits the following reply to the server:
_DMSsend this Canswer [i r];;
The server subsequently executes the __answer function, in which the CLIENT-type variable DMSsender
contains the client that sent the message.
The C3d module is a very important one: it is capable of managing a 3D space containing animated avatars and
objects; it is therefore the most visible module.
It goes without saying that this module manages a 3D scene, but it also offers a system of plug-ins which allows the
developer to easily interface new functionalities in the 3D space. This mechanism is based on the system of Users
and UserInstances described previously:
- Each of the site’s functionalities will be considered as a User:
- for an object that is turning, you need to imagine that there is a virtual User in the scene whose only role is
to make the object turn. This User’s parameters are defined by:
- the object to be turned
- the values of this rotation (axis, speed, etc.)
- There is therefore one client User per avatar, and one virtual User per functionality
- So that it can use each of these Users, the C3d3 module defines one UserInstance per User. A UserInstance is
defined by:
- a User
- a name
- a class
- various parameters
- visibility
You will use the class to define the functionality: Avatar, rotation, etc.
The C3d3 module therefore manages a list of UserInstances of different classes. For each class there is a different
type of process; a developer must be able to add a new class easily, with a new process. The concept of the C3d3
plug-in is introduced for this purpose: a C3d3 plug-in is a small program (with a server and/or client part) that
manages the operation of a class.
126
Below we shall define the Ob structure, which is a superclass of UserInstances, and explain how to develop a
plug-in.
1. Ob structure
The basic structure of the C3d3 module is the Ob structure. It represents an "object" in the sense of object
programming: in other words an instance of a particular class.
The Ob structure can be used to describe:
- avatars
- various functionalities
The Ob structure is actually a superclass of the UserI structure, and therefore benefits from the mechanism of
Users. Typically, avatar Obs will be client User UserInstances, while functionality Obs will be virtual User
UserInstances.
a. on the server
- the UserInstance (and therefore the class, the parameters, and callbacks for communication with the UserClass
module and with the client UserInstances)
- the name
- a destruction callback
- the object’s current position (x,y,z)(a,b,c), where this is appropriate
UserI ObUi(Ob)
Returns the UserInstance associated with an object.
I ObMobile(ob Ob)
Returns the object’s mobility flag.
[I I I] ObPos(ob Ob)
Returns the object’s known position.
[I I I] ObAng(ob Ob)
Returns the object’s known orientation.
S ObName(ob Ob)
127
Returns the name of the object.
I ObRemoveInstance id I
Destroys an instance according to the User’s ID number.
It can be useful if a plug-in (server side), having received a given action, decides to “ enter ” a User in the 3D space
in a given position (defined by a name in the C3d3 module editor). Two scenarios are possible:
- the User is already in the 3D cell: you just need to move the user to his new position
- the User is not already in the 3d cell: you need to bring him there
A new function is defined for this:
I ObPlaceAvatar user User position S
You pass the User as a parameter as well as the name of the position.
The return value is not important.
b. on the client
- the UserInstance (and therefore the class, the parameters, callbacks for communication with the module
UserClass and the server UserInstance)
- the name
- a mobility flag: does the object’s position need to be refreshed and synchronized?
- an avatar flag: does the object appear in the list of avatars present in the scene?
- an anchor
- various callbacks
- a main 3D object, optional
S ObName(ob Ob)
Returns the name of the object.
I ObAvatar(ob Ob)
Returns the object’s avatar flag.
I ObMobile(ob Ob)
Returns the object’s mobility flag.
128
[Anchor r1] ObAnchor(ob Ob)
Returns the anchor associated with an object.
I ObSelect0(id I)
I ObSelect1(id I)
I ObSelect2(id)
I ObSelect3(id I)
These functions trigger a 'selectn' client event, with the ID number as a parameter (itoa format)
I ObHear string S
Outputs a message through the "hear" event.
I ObSetCam ob Ob
Defines the object to which the camera is linked: this function links the camera to the main 3D object.
Surface ObBuffer
Returns the rendering buffer.
I ObSetBackground col I
Defines the rendering's 24-bit background color (nil: none).
The following functions are used to define callbacks: you must not modify the Ob structure yourself.
fun ObCbGetName(o,f) : fun[Ob] S
function returning the name of the object
fun ObCbGetVal(o,f) : fun[Ob S] S
function returning a particular value
fun ObCbSetpos(o,f) : fun[Ob [I I I][I I I]] I
function positioning the object in a particular position
fun ObCbAnim(o,f) : fun[Ob] I
function called before each rendering
fun ObCbSend(o,f) : fun[Ob S S S]
function called when a message is received
fun ObCbClick(o,f) : fun[Ob H3d HMat3d I] I
function called when the user clicks on the main object or one of its descendants (handler, material and button)
fun ObCbDclick(o,f) : fun[Ob H3d HMat3d I] I
function called when the user double clicks on the main object or one of its descendants (handler, material and
button)
fun ObCbMove(o,f) : fun[Ob H3d HMat3d] I
function called when the user passes the mouse on the main object or one of its descendants (handler, material)
fun ObCbDraw(o,f) : fun[Ob ObjSurface I I I] I
function tracing the object in 2D on a bitmap, on a given position and size
fun ObCbControl(o,f) : fun[Ob [[I I I] [I I I]]] I
function requesting the moving of the object by passing the 2 speed vectors
fun ObCbControlClick(o,f) : fun[Ob [H3d HMat3d I]] I
function called each time the user clicks in the 3D
fun ObCbControlMove(o,f) : fun[Ob [Ob H3d HMat3d]] I
function called each time the user passes the mouse on a main 3D object. The callback returns two Ob objects: the
object that defined the callback, then the object indicated by the mouse.
129
fun ObCbControlKeyDown(o,f) : fun[Ob [I I]] I
function called each time the user presses a key in the 3D
fun ObCbControlKeyUp(o,f) : fun[Ob I] I
function called each time the user releases a key in the 3D
fun ObCbSpeak(o,f) : fun[Ob S] I
function called when the user says something
fun ObCbPostRender(o,f) : fun[Ob [ObjBitmap [I I]]] I
function called after each rendering. The bitmap’s value is ObBuffer()
fun ObCbReceiveLocal(o,f) : fun[Ob Ob S S S] I
function called when there is local communication between instances (ObSendLocal function)
the callback’s parameters are: from, to, action, param, rep
fun ObCbDestroy(o,f) : fun[Ob] I
function called before the destruction of the object
You can define clickable objects (i.e., parts of the 3D scene on which the mouse’s cursor will be changed and with
which move, click double-click callbacks are associated):
I ObSetLinks [ob Ob liste_liens [[H3d Hmat3d S ObjCursor fun [Ob H3d Hmat3d I]
I fun [Ob H3d Hmat3d I] I fun [Ob H3d Hmat3d] I] r1]
Each link is a tuple containing:
- the link’s 3d handler
- possibly the link’s material handler (if nil, the whole object is a link, independently of the material)
- the link’s apparent name
- the mouse cursor to be used (two constants: HandCursor (a hand) and StdCursor (the simple arrow) can
be used)
- click callback (arguments: instance, 3d handler, material handler, buttons status)
- double-click callback (arguments: instance, 3d handler, material handler, buttons status)
- move callback (arguments: instance, 3d handler, material handler)
fun ObGetLinks ob Ob
returns the previous list
130
There are some global variables:
session : S3d
3d session
shell : H3d
the scene’s main node
cam : H3d
camera
name3d : S
name of the cell
When an object is created on the client, there are two possible scenarios:
The setPosStd position definition callback is automatically defined. It assumes that the avatar has the following
structure:
- a shell node representing the avatar’s position (usually located on a level with the camera)
- a child 3D object oscillating around this position
In addition, if the avatar’s class is not present, the 'default' class is used: the aim is to make the avatar appear as
early as possible in the scene, even if it is not in its definitive form.
This default avatar (panel with Scol logo floating in the air) defines the following callbacks:
- animation callback CbAnim
- destruction callback CbDestroy
When the class is present, the default avatar will be destroyed and replaced by the normal avatar.
As a consequence, you can overload the default avatar by adding a plug-in.
2. Anchors
When developing 3D functionalities, you will quickly notice that there are two types of function:
- Those that are linked specifically to an object, and that will use the 'main object ' field, such as avatars for
example.
131
- Those that require more elements: several 3D objects/materials/positions, such as, for example, a module
making several 3D objects follow several trajectories synchronously.
The second type does away with the concept of a main object, which is replaced by that of an anchor. An anchor is
an (ordered) list of objects, materials and positions. It is basically a list of Anchor-type elements.
typedef Anchor=
objAnchor [H3d HMat3d S I]
| posAnchor [S [I I I] [I I I]];;
This list is made up of two types of element:
- objAnchor: a tuple (3D object, material, name, visibility flag)
- posAnchor: a tuple (name of the position, vector, angles)
Thus the anchor is literally the point at which functionality is attached to the 3D scene. For example, a rotation
module needs a set of objects to rotate, a movement module needs objects and trajectories, a blinking module
needs a list of materials, etc. Some functionalities do not need an anchor: for example, a module displaying a
superimposed logo in a corner of the 3D image.
The "anchor" parameter of an instance contains the name of the anchor associated with the instance.
This can be the name of an anchor defined in the module’s editor, or a direct definition such as: strbuild
("#"::nom_H3d::nom_HMat3d::nil)::nil
In this latter case, the anchor is a list of a single element.
3. Plug-ins
1. General points
The Ob structure represents an object, in other words the instance of a particular class. The role of plug-ins is to
describe classes. There will be precisely one class defined for each plug-in. A plug-in that does not define a class is
of no interest.
The plug-in is described by a *.plug file, very similar to the *.dmc format. The same fields can be found:
- name: name of the plug-in
- help: help text file
- serverNeeded: files required by the server plug-in
- serverLoad: list of files to be successively complied to start the server
- clientNeeded: files required by the client plug-in
- clientLoad: list of files to be successively complied to start the client
- editorNeeded: files required by the editor plug-in
- editorLoad: list of files to be successively complied to start the editor
- version version_number subversion_number
Unlike dmc files, here the server* lines are optional, as are the client* lines. But a plug-in with neither a server*
line, nor a client* line would be of no interest.
2. Internal plug-in
The C3d editor determines the plug-ins required by the instances defined in the editor. When the C3d module is
started, the plug-ins required are loaded. N.B.: in order to be recognized by the C3d editor, the directory containing
the *.plug file must be in the Dms/3d/Plugins directory.
Once the plug-in has been loaded, the IniPlug function is started (the equivalent of the IniDmi function for dmi
modules), with the name of the *.plug file as an argument: this file is immediately usable, since its downloading is
a prerequisite to the starting of the plug-in.
It has access to the global variable 'thisplug', which is a Plug-type pointer that points to itself (in the same way that
a module has access to the variable 'this', which is a DMI-type pointer that points to itself).
Plugin information flags: a plug-in may, on the client side, give some information about itself. This generally
occurs, once and for all, with the IniPlug. These flags are made up of the following masks:
PLUGIN_ONLINE_EDITING the plug-in is intended to be edited online
PLUGIN_WHOLE_OBJECT the plug-in uses an anchor containing a 3D object, with no specified material
fun [] S fun PLUGstartEditor plugin Plug window ObjWin 3dhandler H3d material
HMat3d parameters S
Starts the editor associated with a plug-in with initial parameters.
In the editor, the IniPlug file is also called, with the name of the *.plug file as a parameter. The plug-in then
typically calls the following function:
I PlugRegister class S save fun [ [Inst r1] ] [[S r1] [S r1] [[S r1]r1] [[S r1]r1]]
close fun[] I openedit fun[ObjWin S] I closeedit fun[] S
This save function is called just before the file is saved. On input, it recovers the list of instances defined in the
editor, whose class corresponds. This function is not called if this list is empty.
The Inst structure is defined in the following way:
struct Inst=[nameInst:S,classInst:S,anchorInst:S,paramInst:S]mkInst;;
The save function must return a tuple of two lists of words, and two lists of word lists, which makes a tuple of four
elements:
- the first element is a list of files to be added to the 'registerF' line in the dmi block
- the second element is a list of files to be added to the 'register' line in the dmi block
- the third element is a list of lines to be added to the end of the dat block (strextr format)
- the fourth element is a list of lines to be added to the end of the dmi block (strextr format)
N.B.: the *.plug and clientNeeded files are automatically saved as downloadable files: there is no point in returning
them in the save function.
Generally, you will just need to add the line 'plugin file_*.plug' to the dat block.
You will be able to add dmi new elements, new actions and new zones to the dmi file.
133
If the save function is not defined (nil in the PlugRegister function) a standard save function will be called, which
returns the following tuple:
[
nil /* registerF */
nil /* register */
("plugin"::plugin_file::nil)::nil /* supplemental Dat */
nil /* supplemental Dmi */
]
Most of the time this suffices.
4. Examples
In this example, the “long” version of the editor is given, a version equivalent to if there was no
definition of the ‘save’ function.
file Dms/3d/Plugins/Rot/[Link]
name Rotate
help Dms/3d/Plugins/Rot/[Link]
clientNeeded ./[Link]
clientLoad ./[Link]
editorNeeded ./[Link]
editorLoad ./[Link]
version 2 0
file Dms/3d/Plugins/Rot/[Link]
typeof class=S;;
fun rotobj2(x,v)=
match x with
(objAnchor [h _ _ _] -> M3rotateObj session h v)
|(_->nil);;
fun newOb(o)=
let hd UgetParam ObUi o "angular" -> s in
let nth_char s 0 -> a in
let if (a>=48 && a<58)||a=='- then ['y 109*atoi s]
else [a 109*atoi substr s 1 1000] ->[v i] in
let if v=='x then [0 i 0]
else if v=='z then [0 0 i]
else [i 0 0] -> v in
ObCbAnim o mkfun2 @rotobj v;
0;;
fun IniPlug(file)=
set class=getInfo strextr _getpack _checkpack file "name";
PlugRegister class @newOb nil;
0;;
134
file Dms/3d/Plugins/Rot/[Link]
typeof plugin=S;;
proto save=fun [ [Inst r1] ] [[S r1] [S r1] [[S r1]r1] [[S r1]r1]];;
fun save(l)=
[
nil /* registerF */
nil /* register */
("plugin"::plugin::nil)::nil /* supplemental Dat */
nil /* supplemental Dmi */
];;
fun IniPlug(file)=
set plugin=file;
PlugRegister (getInfo strextr _getpack _checkpack file "name")
class nil nil nil nil;;
The test module demonstrates the server plug-in and the possibilities for communication between
server object and client object. The principle is the following: by clicking on an object (first
element of the instance’s anchor), the user randomly changes the object’s flat color. This change is
global: it applies to everyone. It is also persistent: the server permanently keeps the current color,
and transmits it to new clients.
The message system is the following:
- the server transmits the color with the 'setFlat' message
- the client requests the current color with the 'color?' message
- the client indicates that it is clicking on the object with the 'click' message
The communication functions used are those of UserInstances, used as superclasses of the Ob
structure.
file Dms/3d/Plugins/Test/[Link]
name Test
help Dms/3d/Plugins/Test/[Link]
serverNeeded ./[Link]
serverLoad ./[Link]
clientNeeded ./[Link]
clientLoad ./[Link]
editorNeeded ./[Link]
editorLoad ./[Link]
version 2 0
file Dms/3d/Plugins/Test/[Link]
/* Rotate Plugin - DMS - March 99 - by Sylvain HUET */
typeof class=S;;
135
fun cbcomm(ui,cli,action,param,z)=
let z->[o col] in
if !strcmp action "click" then
(set col=(rand&255)+((rand&255)<<8)+((rand&255)<<16);
mutate z<-[_ col];
UsendCli this nil ui "setFlat" itoa col)
else if !strcmp action "color?" then
UsendCli this cli ui "setFlat" itoa col
else nil;;
fun newOb(o)=
UcbComm this ObUi o mkfun5 @cbcomm [o 1];
0;;
fun IniPlug(file)=
set class=getInfo strextr _getpack _checkpack file "name";
PlugRegister class @newOb nil;
0;;
file Dms/3d/Plugins/Test/[Link]
/* Rotate Plugin - DMS - March 99 - by Sylvain HUET */
typeof class=S;;
fun appFlat(x,col)=
match x with
(objAnchor [_ m _ _] -> M3setMaterialFlat session m col)
|(_->nil);;
fun applyFlat(o,col)=
apply_on_list ObAnchor o @appFlat col;
0;;
fun cbcomm(ui,action,param,o)=
if !strcmp action "setFlat" then
applyFlat o atoi param
else nil;;
fun newOb(o)=
UcbComm this ObUi o mkfun4 @cbcomm o;
match hd ObAnchor o with
(objAnchor [h _ _ _] -> ObSetMain o h)
|(_->nil);
ObCbClick o @cbclick;
UsendSrv this ObUi o "color?" nil;
0;;
fun IniPlug(file)=
set class=getInfo strextr _getpack _checkpack file "name";
PlugRegister class @newOb nil;
0;;
file Dms/3d/Plugins/Test/[Link]
/* [Link] : editeur du plugin */
fun IniPlug(file)=
PlugRegister (getInfo strextr _getpack _checkpack file "name")
class nil nil nil nil;;
136
_masterchannel ................................................ 85 standard client ......................................... 49, 85, 86
3D2, 3, 56, 57, 58, 59, 61, 62, 63, 68, 69, 92, 94, 95, standard server ..............................................85, 86
96, 97, 98, 122, 127, 128 startup................................................................ 97
3D objects ......................................................... 56 start-up ............. 9, 14, 41, 47, 48, 82, 83, 84, 85, 98
ActiveX ................................................ 3, 101, 110 structures ............................................ 26, 102, 109
BigNum ........................................................ 71, 72 syntax ............. 3, 8, 9, 16, 18, 38, 39, 41, 44, 60, 83
C3d .................................................................. 122 tables ................................................ 18, 26, 31, 34
callback .... 12, 13, 53, 103, 107, 111, 112, 117, 118 TCP/IP................................. 38, 39, 40, 44, 82, 101
cameras .................................................. 56, 59, 60 timers............................................................52, 55
channel14, 16, 36, 38, 39, 40, 41, 42, 43, 44, 50, 52, tuples .......................................... 17, 18, 23, 25, 29
54, 55, 82, 83, 85, 90, 91, 97, 98 type constructors ................................................ 27
collision ..........................56, 58, 59, 68, 69, 70, 127 types9, 10, 16, 17, 18, 27, 29, 38, 42, 48, 53, 58, 60,
communication constructor ...........18, 20, 43, 122 63, 68, 74, 93, 94, 96, 97, 127, 128
condition ...................... 21, 26, 72, 93, 94, 100, 101 UDP ....................................................... 38, 39, 44
console ......................... 9, 10, 15, 31, 36, 75, 82, 92 variable . 7, 12, 14, 16, 18, 20, 21, 23, 27, 29, 58, 59,
cookies ................................................... 48, 49, 50 63, 86, 94, 104, 118, 122
dmc .............. 97, 100, 115, 117, 118, 119, 120, 122 virtual machine ..................................... 7, 8, 10, 83
dmi ............................................ 100, 101, 107, 112
DMS................................ 92, 93, 97, 119, 120, 121
documents ............................... 93, 94, 96, 101, 107
editor . 8, 59, 93, 96, 97, 98, 100, 113, 114, 118, 120
environment . 3, 7, 8, 14, 16, 38, 39, 40, 41, 42, 44,
83, 85
events ........... 42, 52, 53, 68, 94, 100, 103, 110, 118
files 3, 7, 8, 9, 29, 38, 41, 42, 47, 48, 49, 50, 52, 55,
56, 57, 59, 60, 61, 63, 71, 82, 84, 85, 86, 96, 97,
98, 100, 107, 113, 117
Hello World.................. 9, 10, 11, 13, 16, 38, 52, 53
inference of type .......................................... 10, 16
M3D ............................................ 59, 61, 62, 63, 64
material .............. 57, 58, 60, 61, 63, 66, 67, 68, 128
memory 7, 32, 44, 57, 58, 63, 64, 82, 83, 84, 96, 97,
98, 100, 107
modules .... 56, 92, 94, 95, 96, 97, 98, 100, 101, 102,
103, 110
multimedia ................................................... 80, 92
operating rights .................................................. 83
parentheses ............................................. 10, 15, 45
partition ...........................................7, 9, 47, 48, 97
plug-in ........................................................ 74, 110
polymorphic ...................................... 3, 16, 25, 29
polymorphism......................................... 16, 17, 18
proprietary channel ............................................ 52
quicksort............................................................ 24
recursion.................................... 16, 17, 18, 24, 101
redefinition ........................................................ 29
reflex ..................................................... 53, 54, 55
Scene ............................................................ 56, 58
script9, 38, 39, 40, 41, 42, 44, 45, 48, 82, 83, 84, 85,
86, 88, 90, 92, 97, 98
scs .................................................................... 101
server . 16, 39, 40, 41, 42, 44, 48, 49, 82, 85, 86, 92,
93, 94, 95, 96, 97, 98, 100, 101, 102, 103, 109,
110, 115, 117, 118, 120, 122
session ....... 57, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70
side effects.................................................... 15, 18
signature ................................ 33, 48, 49, 50, 96, 97
signing............................................................... 31
SQL........................................................ 74, 75, 76
137
138