@database EasylifeSTRUCT.guide @author "Paul Hickman" @$VER: EasylifeSTRUCT.guide 1.10 (30.03.95) @width 77 @index Easylife.guide/CommandIndex @node main "Easylife Structured Variables" @toc Easylife.guide/main @prev main @next STRUCT intro @{u}@{b}Easylife Extension V1.10 - By Paul Hickman@{uu} Easylife Structured Variables System{ub} @{u}Structured Variables@{uu} @{"What Is A Structured Variable " link WhatIs} @{"Using Pointers " link pointers} @{"Defining Structured Variables " link DefContents} @{"The Compiler " link Compiler} @{"Easylife Commands & Functions " link StContents} @{"Examples & Tutorials " link Tutorials} @{"Usage Via Easylife.Library " link LibraryContents} @{"Storage Formats " link StorageContents} @{u}Structures Support Programs@{uu} @{"Variable Checker " link VarChecker.guide/main} @{"Program Optimser " link Optimse.guide/main} @endnode @node WhatIs "Structs / What is a structured variable?" @{b}@{u}What Is A Structured Variable?@{uu}@{ub} In brief, if you have programmed in modula 2 / pascal, a structured variable is a record. If you have programmed in C it is a struct. AMOS only has 3 types of variable, integers, reals, and strings. Without special encoding of the information each of these can only hold one item of data - I.E. It is atomic. You can of course use these to hold several items of data - An integer could be used as a series of bits, each an independent boolean variable. A string could be divided into columns e.g First 30 characters are the name, the rest the address. However all of these lead to problems, and hard to read programs. A Structured variable is a collection of 1 or more of AMOS's basic 3 variables. E.g. The structure PERSON could contain a string for the persons name, and integer for their age, and boolean integer to say if they are a kylie minogue fan. (This information should be passed to the local noise polution patrol). The structure would be defined in your program like this: 'PERSON : Structure ' NAME : String Length 20 ' AGE : Integer ' KYLIEFAN : Boolean 'end There are some differences between the three AMOS variables, and those which are used in structures: @{u}Integers@{uu} AMOS has one integer variable type which is 32 bits long, and will accept any value from -2147483648 to 2147483647. Now if your variable is only supposed to take values between 1 and 10, there are two problems: 1) AMOS will not report it as an error if you set the variable to 11, or -6 even though you only want it to be between 1 & 10. 2) AMOS will take 4 bytes of store it, even though only 1 is needed. As you can guess by my pointing them out, easylife structured variables solve both of these problems - you can specify an integer to be between 2 values, and the minimum number of bytes needed to store it will be used (1, 2 or 4). E.g. 'year : integer from 1900 to 2100 This variable only needs 1 byte of storage, as it can only accept 201 different values, so it will only take 1 byte. Also, an error will be produced if you try to set it to a value that is too low, or too high. Also, you can specify a integer variable as a boolean, in which case it will only take 1 bit! It will return 0 (False) or -1(True) to AMOS when you read it, and when you set it, any non-zero value means true. @{u}Reals@{uu} Reals are used in structures exactly the same as in AMOS, except you don't put a '#' on the variable names. @{u}Strings@{uu} The use of strings in structures is different to AMOS. Since the structured variable exists outside the AMOS variable buffer, it is not garbage collected. This means that the address of the string will not change, so you can use its address when a pointer to string is required (E.g. For MUI objects). However this also means that you must specify a maximum length for the string. When you create the structure, this much memory is always allocated to the string regardless of the actual length of the string you set it to. You may also include another structure as an element of the structure. E.g. The structure car could be: car : structure registration : string length 10 yearmade : integer from 1900 to 2100 driver : person end This means the car has the attributes registration, yearmade, drivername,driverage,driverkyliefan (!). NOTE: This creates a structure within a structure, not two structures where one contains a pointer to the other. AMOS also allows you to create Multi-Dimensional Arrays of variables, and not to be outdone, you can also create an array within a structure with these restrictions: - It has a maximum of 3 dimensions. - It has a maximum of 65536 elements in any 1 dimension. However you can create arrays of any type of element including booleans (Where each array element takes only 1 bit) and arrays of sub-structures! Arrays are not as importent in structured variables as they are in AMOS, as they still suffer from their main drawback: They have a fixed number of elements. Structured variables offer the alternative of using pointers. @{u}Structures vs Instances@{uu} What you have seen examples of above are structures. It important to firmly distinguish them from structure Instances. The structures are like new variable types, such as Integer or String. Instances of the structures are actual physical variables of that type of structure - the equivlent of A$. You may define as many instances of each type of structure as you need, as you need them. Memory is allocated dynamically - there is no fixed size variable buffer to worry about filling. This does however mean there is no garbage collection. I.E. After you have disposed of the structure instances, the addresses of other instances is not changed by moving them to fill the 'holes' in the memory left by the disposed structures. However these 'holes' will be filled by newly created structures. @endnode @node pointers "Structs / Using Pointers" @{b}@{u}Using Pointers@{uu}@{ub} Consider a directory listing, and how you store it in AMOS variables. You would propably store each filename in an element of a string array, followed by the file length, or possibly put the file length in an integer array of the same name, but you still have a problem - how long should the array be? Make it too small, and large directories will crash the program - make it too large and you waste a lot of memory for small directories. Even if you used structured variable arrays, you would still get the same problem. The solution is to create a structure of each single filename, which contains a pointer to the next in the list 'direntry : structure ' name : string length 32 'Maximum for AmigaDos files ' size : integer from 0 to maxint 'Maxint = largest integer. ' next : pointer to direntry 'end The directory: FredTheFile 21234 FredTheFile.info 1242 George 4322 Would be held in three direntry structures. The next element of the "FredTheFile" structure would be set to the address of the "FredTheFile.info" structure, and the next element of that structure would be set to the address of the "George" file. The address of the fred the file structure would then be used to refer to the whole directory. But what about subdirectories? All it takes is a few modifications and a complete directory tree can be stored. 'direntry : structure ' name : string length 32 ' size : integer from 0 to maxint ' isdir : boolean 'Set to True for subdirs ' subdir : pointer to direntry ' next : pointer to direntry 'end Now there are 2 pointers - One for the next entry in this directory, and one to point to the first entry of a subdirectory, if this direntry structure contains the name of a subdirectory. The boolean element is used to differentiate between the 2 types of directory entry. The pointers used in this example have all been 'Typed Pointers'. That is they are all defined as 'Pointer To '. Any values you try to assign to such a pointer will be checked to see if that address really does contain a structure of the correct type, and will produce an error if it does not. The exception is that you can assign 0 to any pointer. This is refered to as a null pointer, and is normally used to indicate that this pointer does not point anywhere. This however also means that each pointer can only point to one type of object. If you need to point to several types, you must use an untyped pointer - E.g. Here is an alternative way of implementing directory lists: 'dlistfile : structure ' name : string length 32 ' size : integer from 0 to maxint ' next : pointer 'end ' 'dlistdir : structure ' name : string length 32 ' subdir : pointer ' next : pointer 'end Here no type is given from the pointers, so they can point to any address. However you should still use them properly: - Only set them to the addresses of structures, or to 0. - Do not use integers instead of pointers - There is a difference which will become apparent. There is a big danger in using pointers if you are not carefull: Things can go dramatically wrong if your pointers point to an illegal address. This means do not set them to an address which is not a structured variables address, and when a structured variable is disposed of, ensure any pointers to it are set back to 0. @endnode @node DefContents "Structs / Defintions" @{u}@{b}Defining Structured Variables@{ub}@{uu} @{" Overview " link DefGeneral} Layout of definitions. @{" Integers " link DefInteger} Including Longs, Words, Bytes, Aptrs, Cardinals & Ranged. @{" Reals " link DefReal} Single Precision Only. @{" Strings " link DefString} Of A Fixed Maximum Length. @{" Booleans " link DefBoolean} @{" Arrays " link DefArray} @{" Macro Structures " link DefMacro} @{" Sub-Structures " link DefSub} @{" Constants " link DefConstant} @{" Enumerations " link DefEnum} @endnode @node DefGeneral "Structs / Definitions / General" @{b}@{u}Structure Definitions@{uu}@{ub} The structures used in a program are defined as part of the program inside comments. They should go at the start of the program, before everything except other comments, and AMOS commands which must be at the start of the program, such as Set Buffer & Set Accessory. The structures should be defined between the structures begin & structures end lines, as shown below. It is important that both of these lines are present, and that every line between them is a comment (Begining with '), and there are no completely blank lines. You must only have one structures defintion section per program. E.g. 'Structures Begin ' 'person : structure ' name : string length 20 ' age : integer 'end ' 'Structures End Is perfectly legal, as is (But don't do this): 'StRucTURES BEGin ' ' 'person : STRUCture 'name : string length 20 ' ' ' 'age : inTEGer 'end 'structures end But these are not legal, as neither the begin or end line is properly formed: 'Structures Begin ' 'person : structure ' name : string length 20 ' age : integer 'end 'Structures End 'fred And this is not correct, as it contains blank lines & non-comment lines: 'Structures Begin 'person : structure ' name : string length 20 Global X$() ' age : integer 'end 'Structures End Any line other than the begin & end line may contain a comment at the end, simply by using a second ' - e.g. 'person : structure 'This is a valid comment ''This whole line is a comment. Inside the structures defintions section, each individual structure definition begins: " : Structure" and ends with an "end" statement. The name can only contains Letters, numbers and underscores. Spaces are not allowed. You cannot nest definitions, but you may define structures in any order, and create a pointer to, insert, or include a structure before it is defined. NOTE: Each name can be a maximum of 24 characters long. Each element is defined as " : ". The name follows the same rules as for structure names. The type must be one of the following: @{" Integer " link DefInteger} @{" Boolean " link DefBoolean} @{" Real " link DefReal} @{" String " link DefString} @{" Array " link DefArray} @{" Pointer " link DefPointer} You may also specify the name of another structure as the type, to include a sub-structure, or an enumerated type, as well as a few special types of integer. NOTE: Names can be repeated in different structures, but you cannot give two elements of the same structure the same name, or give two structures the same name. It is also permissible to use the same name for an element and a structure, or for elements of different types in different structres. In fact I encourage you to repeat names where they are used for the same purpose - E.g. In any structure which is a linked list, call the pointer to the next element 'next'. @endnode @node DefInteger "Structs / Definitions / Integers" @{b}@{u}Integer Elements@{uu}@{ub} There are 2 ways to define an integer element: 1) ' : Integer 2) ' : Integer from to The first way defines a normal 32 integer, which accepts any value an AMOS integer accepts, and takes 32 bits to store. The second limits the range of accepted values. The minimum & maximum values use specify will be permitted e.g. ' fred : Integer from 4 to 7 Will create an integer that accepts vales 4,5,6 & 7 only. You can use the special values 'minint' for the minimum value and 'maxint' for the maximum value to represent the smallest & largest legal integer values e.g. For Negative numbers only ' neg : Integer from minint to -1 If you try to set a ranged integer to a value outside the range, and error will occur, telling if it was too big, or too small. I recommend that you use ranged integers whenever if is possible, as it allows you to detect what parts of your code are causing errors easier, and reduces the space requied. This is especially important if you create an array of integers. Additionally, the following shortcuts can be used to define common ranges of integer: 'val : long 'val : ulong 'val : aptr All 3 of these produce a normal unranged integer. 'val : cardinal A cardinal is the same as writing "integer from 0 to maxint". It is any non-negative integer 'val : uword An unsigned word is the same as writting "integer from 0 to 65535". 'val : word A signed word is the same as writting "integer from -32768 to 32767". 'val : ubyte 'val : char An unsigned byte, or character is the same as writting "integer from 0 to 255". 'val : byte A byte is the same as writting "integer from -128 to 127. @{u}See Also@{uu} @{" Constants " link DefConstants} @{" Enumerations " link DefEnums} @endnode @node DefBoolean "Structs / Definitions / Booleans" @{b}@{u}Boolean Elements@{uu}@{ub} A Boolean element is defined with: ' : Boolean The boolean uses only 1 bit of storage in the structure - if you define several booleans, or an array of booleans, they will share the same byte of memory. When you set the value of a boolean, it will accept any AMOS integer. 0 will set it to false, any other value to True. When you read back the value, it will return False (0), or True(-1). @endnode @node DefReal "Structs / Defintions / Reals" @{b}@{u}Real-Number Elements@{uu}@{ub} A Real Number element is defined with: ' : Real Currently only single precission real numbers are supported. (Anyone know how to read double precision integers as parameters to AMOSPro extensions?). @endnode @node DefString "Structs / Defintions / String" @{b}@{u}String Elements@{uu}@{ub} A String is defined with: ' : String Length You must specify a number from 1 to 65534 as the maximum allowable length of the string. This ammount of memory (+2 Bytes) is always allocated to store the string, regardless of how long the actual string in the particular structure instance is. The string is always stored in a null-terminated fashion, so its address may be passed to Amiga OS library funcions that expect a string, or directly to MUI objects, without using Tag Str$. @endnode @node DefArray "Structs / Defintions / Arrays" @{b}@{u}Array Definitions@{uu}@{ub} A one dimensional array is defined: ' : Array Of Where size is the number of array elements, and type is a definition of any other type of element (Except Array & Insert), which you want an array of. The array elements will have index numbers 0 to Size-1. Example: 'fred :Array 10 Of Boolean Will create an array of 10 booleans nummbered fred(0) to fred(9). 2 & 3 Dimensional arrays are defined as below: ' : Array By Of ' : Array By By Of The maximum size of the array in any one dimension is 65536. @endnode @node DefPointer "Structs / Defintions / Pointers" @{b}@{u}Pointer Elements@{uu}@{ub} Pointers are defined: ' : Pointer ' : Pointer To The first form creates an untyped pointer. No checking is performed on such a pointer - it is up to you to ensure it always points to a valid Easylife structured variable, or is null (0). The second form, which should be used whenever possible will cause an error to occur if you try to point to an address which is not the address of a instance of specified type of structure (Unless you set it zero). Pointers are the most powerfull feature of structured variables, but also the most dangerous. Here are some pitfalls to avoid: - Never use an Integer element for a pointer. Always specify it as a pointer. This is so Easylife's recursive commands & anyone who reads you code knows it is a pointer. - Never set a pointer to an invalid address. - When you dispose of an object with St Free, be careful that you don't leave an pointers to it from other objects. If you try to refer to an object after it is disposed of, anything could happen, as the memory will have been reused. This is one of the most common problems with using structured variables. @endnode @node DefInclude "Structs / Defintions / Macro Inclusion" @{b}@{u}Macro Structures@{uu}@{ub} Sometimes you will find that several structures share common elements. E.g. 'box : structure ' x1 : integer ' y1 : integer ' x2 : integer ' y2 : integer ' ink : integer from 0 to 31 'end ' 'button : structure ' x1 : integer ' y1 : integer ' x2 : integer ' y2 : integer ' text : string length 20 ' pressed : boolean 'end Time can be saved when writting the definitions by using macro structures and inclusion: 'coords : macro structure ' x1 : integer ' y1 : integer ' x2 : integer ' y2 : integer 'end ' 'box : structure ' include coords ' ink : integer from 0 to 31 'end ' 'button : structure ' include coords ' text : string length 20 ' pressed : boolean 'end Both of these fragments of defintions will produce exactly the same structures - Box & Button. Co-ords is defined as a macro structure. This tells the compiler not to create the co-ords structure in the compiled bank. Macro structures can only be included in other structures. You cannot use them as sub-structures, or create pointers to them, as then to not exist as seperate entities in the compiled definitions. The Include statement tells the compiler to insert all the elements of coords in the current structure, as if they were defined in the current structure. The fact that they came from the co-ords structure is not important, the element names of box will still be X1,Y1,X2,Y2,Ink - not Coords.X1, Coords.Y1, Coords.X2, Coords.Y2, Ink. NOTE: You do not have to include macro structures. Normal structures can also be included. The only difference is that they will also be created as seperate structures. NOTE: You must define the included structure BEFORE you include it. I.E. The included structure's defintion must be above the include statement in the definitons. @endnode @node DefSubStructs "Structs / Defintions / Sub-Structures" @{b}@{u}Sub-Structure Elements@{uu}@{ub} Instead of one of the basic types, you may specify the name of another element as the type of an element. This means that you create a sub-structure of the type specified. E.g. 'coords : structure ' x1 : integer ' y1 : integer ' x2 : integer ' y2 : integer 'end ' 'box : structure ' pos : coords ' ink : integer from 0 to 31 'end ' 'button : structure ' loc : coords ' text : string length 20 ' pressed : boolean 'end This is similar to the example given in the Macro Structures section, and provides a usefull comparison of the 2 features. Here the attributes of the button structure are just Pos & Ink. When reading & setting the pos sub-structures attribute's you use it like it is a pointer e.g. If BUT is a button: St Set St Get(BUT,ST_POS),ST_X1 To 5 Y2=St Get(St Get(BUT,ST_POS),Y2) The difference between the sub-structure and a pointer is that the sub-structure is allocated as part of the structures memory block. This means you cannot change its address - E.g. This is illegal St Set BUT,ST_POS To $232112 It also means you do not need to (And must not) use St New or St Free on the sub-structure. It is possible to create several sub-structures of the same type, but giving the elements different names. You can also create arrays of sub-structures. Also, you can use St Dup to duplicate a sub-structure which will return a copy of the sub-structure, as a normal structure, which can then be manipulated like any other structure. @endnode @node DefConstants "Structs / Defintions / Constants" @{b}@{u}Constants@{uu}@{ub} A Constant is an integer variable whose value never changes. You may define a constant in 2 ways: 'const = 'local const = Both of these may occur anywhere in the structure defintions, but for the sake of clarity I recommend you group them together at the top of the defintions, and always put them outside of the individual structure's definitions. Name is the name of the constant, and follows the same rules as names of structures. Each name may only be used for a constant once - e.g. 'const fred = 5 'const fred = 5 Is an error because you are defining a constant twice, even though it is the same value. The value may be a decimal, hex, binary number, or the name of another constant - e.g. 'const fred = 5 'const bloggs = fred Will set bloggs to 5. A constant may be used anywhere that a number is expected in your structure definitions that a number is expected e.g. Integer ranges, Array Or String sizes, etc. However it cannot be used above the line it is defined on. This is why I recommed you define the constants at the top of the structure defintions. If you specify the "local" keyboard this is the only place that constants can be used. However, if you do not specify "local", the compiler with create a global variable "__" and initialise to the constant, so you can also use the constants in your main program. E.g. 'const fred = 5 'const bloggs = 6 'local const may = 7 Will create 2 global variables, __FRED & __BLOGGS, initialising them to 5 & 6 respectively. "minint" and "maxint" are simply local constants defined by the compiler before your structure defintions are read, so you may refer to them when defining other constants. @{b}See Also@{ub} @{"Integers " link DefInteger} @{"Enumerations" link DefEnums} @endnode @node DefEnums "Structs / Definitions / Enumerated Types" @{b}@{u}Enumerations@{uu}@{ub} An enumerated type is a method of creating a varaible which can take one of a number of specified values e.g. Sex = Male, Female, or Hermaphrodite. You could assign values to these e.g. Male=0,Female=1,Hermaphrodie=2 then when comparing use If SEX=0 'Male Else If SEX=1 'Female Else If SEX=2 'Hermaphrodite End If This could be clarified further by setting constants for each of the values 0,1 and 2. An enumerated type does just this, but the constants are local to variables of type sex. E.g. Male could have the value 7 in a different type of values. Easylife does not provide true enumerations like this, but it does allow you to specify a set of constants as an enumeration: 'enum : , , ... Name is the name of the enumeration as a whole and the consts are the possible values the enumerated type can take e.g. 'enum sex : Male , Female , Hermaphrodite Each const is created as a normal constant with ascending values (I.e. Male=0 , Female=1 , Hermaphrodite=2). However it is possible to specify the values to use e.g. 'enum colours : red=1,brown=4,blue,pink, ' black,yellow=2,green Will create the constants red=1,yellow=2,green=3,brown=4,blue=5 pink=6,black=7 (I'm writting this just after thrashing some friends at snooker :-). This example also shows that you can carry an enumeration over more than one line by ending each continued line with a ','. The constants created in an enumeration are no different from normal constants, and can be used as such. Global variables are created to represent them in the AMOS program (Although the name of the enumeration as a whole cannot be used in the AMOS program, as it has no value attached). If you do not want your constants exported to the AMOS program as global variables, you may use the "local" keyword in front of "enum", as with const e.g. 'local enum suits : heart,club,diamond,spade Will not create any AMOS variables, but will set heart=0,club=1, diamond=2,spade=3 whilst the sturcture definitions are parsed. The name of an enumeration as a whole may be used to specify structure elements of the enumerated type e.g. (Using above enumeration) 'card : structure ' value : integer from 1 to 13 ' suit : suits 'end What this actually does is specify suits as a ranged integer from 0 to 3. The big advantage of using enumerations is that if you add an element to the enumeration, the structure elements ranges will automatically change. NOTE: The range of the element is from the smallest value in the enumeration to the largest. It is not a true enumerated type as the enumeration: 'enum test : cold=-10, warm=15, hot=30 will create a ranged integer from -10 to 30, which could be set to any value in between - including those which are not part of the enumeration. Enumerations are useful for collecting groups of connected constants together, even if they are not used for enumerated type elements. However you should bear these guideline in mind when using them: - The name of an enumeration must be unique with respect to the names of other enumerations, the names of structures, and compiler keywords. However it may share the name with constants (Including those in enumerations), and structure elements. - Even though the enumerated values are integers, they should always be refered to using the enumerated global variable e.g. St Set CARD1,ST_SUIT To __DIAMOND Not, st Set CARD1,ST_SUIT To 2 - The optimser program will be able to replace the __DIAMOND by 2, so this will not waste space in the execution of your final program (And it is slightly faster) - You should never perform arithmatic on an enumerated type, as conceptually, the integers are just unique identifiers, not numbers. - Remember the same constant name cannot appear in 2 enumerations, as that would be redefining a constant. That is why these are not "true" enumerated types. @endnode @node DefBlockSize "Structs / Defintions / Block Size" @{b}@{u}Memory Block Size@{uu}@{ub} When Easylife allocates memory for structures, does not allocate each structure from the system memory pool individually, as this would lead to a huge ammount of fragmentation. Instead it allocates a large block of memory (Similar to the variable buffer), then allocates structures from that. However, unlike the AMOS variable buffer, when the block is full, it allocates another block the same size, and keeps allocating more blocks when it needs more memory. You can set the size of these blocks from within your definitions by including a line: 'Block Size Where is the size in bytes. You can put this line anywhere, but I suggest immediately after the structues begin statement for clarity. if your block size is to small to contain the largest structure you define, its size will be increased. You will be warned of this. If you do not specify a blocksize, the default of 8192 bytes is used. @endnode @node Compiler "Structs / Compiler" @{b}@{u}The Structures Compiler@{uu}@{ub} The Structures Compiler is an accessory a program. To run it, load it as an accessory, select the AMOSPro editor window containing the program whose defintions you wish to compile, the run the accessory from the AMOS menu. You may also create a user menu opiton to run the compiler. When run, the structures begin line is searched for, from the top of your program. The compiler then tries to read each line, and interpret it as a structue defintion until it comes to the structures end line, or a structures constants line (see below). It then processes your definitions and creates a bank (No 12) which contains all the information about the type of each element & structure. Then, for each name you have used in your defintions, either as a structure name, or an element name, a Global variable is inserted into your program just before the structures end line, which is 'ST_' followed by the name of the element/structure. It is intialised to a value, which you should not change. These global variables should be used whenever you need to pass the name of a structure, or element to an easylife function. E.g. If your source is: 'Structures Begin ' 'list : structure ' value : integer ' next : pointer to list 'end ' 'Structures End The compiler might create something like (I made these values up): 'Structures Begin ' 'list : structure ' value : integer ' next : pointer to list 'end ' 'Structures Constants Global ST_LIST,ST_VALUE,ST_NEXT ST_LIST=20 : ST_VALUE=26 : ST_NEXT=32 'Structures End If you use constants, or enumerations, the compiler will also create global variables for this, with the prefix '__' instead of 'ST_'. The variable checker accessory can make special checks on the use of both these types of variable. If you change any of your defintions, you can recompile immediately - The compiler will update the existing bank, and replace the variables definition with a new set. However, you must not put any other lines of code between the Structures Begin & End lines, as the compiler may delete them on the next compilation, or mis-interpret them as defintions. Errors If an error is found in your definitions, the error message will be displayed and the cursor moved to the appropriate line. @endnode @node CompilerInstall "Structs / Compiler / Adding To User Menu" @{b}@{u}Installing The Compiler On The User Menu@{uu}@{ub} If you've installed the other accessory programs, you should know how to do this by now :-) - From the AMOSPro Editor user menu, select 'Add Item'. Enter 'Comp Structs' as the item name & Press OK. - Select the Comp Structs Item when prompted, then the structures compiler accessory program. No command line is needed, and the default option of Hide Program, Do not keep after run are OK, but you can keep it if you want (Usefull on floppy disk systems, but not really worth it from harddisk). Press OK. - If you want a hotkey, select the Comp Structs item again, and press your desired key combination. @endnode @node StContents "Structures / Commands" @{b}Structured Variables - Easylife Commands@{ub} @{u}Section 1: Basic Commands@{uu} @{"Creating Instances " link C_StNew} @{"Disposing Of Instances " link C_StFree} @{"Reading Element Values " link C_StGet} @{"Setting Element Values " link C_StSet} @{"Disposing Of All Instances" link C_StFreeAll} @{u}Section 2: Advanced Commands@{uu} @{"Duplicating Structures " link C_StDup} @{"Copying Structures " link C_StCopy} @{"Structures Information " link C_StType} @{"String Comparisons " link C_StCmp} @{u}Section 3: Structure I/O@{uu} @{"Saving A Single Structure " link C_StOutput} @{"Loading A Single Structure " link C_StInput} @{"Saving A Structure Graph " link C_StSave} @{"Loading A Structure Graph " link C_StSave} @{b}Notes@{ub} Whenever a structures command takes an element as input you should: - Always specify an element of the structure instance the command applies to. - Always specify the correct number of indexes for arrays. - Always specify index values in the legal range. @{b}Errors@{ub} These errors may occur from any command / function which takes a structure or element as a parameter: @{u}Bank Not Reserved@{uu} Bank 12 is not reserved. This bank must contain the compiled structure defintions. @{u}Element/Structure Not Recognised@{uu} When you pass an 'ST_...' global variable, you are actually passing the numeric offset of that names information in bank 12. This error occurs if the value you pass is not in bank 12, or is in the wrong part of the bank. It also occurs if you pass a legal name, but in the wrong circumstances e.g. You pass an element name where a structure is expected, or you pass an element name that is not an element of the particular structure instance the command refers to - E.g. "St Set T,ST_VALUE To 5" is an error if 'value' is not an element of the structure T, even if ST_VALUE is an element of some structure. @{u}Illegal Funcition Call@{uu} You specify the wrong number of array indexes for an element. @endnode @node C_StNew "Structs / Commands / Creating New Instances" @{b}Command Syntax@{ub} = St New ( @{i}STRUCTURE @{ui}) @{b}Description@{ub} This function allocates memory for a new instance of a structured variable, and returns a pointer to it. The parameter should be the name of the structure to allocate, using the Global Variables 'ST_...'. The returned value is the address of a new instance of that structure type, with all elements set to their initial values of: Strings: "" Real Numbers: 0.0 Booleans: False Ranged Integers: Lowest Legal Value Integers: 0 Pointers: Null Pointer (0) The address returned conceptual "becomes" the structure instance. When you want to pass this instance to another function it is this address that you should pass. @{b}Notes@{ub} - The structure is allocated from a private pool, and will automatically be deallocated by the EasyLife Default routine if it is not manually freed. - Not all integers have a default value of zero. Integers for which a range is specified are initialised to the minimum value, not to 0, as 0 may not be in the legal range. The other reason for this is internally, the ranged integer is stored by subtracting the minimum value from the actual value to store, and storing the result. Then adding the minimum value when getting the stored value. This means the memory bytes for the element are actually set to 0, as is the case for all other bytes of the structure. This leads to a very fast initialization. @{b}Errors@{ub} @{u}Out Of Memory@{uu} Erm.. What do you want me to say? Tough? Sorry? Wibble? Buy some more. @{b}See Also@{ub} = St Dup St Free St Free All @endnode @node C_StFree "Structs / Commands / Disposing Of Instances" @{b}Command Syntax@{ub} St Free INSTANCE @{b}Description@{ub} This command deallocates the memory of the given structured variable instance. After deallocation, you must not refer to the INSTANCE again, either via an AMOS variable which points to it, or a pointer element of another structure. @{b}Notes@{ub} - This command does not return any memory to the system - it simply frees it for use by other structured variable instances. - Once freed the memory may be used by another structure. If you do not ensure that there were no pointers to the freed structure before freeing it, it is possible that these pointers will point to the new structure. It also possible that the new structure does not being at the same address as the old, so the pointer points to the middle of a structure. All of these are error conditions, and are the most common source of error in structured variable programs. @{b}Errors@{ub} ... @endnode @node C_StGet "Structs / Commands / Reading Element Values" @{b}Command Syntax@{ub} =St Get( INSTANCE , ELEMENT ) =St Get( INSTANCE , ELEMENT , INDEX1 ) =St Get( INSTANCE , ELEMENT , INDEX1 , INDEX2 ) =St Get( INSTANCE , ELEMENT , INDEX1 , INDEX2 , INDEX3 ) =St Get$( INSTANCE , ELEMENT ) =St Get$( INSTANCE , ELEMENT , INDEX1 ) =St Get$( INSTANCE , ELEMENT , INDEX1 , INDEX2 ) =St Get$( INSTANCE , ELEMENT , INDEX1 , INDEX2 , INDEX3 ) @{b}Description@{ub} The St Get command returns the current value of an element of a particular structure instance: INSTANCE = The address of the instance to read from. ELEMENT = The ST_... Name of the element to read. If the element is an array, you should specify the appropriate number of indexes for that element. (This is not checked). The element is returned as an AMOS integer / real number (Depending on element type). For string elements, you can use the St Get$ function to return the element as an AMOS string, or St Get to return the address of the string within the structure, where it is stored null-terminated. This means it can be used for any system library calls that require a pointer to a string, or in MUI taglists. @{b}Notes@{ub} - St Get$ returns a copy of the string. - Currenlty Easylife does not check that you have supplied the correct number of array indexes for the element being accessed. The value of each index supplied is checked against the size of the array in that dimension. If you supply the wrong number of elements, AMOS may crash, as the A3 parameter stack is not returned to the correct position. If you don't know what that means, just assume it isn't very nice. @{b}Errors@{ub} @{u}Illegal Function Call@{uu} - You are setting a typed pointer to an illegal Address. - You are using St Get$ on an element that is not a string. @endnode @node C_StSet "Structs / Commands / Setting an elments value" @aka C_StSetStr @{b}Command Syntax@{ub} St Set INSTANCE , ELEMENT To VALUE St Set INSTANCE , ELEMENT , INDEX1 To VALUE St Set INSTANCE , ELEMENT , INDEX1 , INDEX2 To VALUE St Set INSTANCE , ELEMENT , INDEX1 , INDEX2 , INDEX 3 To VALUE St Set Str INSTANCE , ELEMENT To STRING$ St Set Str INSTANCE , ELEMENT , INDEX1 To STRING$ St Set Str INSTANCE , ELEMENT , INDEX1 , INDEX2 To STRING$ St Set Str INSTANCE , ELEMENT , INDEX1 , INDEX2 , INDEX3 To STRING$ @{b}Description@{ub} This is the opposite of the St Get function. It sets an element of a structured variable instance to a new value: INSTANCE = The Address of the sturctured variable to change. ELEMENT = The Element to change the value of. VALUE = The new value of the element. You must also specify the correct number of indexes for array elements, to select which elemennt of the array to change. St Set Str is used to change the strings of string elements. @{b}Notes@{ub} - To set the elements of a sub-structure, you should use St Get on the sub-structure name from the main structure to find the address of the sub-structure, then use St Set on the sub-structure to set the element e.g. St Set St Get(STRUCT,ST_SUB),ST_ELEMENT To 1 @{b}Errors@{ub} @{u}Value assigned is beyond lower limit of ranged integer@{uu} You are setting a ranged integer element to a value below the minimum specified in the definition. @{u}Value assigned is beyond upper limit of ranged integer@{uu} You are setting a ranged integer element to a value above the maximum specified in the definition. @{u}Value assigned points to wrong type of strucuture/no structure@{uu} You are setting a typed pointer to point to an address which is not the address of an instance of the type specified in the defintion. @{u}String assigned is longer than maximum length of this element@{uu} You are setting a string element to a string longer than the maximum length specfied in the defintion of the element. @{u}Substructure addresses cannot be changed@{uu} You are attempting to set the value of an element which is a sub- structure. You cannot change the actual sub-structure, only its elements. @endnode @node C_StFreeAll "Structs / Freeing All Elements" @{b}Command Syntax@{ub} St Free All @{b}Description@{ub} The St Free All command disposes of all structured variables, and returns the memory blocks allocated to them to the system memory pool for use by AMOSPro & other tasks. @{b}Notes@{ub} - This command is automatically called by the Easylife Default routine. @{b}Errors@{ub} None. @endnode @node C_StDup "Structs / Commands / Duplicating A Structure" @{b}Command Syntax@{ub} =St Dup( INSTANCE ) @{b}Description@{ub} This function creates a duplicate of a structure instance, by allocating a new structure of the same type, and copying all its elements to the new structure. The address of the new structure is returned. @{b}Notes@{ub} - S2=St Dup(S1) is equivilent to (But faster than): S2=St New(St Type(S1)) : St Copy S1 To S2 @endnode @node C_StCopy "Structs / Commands / Copying Structures" @{b}Command Syntax@{ub} St Copy INSTANCE1 To INSTANCE2 @{b}Description@{ub} This command copies the values of all elements from INSTANCE1 to INSTANCE2. @{b}Notes@{ub} - INSTANCE2 must already exist - this command will not allocate new structures. - INSTANCE1 & INSTANCE2 must be the same type of structure. @endnode @node C_StType "Structs / Command / Structures Information" @aka C_StLen @{b}Command Syntax@{ub} = St Type( INSTANCE ) = St Len( INSTANCE ) @{b}Description@{ub} St Type, the more usefull of these two functions returns the type of the specified structure instance. The value returned is the numeric representation of the structure name, and the type can be identified by comparing it to the 'ST_...' global variables for structure names. It is useful where you have untyped pointers, and want to check which type of structure the pointed to element is. St Len returns the number of bytes memory allocated to the structure. You have calculate it manually by adding up the lengths of all the elements, adding 4, and rounding up to the next multiple of 8. @{b}Notes@{ub} - The lengths of individual elements are: Integer : 4 Bytes. Integer with range interval < 65536 : 2 Bytes. Integer with range interval < 256 : 1 Byte. Pointer (Typed or Untyped) : 4 Bytes. Real Number : 4 Bytes. Boolean : 1 Bit. String : Max Len+3 rounded up to even. Sub-Structure : Length of Sub-Structure. Arrays take the length of an element * the number of elements. Different booleans & boolean arrays can share parts of a byte. @endnode @node C_StCmp "Structs / Commands / String Comparisons" @{b}Command Syntax@{ub} =St Cmp( INSTANCE , ELEMENT To STRING$) =St Cmp( INSTANCE , ELEMENT , INDEX1 To STRING$) =St Cmp( INSTANCE , ELEMENT , INDEX1 , INDEX2 To STRING$) =St Cmp( INSTANCE , ELEMENT , INDEX1 , INDEX2 , INDEX3 To STRING$) @{b}Description@{ub} This function compare a string to the contents of a string element, or a string array element. It returns: -1 if STRING$ is less than the element string. 0 if STRING$ is the same as the element string. 1 if STRING$ is greater than the element string. @{b}Notes@{ub} - The Less Than/Greater Than on strings works the same way as the AMOS < and > operators on AMOS strings. - The element must be string element - This is much faster than using: If St Get$( INSTACE, ELEMENT )= STRING$ As the St Get$ has to copy the string first, where as StCmp can compare it in place. - StrCmp is particularly useful for searching ordered lists, or trees indexed on a string element. @{b}Errors@{ub} @{u}Illegal Function Call@{uu} The element is not a string element. @endnode @node C_StOutput "Structs / Commands / Saving A Single Structure" @{b}Command Syntax@{ub} =St Output$( INSTANCE ) @{b}Description@{ub} This command returns a copy of the structure instance in a string, so that you have save it with the Print# command. @{b}Notes@{ub} - Remember that it will be reloaded to a different address, so all the pointers will be invalid, and have to be reset. @endnode @node C_StInput "Structs / Commands / Loading A Single Structure" @{b}Command Syntax@{ub} St Input INSTANCE, STRING$ @{b}Description@{ub} This command loads a string generated by St Output$ back into a structure INSTANCE. The instance must have already be allocated with St New. @{b}Notes@{ub} - The INSTANCE must be of the same type as the one from which the string was saved. @{b}Errors@{ub} @{u}Illegal Function Call@{uu} The type of the INSTANCE does not match that from which the STRING$ was output. @endnode @node C_StSave "Structs / Commmands / Saving A Graph Of Structures" @aka C_StLoad @{b}Command Syntax@{ub} St Save FILENAME$ , INSTANCE =St Load( FILENAME$ ) @{b}Description@{ub} Firstly, a graph is not a couple of lines on squared paper. We it is, but that isn't what I mean here. Specifically what I mean here is a directed graph of the structure instance, and everything it points to. In *english* what I mean is that the St Save command will save the instance to the file, then look at all of its pointer elements. If they are not null, it then saves all of the structures the point to. Then, it looks at the pointer elements of these structures, and saves anything they point to etc., until every structure that can be reached by following a pointer from the INSTANCE specified has been saved. The real power of this is that you can then load the all structures back, with the St Load function. They will be reloaded to different addresses - you don't even have to free the originals, but you can quit the program, reloadit, then reload the structures - and all the pointers in all the structures will automatically by relocated to the new addresses of the structures! You will be returned the new address of the instance you passed to the St Save command. @{b}Notes@{ub} - St Save & St Load can take some time to deal with large graphs. For the computer scientists, the algorithmn is O(nē). - If is OK if your graph contains cycles e.g. Instance A contains a pointer to B & Instance B a pointer back to A. Each instance is only saved once. - A temporary memory buffer is allocated by both of these commands, so an out of memory error is possible. Its size is 8 * The total number of existing structures for St Save, and 8 * The number of structures in the file for St Load. (Not counting sub-structures) - IMPORTANT: Never Save a graph in which some instances contain pointers to sub-structures of other instances - It will not be reloaded properly. It is OK for sub-structures to contain pointers to other structures, but not vice-versa. @endnode @node Tutorials "Structs / Tutorials" @{b}@{u}Examples & Tutorials@{uu}@{ub} The 'demos' directory contains a number of tutorials on the use of structured variables. Where as this manual has concentrated on the syntax of the structure defintions, and the easylife commands, these tutorials concentrate on the style of programming used with structured variables. They are mainly aimed at those who have only programmed in basic before and to whom the whole idea of pointers is new. The common data structures of Lists, Priority Queues and Trees are explained, along with the concept of data abstraction. Also, many of the Easylife Accessories, and other demos are programmed using structured variables (As it is much easier). In particular, you may find it beneficial to examine: The variable checker. (Structures make it 3-5 times faster than the old version) The optimiser. The Structure Compiler itself! (The original was virtually incomprehensible even to me a few months after writing) @endnode @node LibraryContents "Structs / Easylife.Library" @{b}@{u}Usage Via Easylife.Library@{uu}@{ub} The shared library Easylife.Library contains most of the code to support structured variables - the extension itself mostly just calls the library routines. This means that by using the library yourself, you can use structured variables from inside an AMOS extension, or from other assembler code called from AMOS, such as MUI hook functions, Asm banks, or assembler code inserted into procedures. The include file 'Easylife_Lib.i' defines the vector offsets for the library functions & some macros for calling them. Use of easylife.library varies slightly from using normal shared libraries on the amiga (Because I've broken some rules :-): - You cannot use it unless the easylife extension is loaded, and has been initialised. E.g. You can't use it outside AMOS, or in the part of extensions L0 routine that is called while starting AMOS. - You must not call it from another process, or an interupt. This is because some of the code is not reenterant. - You can only use it from assembler code - you can't use it from AMOS via LibCall. This is because it sets the condition codes if an error occurs, and you can't read them from AMOS. However, there is no need it use it from AMOS, as Easylife provides all the implemented user functions of the library. General Usage ============= All functions take their arguments in data registers, in ascending order from D0. All return values are returned in D0. Also, a few functions return a secondary value in D1. All functions preserve all registers, other than D0/D1. After a function is called, you should check the value of the zero flag. If it is set, an error has occured. Therefore, you should call all routines with: jsr _LVO...(a6) beq ErrorHandler If an error does occur: - There is no garuntee that any registers are intact, except A7. - If D0 contains a positive value, it represents a normal AMOS error number. Look it up in the manual, or use the AMOSPro Err$ function. - If D0 contains a negative number, negate it to get an easylife structures error number, as defined in the include file: 'Easylife.i' @{u}Library Functions:@{uu} @{"ELST_Lookup" link ELST_Lookup} equ -30 (ID , Scope) @{"ELST_GetBank" link ELST_GetBank} equ -36 () @{"ELST_Free" link ELST_Free} equ -42 (Inst) @{"ELST_Allocate" link ELST_Allocate} equ -48 (Type) @{"ELST_GetElement" link ELST_GetElement} equ -54 (Elem,Inst,Idx,NIdx) @{"ELST_SetElement" link ELST_SetElement} equ -60 (Elem,Inst,Idx,NIdx,Value) @{"ELST_StrCmp" link ELST_StrCmp} equ -66 (Elem,Inst,Idx,NIdx,String) @{"ELST_FreeBlocks" link ELST_FreeBlocks} equ -72 (Mode) @{"ELST_TreeScan" link ELST_TreeScan} equ -78 (Inst) @{"ELST_TreeScanFree" link ELST_TreeScanFree} equ -84 (List) @{"ELST_LoadTree" link ELST_LoadTree} equ -90 (Filename) @{"ELST_SaveTree" link ELST_SaveTree} equ -96 (Inst,Filename) @{"ELST_RelocateTable" link ELST_RelocateTable} equ -102 (NewTable,OldTable) @endnode @NODE "ELST_Lookup" "Easylife.library/ELST_Lookup()" NAME ELST_Lookup SYNOPSIS ELST_Lookup ( ID , scope ) D0 = D0 D1 FUNCTION Returns a pointer to the information about the identifer passed. Either a) ID is the ID word of a structure type, and scope is 0, in which case a pointer to information about the structure is returned, or b) Id is the ID word of an element, and scope is the ID word of the structure type the element occurs in, in which case information about the element is returned. INPUTS ID = The identifier word you want information about. This should be one of the global constants created in the AMOS Program by the compiler. scope = The structure type for which your want the element ID's information. If you want information about a structure, set scope to 0. RESULT The address of the identifiers information. For details of the format, see Structure Definitions Bank Format. SEE ALSO easylife.library/ELST_Free @ENDNODE @NODE "ELST_GetBank" "Easylife.library/ELST_GetBank()" NAME ELST_GetBank SYNOPSIS ELST_GetBank () D0= FUNCTION This function returns the address of the start of the current structures defintion bank. If no bank exists an error occurs. RESULT The address of the bank. @ENDNODE @NODE "ELST_Free" "Easylife.library/ELST_Free()" NAME ELST_Free SYNOPSIS ELST_Free ( instance ) D0 FUNCTION Deallocates the memory of a given structure instance. The memory is returned to a private memory pool - not to the system. Therefore it may only be re-used for other structued variables. INPUTS instance = The address of the structure instance to free. SEE ALSO easylife.library/ELST_Allocate easylife.library/ELST_FreeBlocks Easylife Command: St Free @ENDNODE @NODE "ELST_Allocate" "Easylife.library/ELST_Allocate()" NAME ELST_Allocate SYNOPSIS ELST_Allocate ( structure , mode ) D0,D1 = D0 D1 FUNCTION Allocates memory for a new structure instance. The memory is allocated inside a private memory block. Additional blocks are automatically allocated from the system memory pool as required. INPUTS structure = The type ID word for the structure to allocate an instance of. mode = If this is MEMF_CLEAR (Defined in exec/memory.i), the structure elements are reset to default values. If it is not, the structure elements are not pre- initialised to any particular value. RESULT The address of the allocated instance is returned. Also, the length of the structure instance allocated is returned in D1 as a secondary result. SEE ALSO easylife.library/ELST_Free @ENDNODE @NODE "ELST_GetElement" "Easylife.library/ELST_GetElement()" NAME ELST_GetElement SYNOPSIS ELST_GetElement ( element , instance , indexes , numindex ) D0, D1 = D0 D1 D2 D3 FUNCTION Reads the value of an element of a structure instance. INPUTS element = The ID word of the string element to get the value of. instance = The address of the structure instance to get the element from. indexes = If the element is an array, this is a pointer to a list of longwords giving the array index positions of the element to read, in the reverse order e.g. ARRAY(X,Y,Z) should have the longwords in the order: D2=Z,D2+4=Y,D2+8=X. numindex = The number of array indexes in the D2 list. RESULT The value of the element is returned, except for string elements where a pointer to the string is returned. This is a proper system string, which is always null terminated, but its length can be found by reading the previous word to that returned. However it is not really an AMOS string, as it is not in the variable buffer. This function also returns a secondary result in D1. It is a value which gives the type of the element: 0 = Longword Integer 1 = Ranged Longword Integer 2 = Word Integer 3 = Ranged Word Integer 4 = Byte Integer 5 = Ranged Byte Integer 6 = Real Number 7 = Untyped Pointer 8 = Typed Pointer 9 = Boolean 10 = String 11 = SubStructure SEE ALSO easylife.library/ELST_SetElement @ENDNODE @NODE "ELST_SetElement" "Easylife.library/ELST_SetElement()" NAME ELST_SetElement SYNOPSIS ELST_SetElement ( element , instance , indexes , numindex , value ) D0 D1 D2 D3 D4 FUNCTION Changes the value of an element of a structure instance. The value of any type of element can be changed, except a sub-structure. INPUTS element = The ID word of the string element to set the value of. instance = The address of the structure instance to set the element in. indexes = If the element is an array, this is a pointer to a list of longwords giving the array index positions of the element to change, in the reverse order e.g. ARRAY(X,Y,Z) should have the longwords in the order: D2=Z,D2+4=Y,D2+8=X. numindex = The number of array indexes in the D2 list. value = The new value for the element. Integers/Reals should be passed by value. Strings should be passed by reference - I.E. D3 contains a pointer to the string. The string should be in AMOS format - I.E. The first word is the length of the string in bytes. SEE ALSO easylife.library/ELST_GetElement @ENDNODE @NODE "ELST_StrCmp" "Easylife.library/ELST_StrCmp()" NAME ELST_StrCmp SYNOPSIS ELST_StrCmp ( element, instance , indexes , numindex , string ) D0 = D0 D1 D2 D3 D4 FUNCTION Compares a string element of a structure instance with a string passed to the function, and returns whether it is less, greater, or equal to it. (Using AscII ordering of the characters from the start of the string, like the AMOS < & > functions on strings.) INPUTS element = The ID word of the string element to compare. instance = The address of the structure element to lookup. indexes = If the element is an array, this is a pointer to a list of longwords giving the array index positions of the string to compare, in the reverse order e.g. ARRAY(X,Y,Z) should have the longwords in the order: D2=Z,D2+4=Y,D2+8=X. numindex = The number of array indexes supplied in the D2 list. string = The string to compare the element to. It should be an AMOS format string. That means the first word of the string is its length in bytes. It need not be null terminated. RESULT The result is 0 if the strings are equal, 1 if the string in D3 is created than the element string, or -1 if it is smaller. @ENDNODE @NODE "ELST_FreeBlocks" "Easylife.library/ELST_FreeBlocks()" NAME ELST_FreeBlocks SYNOPSIS ELST_FreeBlocks ( mode ) D0 FUNCTION Deletes the memory blocks which hold all allocated structure instances. If mode is non-zero, only those blocks which are empty are deleted. INPUTS mode = Scope of deletion. If this is non-zero only empty blocks are deleted. If it is zero, all blocks are deleted. SEE ALSO easylife.library/ELST_Free easylife.library/ELST_Allocate @ENDNODE @NODE "ELST_TreeScan" "Easylife.library/ELST_TreeScan()" NAME ELST_TreeScan SYNOPSIS ELST_TreeScan ( root ) D0 FUNCTION Creates a list of pointers to all the structures that can be reached by following a chain of pointers from the root element of the tree, taking cycles into account, and following pointers from sub-structures. No structure instance will appear twice in the list, and the first element of the list will be the root instance itself. The list is terminated with a 0 longword. ELST_TreeScanFree can be used to release the memory used for the list of structures returned by this function. INPUTS root = The structure instance to build a list of pointed to instances from. RESULT A pointer to the list of structures. The longword before the result contains the number of elements in the list (Not counting the null which terminates the list). The first element of the list is the root structure you passed to the function. SEE ALSO easylife.library/ELST_TreeScanFree @ENDNODE @NODE "ELST_TreeScanFree" "Easylife.library/ELST_TreeScanFree()" NAME ELST_TreeScanFree SYNOPSIS ELST_TreeScanFree ( list ) D0 FUNCTION Frees the memory allocated to the list by ELST_TreeScan. INPUTS list = A list of structures returned as the result of a call to ELST_TreeScan SEE ALSO easylife.library/ELST_TreeScan @ENDNODE @NODE "ELST_LoadTree" "Easylife.library/ELST_LoadTree()" NAME ELST_LoadTree SYNOPSIS ELST_LoadTree ( filename ) D0 FUNCTION Loads a file of saved structure instances, saved with the ELST_SaveTree Function (Or easylife St Save command). The saved structures are reloaded to new addresses in memory, and their pointers are relocated. INPUTS filename = The name of the file to create. It should be a normal system string, not an AMOS string (I.E. A string of null terminated characters without 2 bytes giving the strings length in front of it). RESULT A pointer to the root structure instance of the saved structure tree. This is the structure instance that was passed to the ELST_Save function to create the file. SEE ALSO easylife.library/ELST_RelocateTable Easylife Command: St Load @ENDNODE @NODE "ELST_SaveTree" "Easylife.library/ELST_SaveTree()" NAME ELST_SaveTree SYNOPSIS ELST_SaveTree ( root, filename ) D0 D1 FUNCTION Saves the structure instance 'root', into a file, and then also recursively saves all other structure instances that can be reached by following a chain of pointers from the root. The sub-structures of each structure saved are also searched for pointers. NOTE: If a pointer points to a sub-structure, the sub-structure is not saved. INPUTS root = A pointer to a structure instance to recursively save. filename = The name of the file to create. It should be a normal system string, not an AMOS string (I.E. A string of null terminated characters without 2 bytes giving the strings length in front of it). SEE ALSO easylife.library/ELST_TreeScan Easylife Command: St Save @ENDNODE @NODE "ELST_RelocateTable" "Easylife.library/ELST_RelocateTable()" NAME ELST_RelocateTable SYNOPSIS ELST_RelocateTable ( newlist, oldlist ) D0 D1 FUNCTION Relocates all the pointer elements of a set of structures to the new addresses of those structures. This will relocate all pointers in the main structure, and all pointers in its sub- structures, providing the structure they point to is also in the set of structures to be relocated. INPUTS newlist = A list of the structures to relocate. Each structure address is a longword. The list ends with a 0 longword. All pointers from structures in this list to other structures in the list will be relocated from those structures old addresses (The values currently in the pointer elements). oldlist = A list of the previous addresses of each structure, which they are to be relocated from. Each element of this list gives the old address of the elment in the same position in the newlist. This list should therefore be the same length as the newlist, and also be null terminated. SEE ALSO easylife.library/ELST_LoadTree @ENDNODE @NODE StorageContents "Structs / Storage Contents" @{b}@{u}Easylife Structures - Storage Formats@{uu}@{ub} NOTE: All of these formats are subject to change in future versions of the extension & library. @{"Compiled Definitions Bank " link StorageBank} @{"Structured Varaible Instance" link StorageInstance} @{"Saved Structures File " link StorageFile} @endnode @node StorageBank "Structs / Compiled Defintitions Bank Format" @{b}@{u}Compiled Structures Defintions Bank Format@{ub}@{uu} The definition banks generate by the structure compiler are split into 3 seperate parts: @{u}The Bank Header@{uu} This is currently 20 bytes long. @{u}Offset Type Meaning@{uu} 0 LongWord "Magic Number" to identify bank type 4 LongWord Checksum identifer for this compilation 8 LongWord Not Used 12 LongWord Size Of Allocated Memory Blocks 16 LongWord The offset from the start of the bank to the 3rd part of the bank, the definitions @{u}The lookup table@{uu} The constants put into the ST_... global variables are offsets to the information about each element/structure name in the lookup table from the start of the bank. The structure which is found at each of these offsets is: @{u}Offset Type Meaning@{uu} 0 Word Number Of Entries In List 2 Struct Entry No. 1 6 Struct Entry No. 2 10 Struct Entry No. 3 ... There is one entry in the list for each time the name is used in the definitions as a structure or element name. The 4 bytes of the entry are 2 seperate words. The first is the offset from the start of the bank to the defintion of the entry in the definitions section of the bank. The second is the ID word for the scope in which this entry occured (Or 0 if this entry is for a structure name). E.g. If the name 'Fred' is used as a structure name, and as an element of the structures 'Big' and 'Small', and assuming ST_FRED=10,ST_BIG= 20,ST_SMALL=30, the entry might look like dc.w 3 ;3 Entries dc.w Off1,20 ;Off1=Information about Fred element of 'Big' dc.w Off2,30 ;Off2=Information about Fred element of 'Small' dc.w Off3,0 ;Off3=Information about Fred structure. You should never need to access this part of the bank directly, just use the easylife.library ELST_Lookup function to find the appropriate defintions for an ID. @{u}Defintions@{uu} The defintions section contains a series of blocks of information defining the type of elements, or information about structure types. The position of each defintion is found from the ELST_Lookup function in the easylife.library. The format of the information depends on the type of element, or structure. @{u}Structures@{uu} @{u}Offset Type Meaning@{uu} 0 LongWord Size of structure (Rounded Up For Allocating) 4 Word Number of pointer elements (Arrays count as 1) in the structure (Not including those in sub- structures) 6 Word Number of sub-structures (Arrays count as 1) 8 Struct Sub-Structure #1 Info 18 Struct Sub-Structure #2 Info 28 Struct Sub-Structure #3 Info ... The information about each sub-structure, or array of sub-structures is of the format: @{u}Offset Type Meaning@{uu} 0 LongWord Offset of element in structure 4 LongWord Total number of array elements in array (0= single sub-structure) 8 Word ID Word (ST_... Constant) of sub-structure type. @{u}Elements@{uu} @{u}Offset Type Meaning@{uu} 0 Byte Element Type (See Table In ELST_GetElement) 1 Byte Number of array dimensions (0=Single Element) 2* Word Array Size - Dimension 3 4* Word Array Size - Dimension 2 6* Word Array Size - Dimension 1 8* LongWord Offset to element in structure instance NOTE: The array sizes are only present if the element is an array, so the address of the sub-sequent elements may differ if the element is an array of less than 3 dimensions, or not an array. This may be followed by more information depending on the element type: Integers & Reals: No extra information. Any Ranged Integer: Longword giving the minimum value, followed by a longword giving (the maximum value - the minimum value). Untyped Pointers: A zero word. Typed Pointers: A word giving the ID value (ST_...) of the type of structure the pointer should point to. Booleans: A byte giving the bitoffset withing the byte the element begins at. Bits are numbered 0-7, right to left. This is followed by a second byte to pad to a even address. Strings: A word giving the maximum length of the string. Sub-Structures: A word giving the structures size, following by a word giving the structures ID word. @endnode @node StorageInstance "Structs / Format Of Structured Variable Instance" @{b}@{u}Format Of Structured Variable Instance@{uu}@{ub} The first longword a of a structured variable instace contains information about the structure. The rest contains the actual element data: Word 0 is the type ID word of the structure. It is the ST_... value for the type of structure that this is an instance of. The second word contains some flags, of which only 2 are currenty used: Bit 0 : Is set if this is a sub-structure. Is clear otherwise. Bit 1 : Is set temporarily when constructing a list with the ELST_TreeScan function to mark which structures are already scanned. The rest of the structure contains the elements. They occur in the order they were declared except they are sorted into 4 categories by element type: First come all the pointer elements. Second come all Longword & Word length elements, Sub- Structures and strings, which are padded to an even length. Third come single byte integer elements. Last come boolean elements. Within these 4 classes the elements occur in the order they were defined E.g. 'value : integer 'str : string length 7 'valid : boolean 'letter : integer from 65 to 91 'next : pointer to thisstruct 'prev : poitner to thisstruct Will cause the elements to be ordered "Next","Prev","Value", "Str","Letter" and finally "Valid". Strings are stored as a word giving the length, followed by the string itself, followed by a null byte terminator, followed by an additional byte to pad it to a word boundary if necessary. @endnode @node StorageFile "Structs / Format Of A Saved Structure File" @{b}@{u}Format Of A Saved Structure File@{uu}@{ub} This page describes the format of the files created by the St Save command, or ELST_SaveTree library function. There is a header of 12 bytes: @{u}Offset Type Meaning@{uu} 0 LongWord Magic Number to identify filetype. 4 LongWord Number of instances saved in the file. 8 LongWord Reserved For Future Expansion. This is followed by the saved structure instances. These have the format of a longword giving the address from which the structure was saved, followed by the structure instance as it appeared in memory. No information about the length of each structure instance is written to the file, this must be deduced from the structure type ID which is in the first word of each structure instance. The address from which it was saved is included in the file so that the pointers can be relocated from these old addresses. @endnode @node Future "Structs / Future" In the future I plan to add these capabilitise to the structures commands, and the compiler: - The ability to predefine structure instances in a bank which is created by the compiler with the structure instances. - The ability to edit / monitor instance variables from an interactive debugger accessory, running as an MUI program on the intuition screen so as not to interfere with your program display. @endnode