Tivoli Service Desk 6.0 Developer's Toolkit Script Programming Guide

Chapter 4: Knowledgebase Components

Back to Table of Contents


Introduction

Developer's Toolkit allows you to group statements together into routines and package them into reusable knowledgebases (or modules). This modular characteristic eases the difficulty of maintaining large amounts of source code.

This chapter covers the basics required to understand and build multi-knowledgebase applications.

The ROUTINES section

The keyword ROUTINES is used to introduce any section of a knowledgebase that contains subroutines or procedures.

Locating ROUTINES in the public section

In the public section between the KNOWLEDGEBASE header and the PRIVATE keyword, the routines section contains declarations of procedures and functions that are implemented in the private section.

Using ROUTINES in the private section

In the private section, the ROUTINES keyword is followed by the complete procedure and function implementations.
An example is shown below:

KNOWLEDGEBASE Print; 
  TYPES 
    EmployeeRecord IS RECORD 
      first_name, last_name: String; 
      employee_ID: String; 
      hireDate: Date; 
      salary: Real; 
    END; 
  ROUTINES 
    PrintEmployee(REF e: EmployeeRecord); 
PRIVATE 
  ROUTINES 
    PROCEDURE PrintString(VAL s: String) IS 
    ACTIONS 
      ... 
    END; 
PROCEDURE PrintEmployee(REF e: EmployeeRecord) IS 
    ACTIONS 
      PrintString(e.first_name); 
      PrintString(e.last_name); 
      ... 
    END;

The USES section

Every Developer's Toolkit knowledgebase file consists of two primary sections.

Example

In the following example, there is a knowledgebase called Statistics (contained in file statisti.kb) which is used by another knowledgebase called Application (in the file (applicat.kb)):

KNOWLEDGEBASE Statistics;
  ROUTINES
    PROCEDURE Regression;
    PROCEDURE TimeSeries;
    PROCEDURE ChiSquare;
...
KNOWLEDGEBASE Application;
...
PRIVATE
  USES
    Statistics;
...

By declaring Statistics in its uses section, the routines in Application are able to call the three procedures defined by Statistics.

Introducing the USES section

The uses section is introduced by the USES keyword and must be placed in one (or both) of these places:

Using multiple knowledgebases

A knowledgebase can use as many other knowledgebases as it needs. Each used knowledgebase must be listed in the uses section and must be followed by a semicolon:

KNOWLEDGEBASE User;
...
PRIVATE
  USES
    Used1;
    Used2;
    ...
    Used99;

Using a knowledgebase privately

A knowledgebase is used privately when it is contained in the USES statement in the private section of a knowledgebase.

When a knowledgebase is used privately, its public variables and procedures are available throughout the private section to implement the routines declared in the public section. In other words, the knowledgebase's private implementation can be composed of the public routines of another knowledgebase.

Two knowledgebases can use each other privately without restriction, as long as they name each other in the private section. That is, Knowledgebase A can use Knowledgebase B, and vice versa.

Using a knowledgebase publicly

A knowledgebase is used publicly when it is contained in the USES statement in the public section of a knowledgebase.

When a knowledgebase is used publicly, the symbols from the used knowledgebase are available throughout the entire knowledgebase.

You should use a knowledgebase publicly when symbols from that knowledgebase are required for some public declaration in the using knowledgebase.
An example of this is when a record type defined in one knowledgebase is used in a record type declaration in another.

Cyclical use of public knowledgebases

Cyclic use occurs when Knowledgebase A uses Knowledgebase B and vice versa. Knowledgebases cannot use each other cyclically in the PUBLIC section.

One way to avoid this limitation is to move the common declarations needed by both knowledgebases into a separate knowledgebase that uses nothing publicly itself. This is not always feasible because it may not make sense to combine declarations for very different functions into one knowledgebase. Sometimes, however, this solution works.

As an example, suppose that you create a program that tracks information pertaining to employees and the department they work in. You want to encapsulate most of the information relating to employees in a knowledgebase called "Employee" and the information relating to departments in a knowledgebase called "Department."

However, the public routines that manipulate employee records sometimes require department records as parameters, and vice versa. Therefore, there is a need for the two knowledgebases to use each other publicly. Because this will not work, the knowledgebases must instead be organized as shown in the following example:

KNOWLEDGEBASE EmplType;
    TYPES
        Employee IS RECORD
        ...
        END;
    ...
END;
KNOWLEDGEBASE DeptType;
    TYPES
        Department IS RECORD
        ...
        END;
    ...
