
Notes
-----

These notes are of a technical nature, and are for several
purposes:

        - to remind me how I've done things
        - to help anyone else whose interested in how Isis works
          or is trying to decipher the source code
        - to assist anyone who wants to add functions or
          exporting/importing code to Isis

Zero-terminated strings
-----------------------

Where I say a string is zero-terminated or null-terminated,
read it as meaning that the string *should* be null-terminated
but _may_ be terminated with another control character instead.

All strings are guaranteed to be ctrl-terminated (yes, really)
but that 'ctrl' may not actually by zero... it _usually_ will,
but not always. So just don't assume it is.

The above is only really important if you're going to try and
write function, export or import code for Isis.

Maximum sheet size
------------------

The largest possible sheet size is

               18953 by  2147483647
              &04A09 by &007FFFFFFF

The smaller x size is due to the maximum number being
constrained to three characters (ZZZ) in 'standard' mode. This
can easily (er, maybe) be expanded if required. Using four
characters would add approximately 492778 to the range.

The y size is constrained only by the 32-bit word size.
Theoretically, unsigned numbers would allow a range up to
&FFFFFFFF but I like to use negative numbers to denote special
conditions and errors. However, if anybody ever has enough
memory to create >&7FFFFFFF cells, I can use the processor flags
or another register instead. It would mean changing all the lts
to ccs and so on, though...

Attempts to expand beyond these limits are not checked so will
lead to miscellaneous undefined and probably nasty behaviour.

The labels plotting would probably get screwed up when the
number is beyond 7 or so characters.

Exporter file format
--------------------

The format of an exporter file is as follows:

Position   Length  Description
-----------------------------------------------------
00         04      Identification tag: 'CnvE'
04         04      Type of exporter (1)
08         04      File type supported
12         16      Name of exporter, padded with
                   zero bytes
28         08      Version number of exporter, again
                   padded with null bytes
36         ??      Actual exporter code (relocatable)

The following only applies to TYPE 1 exporters. Other types
(set at offset 04 in the file) are currently undefined but
will probably be used for more complex things...

The export code is called with the following defined:

       r10 = sheet anchor
       r11 = file handle
       r12 = description block
       r13 = full descending stack
       r14 = return address

All other register contents are undefined. No registers need to
be preserved.

Note than ldr rN,[r10] must be performed to find the actual
sheet address. DO NOT MESS ABOUT WITH THE ACTUAL SHEET DATA
UNLESS YOU REALLY KNOW WHAT YOU ARE DOING BECAUSE THE PROGRAM
WILL NOT LIKE IT VERY MUCH: TREAT IT AS READ ONLY.

You can do whatever the hell you like with the file specified
in r11 except DON'T CLOSE IT and you don't need to set its file
type.

On entry to the code there IS an error handler defined but to
generate an error cleanly, set the V flag and exit. Isis will
then take care of closing and deleting the file.

The block at r12 contains:

Offset   Contents
------------------------------------------
00       Minimum x position
04       Minimum y position
08       Maximum x position
12       Maximum y position
16       Selection flag (0 is whole sheet)
20       Address of locate cell code
24       Address of convert cell code

The locate and convert cell code are both called with the cell x
is r0 and the cell y in r1. The locate cell code returns the
address of the cell block (described in the main file format
document) in r0 and the convert cell routine returns a pointer
to the cell contents in string format in r0. Both require that
r10 remains unaltered from entry to the export code.

Importer file format
--------------------

Importer files are similar to exporter but slightly more complex
and come in three formats: type 1 (paste), type 2 (load), and
type 3 (paste & load).

An exporter file of any type is made like so:

Position   Length  Description
-----------------------------------------------------
00         04      Identification tag: 'CnvI'
04         04      Type of exporter (1/2/3)
08         04      File type supported
12         16      Name of exporter, padded with
                   zero bytes
28         08      Version number of exporter, again
                   padded with null bytes
36         ??      Actual exporter code (relocatable)

The three formats are interpreted as follows:

    1 (paste)         Offered when the user drags a file 
                      to the main sheet window for inclusion
                      in the current sheet as if pasted at the
                      cursor with the paste function.

    2 (load)          Offered when the user drags a file to
                      the iconbar for loading to replace the
                      current sheet.
                      
    3 (paste & load)  Offered under either of the above 
                      circumstances.

Types 1 and 2 are never offered to the user except when a
file is dragged to the window or iconbar respectively. Type 3s
are always offered.

In a similar manner to the exporter file format, the following
are passed to the importer code:

       r10 = sheet anchor
       r11 = file handle
       r12 = description block
       r13 = full descending stack
       r14 = return address

