You are on page 1of 10

Infobasic Programming

Introduction

Programming language used for T24


Simple English like statements
No declaration of variables required
No data type specification is required
All variables by default have indefinite variable length

Arrays

Continuous allocation of bytes


All bytes in an array have the same name as that of the array
Each byte is uniquely identified by a subscript which starts with zero (0)

Dimensioned Arrays

Also known as Static Arrays


Have a fixed number of rows and columns
A one-dimensional array is called a vector.
A two-dimensional array is called a matrix.
Can hold any type of data
A dimensioned array must be declared before it can be used, using the DIM
statement
Used when dimensions and extents are known and are not likely to change
Example
o DIM TEST(5,3)
TEST is the name of the array
5 = row number
3 = column number
o DIM TEST1(5)
TEST1 is the name of the array
5 = row number
Unlimited = column
To assign the same value to all elements of a dimensioned array in one go,
use the MAT statement: MAT TEST = ''

Dynamic Arrays

A dynamic array is simply a long string divided into sections by the


occurrence of certain delimiter characters.
There are three levels of delimiter, known as the field marker (ASCII character
254), the value marker (ASCII character 253) and the sub-value marker
(ASCII character 252). Infobasic variables @FM, @VM and @SM corresponds
to field marker, value marker and sub-value marker, respectively.
A field marker separates each field and a value marker separates each value
within a field. Any value can have sub-values separated by sub-value marker.

Dynamic in nature. Automatically increase or decrease in size depending on


the data
Variable length
Need not be declared
Can hold any type of data
All variables in infobasic are dynamic arrays
As a dynamic array is merely a string, you can also use it wherever you would
use a string. For instance, you could:
DYNARRAY = '[F1]': @FM : '[F2V1]' : @VM : '[F2V2S1]' : @SM : '[F2V2S2]'
PRINT DYNARRAY ;

This will print [F1][F2V1][F2V2S1][F2V2S2]


(As characters 252, 253 and 254 lie outside the range of ASCII 'printable
characters', the way they are displayed will depend on the terminal or
printer you are using.)
You can access the fields in a dynamic array using a subscript in 'vector' like
this:
PRINT DYNARRAY<1> * Prints [F1]
PRINT DYNARRAY<2> * Prints [F2V1][F2V2S1][F2V2S2]
To access the values in the second field individually, use two subscripts within
the pointy brackets:
PRINT DYNARRAY<2,1> * Prints [F2V1]
PRINT DYNARRAY<2,2> * Prints [F2V2S1][F2V2S2]
Three subscripts allow you to access individual subvalues:
PRINT DYNARRAY<2,2,1> * Prints [F2V2S1]
PRINT DYNARRAY<2,2,2> * Prints [F2V2S2]
As you can see, a dynamic array can be used to store up to three 'dimensions'
of information. Note also that using 'out of range' subscripts causes no run
time error when accessing fields, values, or subvalues: the dynamic array
simply yields an empty string if the subscript you are looking for 'doesn't
exist'. The code below illustrates this point:
PRINT DYNARRAY<1,2>
* Prints an empty string, ie. nothing
PRINT DYNARRAY<1000> * Prints an empty string, ie. nothing
PRINT DYNARRAY<99,472,293> * Prints an empty string, ie. nothing
The subscript notation can also be used to assign values to a dynamic array,
either overwriting existing values, or creating new ones.
DYNARRAY<1> = '[F1V1]' * Overwrites field 1 of DYNARRAY
PRINT DYNARRAY<1>
* Prints [F1V1]
DYNARRAY<1,2> = '[F1V2]' * Adds second value to field 1, creating a value
mark in the process
PRINT DYNARRAY<1> * Prints [F1V1][F1V2]
DYNARRAY<10> = '[F10]' * Adds a string of field marks to position [F10] in
field 10
PRINT DYNARRAY
* Prints
[F1V1][F1V2][F2V1][F2V2S1][F2V2S2][F10]
You can insert values into a dynamic array using the INS statement:
INS '[NEWFIELD]' BEFORE DYNARRAY<10;>