END;
KNOWLEDGEBASE Employee;
    USES
        EmplType;
        DeptType;
    ROUTINES
        PROCEDURE AddEmployee (VAL lst: LIST OF Employee,
                               REF dept: Department);
...
PRIVATE
...
END;
KNOWLEDGEBASE Department;
    USES
        EmplType;
        DeptType;
    ROUTINES
    PROCEDURE AssignOffice (REF dept: Department, REF empl:
                   Employee);
...
PRIVATE
END;

Procedures

A procedure is a collection of Developer's Toolkit statements that are referred to by name and that do not return a value to the caller.

A procedure is a block that is nested within the knowledgebase. Like the knowledgebase itself, a procedure can have sections for constants, types, variables, and routines. Identifiers in these sections are local to the procedure and are not visible outside of it.

Each procedure has an actions section that is the location for the executable Developer's Toolkit statements that determine what the procedure does.

Examples

The general form for a procedure is shown below:

PROCEDURE <procedure-name>(<formal-parameter-list>) IS 
CONSTANTS 
  <constant-declarations> 
TYPES 
  <type-declarations> 
VARIABLES 
  <variable-declarations> 
ROUTINES 
  <subroutine-implementations> 
ACTIONS 
  <KML statement-list> 
END;

The following is a simple procedure with an actions section that contains two Developer's Toolkit statements. When this procedure is called, the two statements in the actions section are executed:

PROCEDURE CopyrightMessage; 
ACTIONS 
  WinWriteLN($DeskTop,'Copyright 1996 by'); 
  WinWriteLN($DeskTop,'Software Artistry, Inc.'); 
END; 

Using local variables with nested variables

It is often useful for a procedure to contain local variables in a nested variables section. Local variables are program variables whose scope is limited to a specific block of code. As a rule, local variables are confined to a subroutine.

The following example creates a procedure called WriteTenLines. The procedure uses a local variable called i to iterate through a FOR loop and write 10 strings to a window:

PROCEDURE WriteTenLines; 
VARIABLES 
  i: Integer; 
ACTIONS 
  FOR i:=1 TO 10 DO 
    WinWriteLn(myWindow,''); 
  END; 
END; 

This example is further enhanced to include a local constant:

PROCEDURE WriteTenLines; 
CONSTANTS 
  MAX_LINES IS 10; 
VARIABLES 
  i: Integer; 
ACTIONS 
  FOR i:=1 TO MAX_LINES DO 
    WinWriteLn(myWindow,''); 
  END; 
END; 

Creating local routines

It is often desirable to create local routines, particularly if the variable you want to use only occurs in one part of a program. Local routines are procedures or functions declared inside another procedure or function. A local routine can be called only by the procedure or function that contains it or by other local routines contained with it. Look at the example:

PROCEDURE PrintEmployeeInfo(REF e: EmployeeRecord) IS 
ROUTINES 
  PROCEDURE PrintDemographics IS 
  ACTIONS 
    PrintString(e.first_name); 
    PrintString(e.last_name); 
    PrintString(e.ssn); 
  END; 
  PROCEDURE PrintManages IS 
  ACTIONS 
    FOR e.manages DO 
      PrintString(e.manages[$Current]); 
    END; 
  END; 
ACTIONS 
  PrintDemographics; 
  PrintManages; 
END;

Scoping

One of the important conceptual issues in block-structured languages is scope. Within any given block, only certain identifiers exist, or are in scope. In general, nested blocks are able to "see" identifiers declared in an enclosing scope. An object or identifier in an enclosing scope is local only to that block.

Scoping example

Consider the following example:

KNOWLEDGEBASE Scope; 
  CONSTANTS 
    MAX_EMPLOYEES IS 500; 
  TYPES 
    EmployeeRecord IS RECORD 
       first_name, last_name: String; 
    END; 
  VARIABLES 
    employeeList: List of EmployeeRecord; 
PRIVATE 
  CONSTANTS 
    ARRAY_SIZE IS 1000; 
  VARIABLES 
    employeeArray[ARRAY_SIZE]: ARRAY OF EmployeeRecord; 
  ROUTINES 
    PROCEDURE ProcTwo IS 
    VARIABLES 
       i: Integer; 
     ACTIONS 
       ... 
      END; 
      PROCEDURE ProcOne IS 
      VARIABLES 
        i: String; 
        j: Integer; 
      ACTIONS 
        ... 
      END; 