Again, V should be set and an error block returned in order to
report an error.

The block passed in r12 is set up with the following:

Offset   Contents
------------------------------------------
00       Cursor x position
04       Cursor y position
08       Address of locate cell code
12       Address of write cell code
16       Flag (types 2 and 3 only): 0 to read size
                                    1 to write data

The locate cell code is the same but the write cell code takes
parameters:

       r0  = cell x position
       r1  = cell y position
       r2  = string to write

The routine will automatically determine if the string at r2
holds a string or number, put it in the correct cell, and
set the cell's type appropriately. Attempts to write to cells
beyond the sheet limits are ignored.

In types 2 and 3 importers the code will be called twice,
firstly with zero at r12+16. When this happens, the expected
size of the sheet should be returned to Isis in r0 (width) and
r1 (height). Offsets 00 to 12 in the block at r12 are unset
for this phase.

The second time, the code is called with one at r12+16. The
data should then be written to the sheet starting at [0,0].
The positions at r12+00 and r12+04 will be zero to allow the
same code to be used in type 3 importers for both type 1 and
type 2 situations.

Type 1 importers are only called once with the position at
which to start writing in r12+00 and r12+04. The value in
r12+16 is unimportant (it is one, to assist with the writing
of type 3 importers).

In general, type 3 importers are most preferable for general
file types such as CSV and TSV but type 2 is better for stand-
alone spreadsheet formats such as Schema 2.

Spell checker dictionary format
-------------------------------

Basically, a dictionary is stored as a binary tree. Each word
contains a three-byte left pointer, a three-byte right pointer
and the word in packed (5, I think, bits) format. On disc, the
file is squashed. If you're really _that_ interested, contact
me for a copy of the Zeus libraries which contain the main
spelling (and a lot of other) code.

This method is quick but generates *huge* dictionary files.
If anyone has any ideas as to more compact methods, *please*
contact me.

The formula compiler & processor
--------------------------------

Formula symbols are similar to C/C++/Java with three notable
differences:

        - Arithmetic if works in a slightly different manner.

                expr1 ? expr2 : expr3

          *All* the expressions are evaluated and one chosen
          rather than only the true or false expression being
          evaluated.

          Note that nested arithmetic ifs *must* be placed
          in brackets: {a}=={b} ? ({c}=={d} ? {e} : {f}) : {g}
        - The comma operator is not available.

I am not a very good C++ programmer so there may be other
differences I don't know about... :-)

Constants must be enclosed in {}s and cell references in []s.

Two special symbols are available: 'X' is the cell column,
'Y' the cell row. These are case-sensitive.

All logical operators work on either true (1) or false (0).
Any value is converted to one of these before any logical
operators are applied. For these purposes, a value is false if
it equals zero and true if it doesn't.

The precedences for each operator are:

Pr Symbol    Description
--------------------------------
15 Undefined Function
14 ~         BitwiseNot
14 !         LogicalNot
14 +         UnaryPlus
14 -         UnaryMinus
13 **        Power
12 *         Multiply
12 /         Divide
12 %         Modulus
11 +         BinaryPlus
11 -         BinaryMinus
10 <<        BitwiseShiftLeft
10 >>        BitwiseShiftRight
09 <         LessThan
09 <=        LessThanOrEqual
09 >         GreaterThan
09 >=        GreaterThanOrEqual
08 ==        Equality
08 !=        Inequality
07 &         BitwiseAnd
06 ^         BitwiseEor
05 |         BitwiseOr
04 &&        LogicalAnd
03 ||        LogicalOr
02 ?         ArithmeticIf
02 :         Colon
01 ,         Comma
00 ()        Brackets

Note that the INX & UFL FP flags are ignored in all
calculations.

Any or all of the above may be subject to sudden change until
we get to the release version...

Function file format
--------------------

Right... Function files are small data (&FFD) files which
contain a standard header and the code to perform some
operation on a number of elements in a formula and produce, at
present, one result.

The format of a function file is:

Position   Length   Description
-------------------------------------------------------------
000        04       Identification tag ('Func')
004        04       Function type (must be 1)
008        16       Name of function, padded with nulls
024        01       Function return type (1 string, 2 number)
025        01       Function parameter 1 type: 0 none
                                               1 string
                                               2 number
                                               3 range
026        01       Function parameter 2 type
027        01       Function parameter 3 type
028        01       Function parameter 4 type
029        01       Function parameter 5 type
030        01       Function parameter 6 type
031        01       Function parameter 7 type
032        96       Function help, padded with nulls
128        ??       Relocatable function code