* Prints
[F1V1][F1V2][F2V1][F2V2S1][F2V2S2][NEWFIELD][F10]
Note the difference here between using INS to load field 10 and using
...<10>=.... A simple assignment would have overwritten the value in field
10. INS actually inserts a new field at that position, pushing the value [F10]
out into field 11.
PRINT DYNARRAY

You can also delete values using DEL:


DEL DYNARRAY<10;>
PRINT DYNARRAY ; * Prints

[F1V1][F1V2][F2V1][F2V2S1][F2V2S2][F10]
The string F10 is now back in field 10.
If you wish to find a string within your dynamic array, you can do so using the
LOCATE statement:
* Finds [F10] at field number 10 and prints '10'

LOCATE '[F10]' IN DYNARRAY<1> SETTING POSITION THEN


PRINT POSITION
ELSE
PRINT 'Not found'
END

Note the <1> after the DYNARRAY array name in this code. This indicates
that the search should begin with field 1, but more importantly it indicates
that the string being searched for is a complete field. Compare the following:
* Fails to find [F1V2] because it is not a complete field, and prints 'Not found'
LOCATE '[F1V2]' IN DYNARRAY<1> SETTING POSITION THEN
PRINT POSITION
ELSE
PRINT 'Not found'
END

To find [F1V2], you would have to search at value level:


* Finds [F1V2] as the second value in field 1 and prints 2
LOCATE '[F1V2]' IN DYNARRAY<1,1> SETTING POSITION THEN
PRINT POSITION
ELSE
PRINT 'Not found'
END

The <1,1> not only defines the starting position for the search, it indicates
that the search must find a value within field 1. The general principle remains
that you can only search 'one level down': you can search an entire dynamic
array for a complete field, a field for a value, or a value for a subvalue. As the
result is returned as a single number and not a set of coordinates, it could not
be otherwise. How would LOCATE report finding [F1V2] in field 1, value 2, by
returning a single number?
LOCATE really comes into its own, however, when dealing with a field only list
(containing no values or subvalues): particularly if the fields are in sorted
order. Consider the following:

NEWARRAY = 1 : @FM : 2 : @FM : 4 : @FM : 5


LOCATE 5 IN NEWARRAY<1> BY 'AR' SETTING POSITION ELSE PRINT '5 absent' ;

* Prints nothing

PRINT POSITION ;

* Prints 4

LOCATE 3 IN NEWARRAY <1> BY 'AR' SETTING POSITION ELSE PRINT '3 absent'

* Prints '3 absent'


PRINT POSITION ; * Prints 3

First, to explain the BY 'AR' clause. This optional clause informs LOCATE that it
is dealing with a sorted list: the AR denotes the sort order: ascending rightjustified. AL stands for ascending left justified, DR for descending right
justified, and DL for descending left justified.
One advantage of the BY clause is that it can speed up your search. If your
list is sorted AR, and you are looking for the value 3, jBase knows that it can
give up the search as soon as it reaches the first string higher than 3: which it
does when it gets to 4. It therefore doesn't have to search the entire dynamic
array for a value that is not there unless the value it is looking for happens to
be bigger than all the fields already in the array.
More importantly, though, it adds an interesting twist to the action of
the SETTING clause in the case where the string searched for cannot
be found: as the variable following SETTING is set to the position the
string would have been in if it had been found. By using INS to insert
the string in this position, the dynamic array can be maintained in a sorted
order without the need for a sorting algorithm.
This is a very neat and widely used trick. The code runs as follows:
LOCATE STRING IN SORTEDARRAY<1> BY SORTORDER SETTING POSITION ELSE
INS STRING BEFORE SORTEDARRAY<POSITION>
END

This code will maintain a sorted list of STRING values automatically.

Comparison of dimensioned and dynamic arrays


From all this, it will seem that dynamic arrays are vastly more flexible than
dimensioned arrays: and they are. They are supported by a LOCATE statement, for
which dimensioned arrays have no equivalent, and allow strings to be inserted into
the middle of an array by shuffling other strings to the right, which dimensioned
arrays cannot do. They do not require each element to be initialised, do not cause
run time errors if accessed 'out of range', and do not require resizing to accomodate
more or fewer strings: all of which dimensioned arrays do. They even offer three
dimensions in place of the maximum of two dimensions supported by dimensioned
arrays.
Why, then, should one ever use dimensioned arrays? While there are several
reasons, one stands head and shoulders above the others: because they are faster.