Scoping example explanation

MAX_EMPLOYEES, EmployeeRecord, and employeeList are visible throughout the knowledgebase because they are declared in the outermost block. These elements appear in the public section of the knowledgebase, so they are also visible to other knowledgebases that use this knowledgebase.

Similarly, because ARRAY_SIZE and employeeArray are declared in the private section of the outermost block, they are visible throughout the private section. Both ProcTwo and ProcOne can refer to these identifiers, but because they are in the private section, no other knowledgebase can access them.

The variable i in ProcTwo is visible only in ProcTwo. The variables i and j in ProcOne are visible only in ProcOne. The i variable in ProcOne is completely unrelated to the i variable in ProcTwo.

Variable values exist only while the block in which they are enclosed executes. For instance, the variables i and j have values only during the execution of ProcOne.

Parameter Passing

Passing information to a procedure

When calling procedures, it is often necessary to pass information to them.
This can be accomplished with the following steps:

    PROCEDURE ComputePercent (VAL Dividend : INTERGER,
                             VAL Divisor : INTEGER,
                             REF Quotient : INTEGER) IS
                (*parameter to PROCEDURE ComputePercent*) 
    ACTIONS
          Quotient := Dividend/Divisor*100;
    END;

When the procedure is called, the number of expressions passed equals the number of parameters declared for the procedure. The expressions passed must have the same data type and parameter type as the parameters specified.

    VARIABLES
    (*Compute the percentage of cars of differing colors
    in a garage*)
         NumBrownCars : INTEGER;
         NumBlackCars : INTEGER;
         NumMixedCars : INTEGER;
         TotalCars : INTEGER;
         PercentBrownCars : INTEGER;
         PercentBlackCars : INTEGER;
         PercentMixedCars : INTEGER;
    ACTIONS
    (*Expressions passed to compute the percentage of 
    cars of differing colors in a garage*)
         ComputePercent (NumBrownCars, TotalCars,
                         PercentBrownCars);
         ComputePercent (NumBlackCars, TotalCars,
                         PercentBlackCars);
         ComputePercent (NumMixedCars, TotalCars,
                         PercentMixedCars);
    End;

Passing by REF or VAL

In the next example, notice that some parameters are passed by value (VAL) and some by reference (REF).

In a VAL parameter, a value is copied from the caller to the called routine, and nothing that the called routine does affects the value that the caller still possesses.

A REF parameter addresses the same storage that the caller possesses. Thus, changes to the parameter's value that occur during the course of the called routine take effect immediately on the caller's value.

Example

Consider the following example:

ROUTINES 
  PROCEDURE DistanceFormula(VAL x1, y1, x2, y2: 
      Integer, REF distance: REAL) IS 
  ACTIONS 
    distance:=Sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); 
  END; 
  PROCEDURE ComputeDistances IS 
  VARIABLES 
    distance: Real; 
  ACTIONS 
    DistanceFormula(1,1,9,9,distance); 
    WinWriteLN(myWindow,'The distance is ' & 
               distance); 
    DistanceFormula(9,9,15,87,distance); 
    WinWriteLN(myWindow,'The distance is ' & 
               distance); 
  END; 

Example explanation

In the preceding example, a procedure called DistanceFormula has been declared.

The procedure takes five formal arguments:

When the procedure is called, copies of the first four integer values passed are sent to the procedure. However, in the case of the fifth parameter, the actual variable sent by the caller is passed to the procedure.

If a procedure expects a parameter passed by value, the caller can send a:

However, if a procedure expects a parameter to be passed by reference, the caller can send only a variable.

Treating parameters as variables

A procedure can treat all parameters passed to it as variables. It can:

Changes made to parameters passed by value are not transmitted back to the caller.

In the previous example, ComputeDistances sent literal values for the four integer arguments to DistanceFormula because the corresponding parameters were declared with the VAL keyword. However, ComputeDistances passed only a variable for the fifth argument because the fifth parameter was declared with the REF keyword.

Note: There is no default parameter type. You must specify either VAL or REF for each parameter in a procedure declaration.

Functions

Functions are identical to procedures except that they return a value to the caller. For that reason, functions can be used only in assignments or expressions. They cannot be used as statements.

Functions can return simple types (such as strings, integers, reals, Boolean values, dates, and times) as well as structured types and user-defined types.

You can also write a function that returns a list of records.

Function form

Functions have the following general form:

FUNCTION <function-name>(<formal-parameter-list>): <Type> IS 
CONSTANTS 
  <constant-declarations> 
TYPES 
  <type-declarations> 
VARIABLES 
  <variable-declarations> 
ROUTINES 
  <subroutine-implementations> 
ACTIONS 
  <KML statement-list> 
END; 

Function example

The following example changes DistanceFormula so that it is a function rather than a procedure:

ROUTINES 
  FUNCTION DistanceFormula(VAL x1, y1, x2, y2: 
      Integer): REAL IS 
  ACTIONS 
    Exit Sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); 
  END; 
  PROCEDURE ComputeDistances IS 
  VARIABLES 
    distance: Real; 
  ACTIONS 
    distance:=DistanceFormula(1,1,9,9); 
    WinWriteLN(myWindow,'The distance is ' & 
      distance); 
    distance:=DistanceFormula(9,9,15,87); 
    WinWriteLN(myWindow,'The distance is ' & 
      distance); 
  END; 

Note: Every function must have an explicit return type that follows the parameter list and is separated from it by a colon.

Using $Result

$Result can be used within the body of a function to access the current return value for that function. You can set or test it within the function body.

Consider the following change to DistanceFormula:

FUNCTION DistanceFormula(VAL x1, y1, x2, y2: 
    Integer): REAL IS 
ACTIONS 
  $Result := Sqrt((x2-x1)*(x2-x1) + (y2-y1)*
                 (y2-y1)); 
END; 

In this example, the return value of the function is set with $Result.

$Result can be assigned many times in a function body. $Result automatically has the data type declared for the function's return value.

Using Exit with functions

Exit, when used with a function, causes:

When you use an Exit statement within a function, you can give it a parameter that indicates the value you want returned.

Exit (42); 

is the same as:

$Result := 42;
Exit;

If a function ends without using an Exit statement, a value of $Unknown is returned.

Exit combines the tasks that:

Calling Library Procedures and Functions

Access to routines written in C or C++ from a program written in Developer's Toolkit is provided by the Developer's Toolkit external routine mechanism.

An external routine consists of two parts:

Developer's Toolkit's declaration syntax

Beginning with Developer's Toolkit 4.2, Developer's Toolkit's declarative syntax supports most interface requirements without an extensive understanding of the underlying Developer's Toolkit data structures.

To call an external routine, the Developer's Toolkit Interpreter must have a declaration of the routine that tells:

External routine syntax

The syntax of an external routine declaration is shown in the following example. As with any Developer's Toolkit routine implementation, these declarations may appear only in the private section of a Developer's Toolkit knowledgebase.

FUNCTION name [(VAL|REF parameter : type [, ...])] : type
    IS EXTERNAL dll_name [, entry_point][, linkage];
PROCEDURE name [(VAL|REF parameter : type [, ... ])]
    IS EXTERNAL dll_name [, entry_point][, linkage];

The DLL name is a constant string expression that identifies the library in which the external routine is located. The .dll extension is usually different on a per-platform basis and is generally omitted from the given name.

Entry points

Entry points are locations within a program or routine where execution can begin. A routine normally has only one entry point. The entry point may be either a:

A string represents the name of an entry point and an integer represents its ordinal number in the library.

Constructing a function name

C++ compilers typically use a technique known as name mangling that ensures correct linkage between separate compiled object modules.
External functions written in C++ usually must either be declared external "C" in the C++ source code or be loaded by their ordinal number.

Linkage specifications

The linkage specification in an external routine declaration must be one of the following symbols:

Note: The Developer's Toolkit DLL callout facility will fail for "pass by reference" arguments if the DLL being called was not compiled with Microsoft Visual C++.

For IBM C++ on OS/2, the protocol is _Optlink._

For OS/2, the protocol is _System.

If the linkage specification is omitted altogether from an external routine declaration, the linkage defaults to $STANDARD.

For all UNIX operating systems, the convention is compile-specific. If your library was written in C or C++, use $C. Otherwise, use $System.

Simple parameter types for external routines

To facilitate the use of third party libraries, TSD Script provides a number of predefined type names that map directly to simple C/C++ types.

TYPES
SHORT    IS INTEGER: INT(2)  DEFAULT($ERROR);
USHORT   IS INTEGER: UINT(2) DEFAULT($ERROR);
LONG     IS INTEGER: INT(4)  DEFAULT($ERROR);
ULONG    IS INTEGER: UINT(4) DEFAULT($ERROR);
PSZ      IS STRING : POINTER DEFAULT(0);
FLOAT    IS REAL   : FLOAT(4) DEFAULT($ERROR);
DOUBLE   IS REAL   : FLOAT(8) DEFAULT($ERROR); 