The function help should be of a form similar to:

    duplicate(s,n): duplicates the given string n times.

Functions names should be lower case (and are forced so by Isis
if not) and should contain nothing but characters 'a' (&61) to
'z' (&7A) and '0' (&30) to '9' (&39) - if any other characters
are present, the function can never be used.

On entry to the function code, the following are set:

   r0 & f0 are undefined

   f1-f7   contain any numeric parameters passed to the function
           (f1 = parameter 1, f2 = parameter 2, and so on)

   r1-r7   contain any string or range parameters passed to the
           function (r1 = parameter 1, r2 = parameter 2, and so
           on)

   r8  *   if the return type is string, holds the anchor of
           the zero-initialised, 104 byte string result block
           in which the function should return its result

   r9      contains the address of the actual function in
           memory

   r10     holds the address of the formula stack - which
           should never be used but is included for possible
           later expansion of this format

   r11 *   256 bytes of workspace - no assumptions should be
           made as to content or position

   r12     formula block pointer - again, should never be used
           but is included for later expansion

   r13     points to a standard fd program stack

On exit, the registers can be changed thus:

   f0      if the return byte is number, holds the number
           result

If the return type is string, the heap block pointed to be !r8
should contain the resultant string. Note that r0-r7, r9-r12
and f1-f7 need not be preserved.

'*' signifies a heap block anchor. To access the actual memory
block, the simplest method is to perform:

       ldr r8,[r8]       or      ldr r11,[r11]

r8 or r11 now points to the actual block.

Ranges are passed to the functions in r1-r7, in a similar way
to a string. Each range is also stored in a heap block, the
first two words of which contain the width-1 and height-1 of
the block of cells.

These two words are followed by a list of the contents of each
cell, stored as followed:

Number:   4 bytes token = 2
         12 bytes fp number

String:   4 bytes token = 1
          1 byte  length, aligned to 4
          n bytes null-terminated string

To read the block, the sum() function uses the following code:

        ldr     r9,[r1]         ; get block

        ldr     r0,[r9],#4      ; find width
        ldr     r1,[r9],#4      ; find height
        
        add     r0,r0,#1        ; calc. total
        add     r1,r1,#1        ; no. of cells
        mul     r8,r0,r1        ; in block

.Loop
        ldr     r0,[r9],#4      ; load token

        teq     r0,#2           ; = number ?
        ldfeqe  f1,[r9],#12     ; load number
        ;*** process number in f1

        teq     r0,#1           ; = string ?
        ;*** process string at r9+1
        ldreqb  r0,[r9]         ; load length
        addeq   r9,r9,r0        ; increase ptr.

        subs    r8,r8,#1
        bpl     Loop

The above is the simplest method and assumes you don't want
the cells in any kind of row/column order. If you do, they
are stored in the block so for [0-3,0-3] you would get:

    [0,0], [0,1], [0,2], [0,3], [1,0], [1,1], [1,2] ...

If that doesn't work, it must be the other way round. :->

Return from the function is as standard from any subroutine.

So, basically, if the function 'duplicate("TEST",5)' is called,
the registers are set up:

              r1 = "TEST"
              f2 = 5

and r8-r13 as described.

*All* floating point operations should be performed with
extended precision. To convert from an FP value to integer,
use simply,

           fix r0,f0

to ensure consistency with rounding across functions.

All floating point exceptions are trapped and dealt with by
Isis.

To signify an error, function code should return with V set. No
registers have any significance. X forms of SWIs should be
used if possible - an error handler is available but to call
it during a function leads to data and heap corruption.

Type 1 format function files will always be compatible with
Isis and as I have written 30+ functions already, it looks as
if the format is not set to really change.

Using TaskControl
-----------------

To use TaskControl with Isis, use:

   SYS "TaskControl_Find","Isis" TO handle%
   IF handle%<>0 SYS "TaskControl_Send",handle%,code%,value%

Note that r0 of TaskControl_Find is case-sensitive.

Code block &040 - &07F is allocated for Isis.

Those currently available, including the core messages, are:

Code  Description
-----------------------------------
&000  m_CORE_NULL
&001  m_CORE_CLAIM
&002  m_CORE_RELEASE
&003  m_CORE_QUIT
&004  m_CORE_FORCEQUIT

&040  m_ISIS_DUMPSHEET
&041  m_ISIS_OPENWINDOW
                0 main sheet window
&042  m_ISIS_STARTSELECTION
                (x1<<16)+y1
&043  m_ISIS_ENDSELECTION
                (x2<<16)+y2

A bit limited in scope at the moment, but I will add more as
I need them or as I feel like it.

For more information on TaskControl, contact me.