UniVerse can address a single element in a dimensioned array almost as quickly as a


single variable. The fields, values, and subvalues of a dynamic array require clever
searches along long strings counting field, value, and subvalue markers to address.
While they are cleverly implemented, this will never be as fast as a dimensioned
array.
In general, I would make the following recommendations:
1. Where each element you are going to store has a specific and unique meaning,
and is wedded to its numeric position, use dimensioned arrays. This is precisely the
situation you are in when you read a record from a jBase data file. Field 1 of the
record may be the customer name, field to the product code, and so on. The values
of these fields do not require sorting, and it would be meaningless to 'insert'
elements into such an array. The number of elements you will require to hold the
record is not going to change during the life time of the program. All these factors
suggest dimensioned arrays as the natural home for records read into memory.
Infobasic offers two statements to read a record into memory: READ which will read
one into a dynamic array, and MATREAD which will read it into a dimensioned array.
For most data files, MATREAD is appropriate.
2. Don't store values and subvalues in dynamic arrays: store fields only. By keeping
your dynamic array structure flat, or 'one-dimensional', you allow the dynamic array
to be searched for values, you simplify the business of inserting and deleting values,
and you make your code easier to understand and maintain. Rather than creating an
array called INVOICES which stores fields, each of which has an invoice number in
value 1 and invoice value in value 2, create two dynamic arrays, called
INVOICE.NUMBERS and INVOICE.VALUES. Whenever you insert a field into one,
insert a corresponding field into the other. Whenever you delete a field from one,
delete the same field from the other. This has the added advantage that as each
dynamic array is half the size, it is far quicker to process.
3. In short, use dimensioned arrays for structures built from elements of data with
different meanings, and dynamic arrays for lists of a single entity. If you must
process lists of structures, combine the two: create a dimensioned array called
INVOICES, element one of which is a dynamic array full of invoice numbers (stored
as fields), element two of which is a dynamic array full of the corresponding invoice
values, and so on.

Introduction to SUBROUTINE and PROGRAM


There are two types of programs that we can write in Infobasic.
1. PROGRAM : executed from the database prompt
2. SUBROUTINE : executed from within T24
PROGRAM ProgramName
Statement 1
Statement 2
Statement 3
END

SUBROUTINE SubroutineName
Statement 1
Statement 2
Statement 3
RETURN

END
** Never store user written programs/subroutines in GLOBUS.BP directory
Compiling and Cataloging Routines

BASIC command is used to compile routines. When a program/subroutine is


compiled, an object code is produced in the source directory.
BASIC file.name {item.list} {(options)}

RUN command is used to run the compiled object.


RUN file.name itemID {(options)}

CATALOG command is used to catalog the object.


CATALOG file.name {item.list} {(option)}

EB.COMPILE is the core program used to compile and catalog a


program/subroutine.

Once cataloged, the program can be run like any other commands. The RUN
command can be used to run a program without cataloging, but you should
catalog your program whenever possible.

Process workflow of a CATALOG command


When a catalog command is issued for a subroutine, it will refer an environment
variable JBCDEV_LIB to obtain the path where it has to place the object file.
Whereas when a catalog command is issued for a program, it will refer an
environment variable JBCDEV_BIN. Once the path is obtained, the object code of
subroutine is placed under one of the library files under that path whereas the object
code of program is placed directly under that path.
Therefore JBCDEV_LIB directory contains a number of library files. These files are
controlled by a configuration file named jLibDefinition, which is present under jBASE
config directory (also in the $HOME/lib directory). This file specifies the naming
convention of the library files and their maximum size. jBASE decides under which
library file the object code has to reside. If none of the existing library files have
space to store a new object code, then jBASE will automatically create a new library
file.

Executables and shared library objects can be removed from the bin and lib
directories by using the DECATALOG command.

Execution of a PROGRAM OR SUBROUTINE

For Program, go to the database prompt, write the program name and press Enter
For Subroutine, login to T24, make an entry in PGM.FILE, write the subroutine name
in the command line and press Enter
Control Structure
IF THEN ELSE