The types SHORT, USHORT, LONG, ULONG, PSZ, FLOAT and DOUBLE are provided in the system knowledgebase found in the file TSD Script.KB.

Mapping external DLL types

External DLL types are mapped by TSD Script to the most common low-level data types used in C and C++. The extra declarative syntax tells the TSD Script Interpreter how to map the data.

For example, the declaration for SHORT says that the value should be packed into a two byte integer. The Default declaration indicates that $Unknown causes a run-time error if an attempt is made to pass it to an external routine through a SHORT parameter.

The declaration for PSZ says that the value should be packed as a pointer, and that $Unknown should be passed as a zero (NULL) pointer.

Here is an example of how you might declare the ExitWindows function supplied by Microsoft Windows:

FUNCTION ExitWindows (VAL reserved: INTEGER,
                      VAL returnCode: INTEGER ): BOOLEAN
IS EXTERNAL `USER.EXE', `ExitWindows', $SYSTEM;

Note: A TSD Script "integer" is a long (32-bit) value and "int" does not always work in C.

Parameter Passing for External Routines

Like the parameters for normal TSD Script routines, the parameters for external routines are specified as passed by either:

VAL parameters

VAL parameters to external routines behave much like VAL parameters to non-external routines.

The value is copied from the caller to the called routine, and nothing that the called routine does affects the value that the caller still possesses.

A string that is passed by VAL is also received by the external routine as a pointer which addresses a temporary storage location into which the TSD Script string has been copied.

REF parameters

REF parameters differ slightly from VAL parameters for external routines.

When a non-external routine receives a REF parameter, it addresses the same storage that the caller possesses. Any changes to the value of the parameter during the called routine takes effect immediately on the caller's value.

Passing by reference to an external routine is actually implemented as copy-in/copy-out. The difference is subtle, but under some circumstances, the behavior is detectable. For instance, the dispatch of a message from an external routine is an example of this behavior.

The data type STRING (and aliases such as PSZ) is an exception and is passed by a pointer to the actual TSD Script string value when passed by REF.

All REF parameters are passed to external C or C++ routines as pointers. TSD Script does not attempt to support the C++ notion of references. If you need to call a C++ routine that takes reference parameters, you can write a small wrapper function. The wrapper takes a pointer from TSD Script, de-references it, and passes it along to the required C++ function.

Because TSD Script does not directly support the ANSI C and C++ notion of const, TSD Script programmers typically declare a parameter as REF when the C/C++ function takes a const pointer argument.

Translating data

Passing data between TSD Script and an external routine often requires that data be translated into an alternative format. Before the external routine is called, the caller's value is:

If the parameter is a REF parameter then, after the caller returns, the temporary area is unpacked back into the caller's storage.

Data structures and binary packing

Although you can construct fairly elaborate interfaces using simple types, eventually you will want to pass aggregate data structures to an external routine.
Developer's Toolkit 4.2 added new syntax to TSD Script that allows the explicit specification that detailing how TSD Script data is mapped to C or C++ data structures. This mapping is referred to hereafter as binary packing.

Binary packing information is supplied as an annotation to the type specification in either a named type declaration or a field specification within a record declaration. The gross syntax for both are shown below.

TYPES
type_name IS type : annotation ... ;
type_name IS RECORD
[ field_name : type ] [ : annotation ... ] ; ...
END;

Data annotation format

The following annotations specify the format in which TSD Script data is packed. They are all mutually exclusive.

Annotation Description
INT(width) The INT annotation specifies that the field is packed into the native integer format with the specified width. Legal values for the width are 1, 2, and 4. Any TSD Script data type that can be explicitly converted to INTEGER can be packed as INT.
UINT(width) The UINT annotation specifies that the field is packed into the native integer format as an unsigned value with the specified width. When passing a value from TSD Script to an external routine, there is no significant difference between INT and UINT, because the same bit pattern is passed in either case. However, when a 1 or 2-byte value is passed back to TSD Script from the external routine, the INT/UINT distinction determines how the value is sign-extended. Again, legal values for width are 1, 2, and 4.
NUMERIC(width) Fields with the NUMERIC annotation are packed as a blank-padded character sequence with the given width. TSD Script Reals, Integers and any data type that can be converted to Integer may by packed as a NUMERIC field.
FLOAT(width) Fields with the FLOAT annotation are packed as an IEEE floating point number with the specified width. Valid widths are 4 and 8. Any TSD Script type that can be explicitly converted to REAL can be packed as a FLOAT.
BCD(width) Fields with the BCD annotation are packed as Binary Coded Decimal. Any TSD Script type that can be explicitly converted to REAL can be packed as BCD.
CHAR(width) Fields with the CHAR annotation are packed as a simple character array with the given width. Any TSD Script type that may be converted to STRING may be packed as CHAR.
ZSTRING(width) Fields with the ZSTRING annotation are packed as a null-terminated (C-style) string with the given width. Any TSD Script data type that can be converted to STRING can be packed as ZSTRING.
LSTRING(width) Fields with the LSTRING annotation are packed as a Pascal-style string, with a lead byte containing the length of the string. Any TSD Script type that can be converted to STRING can be packed as LSTRING.
ASE_DATE Fields with the ASE_DATE annotation are packed as a DATEREC struct. Any data type that can be explicitly converted to DATE can be packed as an ASE_DATE.
BTRV_DATE Fields with the BTRV_DATE annotation are packed as a Btrieve-style date. Any data type that can be explicitly converted to DATE can be packed as a BTRV_DATE.
CCYYMMDD Fields with the CCYYMMDD annotation are packed as a character string containing the century, year, month, and day, each packed into two bytes. Any type that can be explicitly converted to DATE can be packed as a CCYYMMDD.
ASE_TIME Fields with the ASE_TIME annotation are packed as a TIMEREC. Any data type that can be explicitly converted to TIME can be packed as an ASE_TIME.
BTRV_TIME Fields with the BTRV_TIME annotation are packed as a Btrieve-style time. Any data type that can be explicitly converted to TIME can be packed as a BTRV_TIME.
HHMMSS Fields with the HHMMSS annotation are packed as a character string containing the hour, minute, and second, each packed into two bytes. Any data type that can be explicitly converted to TIME can be packed as an HHMMSS.
POINTER Fields with the POINTER annotation are packed as a 32-bit pointer to their actual TSD Script data. Any of the non-aggregate data types in TSD Script may be packed as POINTER.
NOEXPORT The NOEXPORT annotation marks a field that is not included at all in the external binary representation. Any type of field can be marked NOEXPORT

Default value annotation

In addition to a format annotation, a default value annotation can be specified. The default value annotation instructs the TSD Script interpreter how to fill the field in the binary structure when the TSD Script value is unknown. The syntax for the default value annotation is:

DEFAULT( $ERROR|expression ) 

When $ERROR is specified, packing an unknown value causes the TSD Script Interpreter to display an error message and abort the external routine.

This is the default when no value annotation is specified.

When an expression is specified, that expression is evaluated and its value packed according to the format annotation when the TSD Script value is unknown. This feature is used to map unknown strings to NULL.

Packing annotations

In a sequence of field specifications, you can supply packing annotations without any corresponding field name or data type. These annotations specify fields in the binary structure that do not appear in the TSD Script record. This occurs because the fields themselves do not appear in the TSD Script record. You must supply an additional annotation with the value for that field.

The syntax for this special annotation is

Each time the field is packed, the given expression is evaluated and then packed according to the corresponding format annotation.

FILL annotations

Finally, for purposes of field alignment, the FILL annotation can be used to place an arbitrary number of filler bytes between fields in the binary structure.

The syntax of the FILL annotation is

FILL( width [ , value ] ) 

The number of bytes specified by width, and those containing the given value, are packed into the binary structure. Although any constant integer value can be specified for the FILL annotation, the actual packed bytes contain only the least significant 8 bits, so -128 to 255 represents the useful range of values. The default value is zero.

Named types and fields without explicit packing annotations are packed according to the defaults for their underlying types.
The following table indicates the defaults for the intrinsic non-aggregate TSD Script data types.

Type Default packing information Default Result
Boolean INT(1) DEFAULT($ERROR)
Integer INT(4) DEFAULT($ERROR)
Real FLOAT(8) DEFAULT($ERROR)
String POINTER DEFAULT(0)
Time ASE_TIME DEFAULT($ERROR)
Date ASE_DATE DEFAULT($ERROR)
Window, File (Handle types) UINT(4) DEFAULT($ERROR)

Tivoli Service Desk 6.0 Developer's Toolkit Script Programming Guide

Back to Table of Contents

Copyright