It may take two different forms being single and multiple line statements.
In most cases, either THEN or ELSE must be specified.
Example:
IF AGE GT 18 THEN PRINT ADULT ELSE PRINT MINOR
IF AGE GT 18 ELSE PRINT MINOR
IF AGE GT 18 THEN PRINT ADULT
IF AGE GT 18 THEN
PRINT ADULT
END
ELSE
PRINT MINOR
END

BEGIN CASE END CASE


VAR = OPERATOR
BEGIN CASE
CASE VAR = JAVED
CRT USER JAVED IS LOGGED ON
CASE VAR = BASHAR
CRT USER BASHAR IS LOGGED ON
CASE 1
CRT UNKNOWN USER
END CASE

FOR LOOP
FOR COUNTER=1 TO 10
CRT COUNTER - : COUNTER
NEXT COUNTER

LOOP
LOOP

REPEAT

CRT INPUT A NUMBER


INPUT VAR
WHILE VAR
CRT NUMBER FOUND

** The condition is held in the WHILE or UNTIL clause. In case of WHILE, NUMBER
FOUND will be displayed if VAR contains a value. But in case of UNTIL, NUMBER
FOUND will be displayed if VAR contains no value.

Built In Infobasic Functions

LEN
o

VAR = LEN(PRIME)

COUNT
o

Return the number of delimeters


VAR = ABC@VMDEF@VMGHI
I = COUNT(VAR,@VM)

DCOUNT
o
Return the number of records
VAR = ABC@VMDEF@VMGHI
I = DCOUNT(VAR,@VM)

UPCASE
o

DOWNCASE
o

VAR = CHANGE(PRIIME,II,I)

OCONV
o
Output conversion
o

VAR = DOWNCASE(PRIME)

CHANGE
o

VAR = UPCASE(prime)

DATE = OCONV(TIME(),MTS)

ICONV
o
o

Input conversion
TIME = ICONV(Y.TIME,MTS)

Insert Files

I_COMMON
o
Defines all the common global variables that can be used across
subroutines.

I_EQUATE
o
Initializes all the common variables

Some common variables get loaded when a user signs on while some
variables get loaded while opening specific applications or performing specific
actions.

These files are available in GLOBUS.BP directory

It is a good practice to include these files in each subroutine irrespective of


their uses.

Examples include COMI, ID.NEW, R.USER, OPERATOR, APPLICATION,


V$FUNCTION, etc.
Open a file
OPEN FBNK.CUSTOMER // mnemonic hard-coded
FN.CUS = F.CUSTOMER
F.CUS =
CALL OPF(FN.CUS,F.CUS)
OPF takes two parameters:
Name of the file prefixed with F, and Path of the file to be opened (usually specified as )

When OPF gets executed,


the COMPANY file is read in order to obtain the mnemonic of the branch.
Then FILE.CONTROL record of the file is read to find out the type of the
file (INT,CUS or FIN).
Once the type is extracted, the F. is replaced with F.<mnemonic>. After
execution
VOC entry for the file is read and path of the data file gets populated in
the second parameter
Read a file
F.READ(<file name>,<record id>,<dynamic array containing the resultant record
delimited by field, value and sub-value markers>, <file path>, <error>)

The <error> contains null if read is successful, otherwise it will contain a


numeric value.
Extraction of values from dynamic array involves specifying the field position.
But it is always advisable to use field name instead of field position.
CRT command
Is used for display
GOSUB
Keyword used for passing control to another block of code, thereby
ensuring code modularity and better code management. Each block
has a name and has to end with a RETURN statement. After executing
of the block, control is back to the point from where it was called.

Executing subroutine from T24


An entry needs to be made in PGM.FILE with appropriate type (M, S)

Debugging program / subroutine


Insert a DEBUG statement in the routine in order to debug a program
or subroutine. Program can also be debugged from Jbase prompt by specifying Jd
option.
Debugging commands
S
V <variable name>
Q

: to execute the line


: to see the contents of the variable
: quit out of the subroutine and return to jbase prompt

Ctrl + C

: abort the subroutine

You might also like