Home Why Omnibasic Features FAQ Examples
Reviews Keyword/Syntax On-Line Manual Download Manual ScreenShots

Chapter 10 Part 2

Arithmetic and Logical Functions

This group of functions includes the following:

ABS() absolute value of integer or float
MOD() remainder of integer divide
LAND() bitwise logical AND of two integers
LOR() bitwise logical OR of two integers
LXOR() bitwise logical Exclusive OR of two integers
LNOT() bitwise logical complement of integer
NOT() complement of Boolean value
RND() Random Number

The ABS() function returns the absolute (unsigned) value of either an integer or floating point expression and returns either an integer or floating point result as appropriate.

The MOD() function divides Expr1 by Expr2 (both are integer expressions) and returns the integer remainder. This is useful for determining whether a number is odd or even as well as other uses.

The bitwise logical functions ( LAND(), LOR(), LXOR(), AND LNOT() ) are useful for setting, clearing, and testing bits within an integer value.

The NOT() function is used to complement a Boolean value. (TRUE becomes FALSE and FALSE becomes TRUE.)

Some examples follow:

DIM A$:STRING[1]
DIM A:BYTE
Start
   GET #0,A$\ get character from keyboard
   A=ASC(A$)\ convert to ASCII code
   IF A>+$41 AND A<=$5A\ check for upper case letter
      A=LOR(A,$20)\ force to lower case
   ENDIF
GOTO Start

DIM A:INTEGER
DIM B:INTEGER
Start
   INPUT “Enter value >”,A
   B=ABS(A)\ get the absolute value of A
   WHILE NOT(EOF(#FileNum)) DO
      READ #FileNum,Text
      PRINT Text
   ENDWHILE

Conversion Functions

This group of functions includes the following:

VAL() numeric value of string
IVAL() integer value of string
FVAL() floating point value of string
STR$() string value of integer or float
ZSTR$() string value of integer or float with padded zeros
INT() integer value of float
ASC() ASCII code of first character in string
CHR$() character representation of ASCII code
HEX$() hexadecimal value of integer
ZHEX$() hexadecimal value of integer with padded zeros
TRIM$() string without trailing spaces

The result of the VAL() function may be either integer or float depending on the context as determined by the expression evaluator. The IVAL() and FVAL() functions force either an integer or floating point result respectively.

The STR$() function converts a numeric value into string representation. In fact, when printing numeric values, the compiler calls this function itself.

The INT() function removes the fractional part of a floating point number and returns only the whole number remaining.

The ASC() and CHR$() functions are complementary to one another and are used for various purposes such as outputting non-printable characters.

The HEX$() function returns the hexadecimal value of an integer in string format with leading zeros suppressed.

The TRIM$() function removes trailing spaces from a string.

Some examples:

A=VAL(“1234”)
A$=STR$(22.3)
A$=TRIM$(A$)
PRINT CHR$($07)\ “rings” bell on terminal
A=ASC(A$)
DIM A$:STRING[26]
DIM I:BYTE 
FOR I=1 to 26
   MID$(A$,I,1)=CHR$(I+$40)
NEXT I

The last example “builds” a string consisting of the 26 letters of the alphabet.

Transcendental Mathematical Functions

This group of functions accept as arguments either integer or floating point expressions and render a floating-point result. The geometric functions (SIN(), COS(), etc) give their result in radians.

The functions provided are:

SQR() square root
SIN() sine
COS() cosine
TAN() tangent
ASN() arc sine
ACS() arc cosine
ATN() arc tangent
LOG() natural log
LOG10() common log

An example follows:

DIM I:LONG
X=I
IF SQR(X)=INT(SQR(X)) THEN
   PRINT SQR(X)
ENDIF
NEXT I

The example program will print out the integer square roots of all values from 1 to 1000.

Clock/Calendar Functions

OmniBasic supports seven Gregorian functions. Rather than condense many of these functions into one “cluster” such as DateTime() or DATE$, the functions are provided separately. A study of programs written with Basics using the “clustered” approach revealed a large amount of effort to “uncluster” the values into usable pieces. Also, if any manipulation or calculation or comparison is to be made between two or more time samples, the numeric format provided is obviously more useful than a “clustered” string approach.

The seven Gregorian functions are:

THOUR() for hours
TMIN() for minutes
TSEC() for seconds
TYEAR() for years
TMON() for month
TDAT() for date
TDAY() for day of the week (0=Sunday, 1=Monday, etc)

All of the Gregorian functions return an 8-bit integer value except TYEAR() which returns a 16-bit integer value. An example follows:

Start
   PRINT “This is a weekend.”
ELSE
   PRINT “This is a week day.”
ENDIF
IF THOUR(0)>12 THEN
   PRINT THOUR(0)-12;” PM”
ELSE
   PRINT THOUR(0);” AM”
ENDIF

LEFT$(), RIGHT$(), MID$(), TAIL$()

These functions are used to extract or replace portions of strings. Unlike many Basics, OmniBasic allows these functions to appear on the left side of the equal sign in LET statements. This is what allows the replacement function.

The LEFT$() function specifies the beginning character of the string through arg2 characters. For example:

B$=LEFT$(A$,2)

Sets B$ to the first 2 characters of A$.

The RIGHT$() function specifies the last arg2 characters of the string. For example:

B$=RIGHT$(A$,3)

Sets B$ to the last 3 characters of A$.

The MID$() function specifies the portion of the string beginning with arg1 through arg2 characters. For example:

B$=MID$(A$,3,2)

Sets B$ to the third and forth characters of A$.

More examples:

A$=”123456789”
MID$(A$,3,2)=”xx”
PRINT A$

Outputs: 12xx56789

A$=”123456789”
PRINT MID$(A$,8,22)

Outputs: 89

A$=”123456789”
PRINT LEFT$(A$,3)

Outputs: 123

A$=”123”
MID$(A$,6,2)=”xx”
PRINT A$

Outputs: 123

In the last example it appears that the MID$() had no effect. This is because the assignment occurred after the internal “end marker” of the string. Keep this in mind when using these functions on the left side of the equal sign in LET statements.

TAIL$(A$,2) returns the contents of A$ starting at position 2 through the remainder of A$.

EOF(), LEN(), TAB(),SIZE(), ADDR()

The EOF() function is used to check for an end-of-file condition of a file. The general syntax of this function is as follows:

EOF(#PathNum)

The EOF() function returns a boolean result (TRUE or FALSE).

The LEN() function is used to determine the actual or working length of a string variable. The general syntax is as follows:

LEN(StringVar)

The LEN() function returns an integer result of the string length.

The TAB() function returns no value, but rather, sets the print position to the integer expression value of the argument. The general syntax is as follows:

TAB(IntExpr)

The SIZE() function is used to determine the size (in bytes) of the variable referenced in the argument. This is especially useful in the case of user-defined types in which the compiler may have added “pad” bytes to force even byte alignment such that simply adding the elements of the type will not render a correct size. The general syntax is as follows:

SIZE(VarName)

The SIZE() function returns an integer result in bytes of variable size.

The ADDR() function is used to determine the absolute physical address of the argument variable in the system’s memory. This is especially useful in conjunction with setting pointers to variables and has other uses as well. The general syntax is as follows:

ADDR(VarName)

The ADDR() function returns an integer value of the argument variable’s memory address.

PEEK(), POKE

The PEEK() function and POKE statement are included only for completeness and to provide a measure of compatibility with existing programs being converted to OmniBasic. With the full range of pointer capability built into OmniBasic, there is never really a need to use this pair of tools. Therefore, the use of the PEEK() function and POKE statement is discouraged. Also, with the capability to use C statements at will, it is more efficient to use an assignment statement.

The PEEK() function returns a byte value from the memory location addressed by the argument. An example of the use of the PEEK() function with pointer alternative follows:

DIM A:INTEGER
DIM B:BYTE
Start
   A=$FF0000
   B=PEEK(A)

DIM A:BYTE POINTER
DIM B:BYTE
Start
   A=$FF0000
   B=[A]

The POKE statement stores the second argument into the address specified by the first argument. The general form of the POKE statement is as follows with examples and alternative:

POKE Expr1,Expr2

Start
   POKE $FF0000,55

DIM A:INTEGER POINTER
Start
   A=$FF0000
   [A]=55

SHELL, END, REM, BASE, DECIMALS, DIGITS

The SHELL statement starts a shell and passes the argument to that shell. This allows a program to initiate a host of system functions for the user. An example follows:

SHELL “dir”

This will output directory to display on the standard output path.

The END statement is used to end the program.. As many END statements may be used as desired. After the last line of the program, the compiler generates code equivalent to an END statement if none exits. The effect of the end statement is to return control to the process that initiated the Basic program. An example follows:

ON ERROR GOTO TRAP1.
TRAP1
   PRINT “ERROR #”;ERR
END

The REM (remark) statement is used to add comments or remarks to a program. The REM statement generates no code and therefore does not affect the compiled program’s size. The generous use of REM statements is encouraged to increase readability of the program. An asterisk (*) or single quote (‘) character in column one of the source line has the same effect as a REM statement. For example:

REM This is a remark

The BASE statement allows the referencing of arrays with either a base of 0 or 1. The default value is 1. Using a base of 1 is more common and thus more likely to be compatible with programs written for another Basic. Base 0 is slightly more efficient because there is no need to adjust the base when calculating array subscripts. For example:

BASE 0
BASE 1
REM Using both BASE 0 and BASE 1 in the same program could be disastrous!

The DECIMALS statement is used to set the number of decimal places on the right side of the decimal point for floating-point calculations and manipulation. The default value is 2. The DIGITS statement is similar to DECIMALS, but specifies total digits up to 15. The default for DIGITS is 15. For example:

DIM A:FLOAT
Start
   DECIMALS 3
   DIGITS 8
   A=4
   PRINT A

Prints the following: 4.00

CREATE, OPEN, CLOSE

The CREATE statement is used to create a file on a mass storage device and to open that file. The OPEN statement is used to open a file on a mass storage device or to open a device for input/output operations. The CLOSE statement is used to close one or more paths or mass storage files. The CREATE and OPEN statements also specify the access mode such as READ, WRITE, or UPDATE. The initial length of a newly created mass storage file is set to 0. Attempting to create a file already in existence or opening/closing a file not in existence will cause a system error to occur. This error may be trapped with an ON ERROR GOTO statement. Only one file/device may be opened or created on one statement while multiple files/devices may be closed with one statement. Access mode may be READ, WRITE, or UPDATE. An access modifier +DIR, +BINARY, or +TEXT may follow. On MSDOS, TEXT is the default. The general syntax of the CREATE and OPEN statements is as follows:

CREATE #FileNum,”FileName”:AccMode

The file number (FileNum) must be a BYTE variable, which will receive the path number from the system. The file name (FileName) may be a string variable or string constant (quoted string) and describes either the file name on a mass storage device or the device name of a device. The access mode (AccMode) is used to set up the type of operation(s) allowed.

The General syntax of the CLOSE statement is as follows:

CLOSE #FileNum,...,FileNum

One or more files/devices may be closed on one CLOSE statement. Once a file or device is opened or created, the various file read/write statements may operate on the data to/from these files/devices such as READ, WRITE, PRINT, INPUT, GET, PUT, BUFREAD, BUFWRITE, etc. When these read/write statements operate on these files/devices they use the FileNum variable to refer to the file/device. The read/write statements may also use a BYTE constant to refer to a device. The use of constants is usually done on the standard I/O devices, which are opened by the system (don’t need an open statement). These are standard input (0), standard output (1), and standard error output (2).

These statements may be prefixed with STATUS: which circumvents the normal error trapping and allows examination of the STATUS variable.

An example of using one of the standard devices already opened by the system (Linux) follows:

#SET Keyboard=0
DIM InpData:STRING[1]
Start
GET #Keyboard,InpData

An example of opening a file for read and reading data from the file follows:

DIM A$:STRING
DIM InpFile:BYTE
START
   OPEN #InpFile,”MyFile”:READ
   READ #InpFile,A$

GET, PUT, BUFREAD, BUFWRITE

These groups of statements read and write unformatted (raw) data to and from files and devices. In the case of the GET and PUT statements, whole variables or arrays are read or written and in the case of string variables the entire variable is read or written regardless of the working length of the string. Numeric data is not converted to ASCII format. In the case of the BUFREAD and BUFWRITE statements, data is transferred to/from the device/memory according to the memory address and byte count specified. This allows transfers to/from memory buffers and also allows the reading and writing of multiple variables with one statement provided the variables are dimensioned in the appropriate order.

All of these statements represent the most efficient transfer of data in terms of time since no intermediate buffer is required and one statement reads or writes as many bytes as desired.

These are also the statements, which must be used for random access of mass storage files. In conjunction with the SEEK statement and (optionally) the FILPOS() function, byte addressability and thus random access of a mass storage file is accomplished.

The GET and the BUFREAD statements are also useful for getting a single character from the keyboard without requiring an “enter” (carriage return) from the user.

As with all statements of the read/write class, the special variable XferCount may be used to determine exactly how many bytes were transferred after the operation.

The use of the READBUF and WRITEBUF require knowledge of the data structure(s) involved and careless or casual use may result in unpredictable results or even a system “crash”. For example, do not read in more bytes than the size of the variable or array you are trying to assign some data unless you understand that the variable(s)/array(s) following will be assigned subsequent excess data. If more bytes are specified than there is dimensioned variable space or requested memory buffer, the data read in may clobber someone else’s data or program space.

The general form of the GET and BUFREAD statements follow. The PUT and BUFWRITE statements follow the same form.

GET #FileNum,VarName
BUFREAD #FileNum,VarAddr,VarSize

FileNum is a variable or constant, which refers to the path number of the device or file. VarName refers to the variable name being read into. VarAddr refers to the address of the variable or memory buffer being read into. VarSize refers to the number of bytes to be read.

In the following program the GET and BUFREAD statements are equivalent:

DIM A(10):LONG
DIM InpFile:BYTE
Start
   OPEN #InpFile,”TestFile”:READ
   GET #InpFile,A
   BUFREAD #InpFile,ADDR(A),SIZE(A)

READ#, WRITE#

These statements are specifically designed to read and write single string variables to and from memory and a mass storage device. Among the features of this approach is that commas may be written and read just as any other character. On other Basics, the reading of a comma stops the reading process. If the program is, for example, to read and process a text file (such as the Innomation Systems, Inc.’s BASIC Compiler must routinely do) then terminating a read each time a comma is encountered is unacceptable. Another desirable feature is that the READ statement requires no intermediate buffer and is thus more efficient. Also, only the actual working length is transferred which saves time and mass storage space. This is useful for sequential access files but not random access. When writing a string to the mass storage device, a carriage return is appended (if not already present in the string) to the end of the string and the write is terminated. When reading, the operation is terminated when a carriage return is encountered or the dimensioned size of the string is reached, whichever occurs first. Elements of string arrays may also be read and written, but not the whole array as in the GET and PUT statements. Reading and writing numeric data types must be accomplished with the GET/PUT, FINPUT/ FPRINT, or READBUF/WRITEBUF statements.

The general syntax of the READ statement is as follows:

READ #FileNum,StringVar

FileNum is the BYTE variable used to hold the path number when previously opening the file. StringVar is the string variable being read into from the mass storage device.

The general syntax of the WRITE statement is as follows:

WRITE #FileNum,StringVar

In the following example, a text file (such as from an editor) is read one line at a time and output to the CRT.

DIM Text:STRING[200]
DIM InpFile:BYTE
Start
   INPUT “Enter File Name >”,Text
   ON ERROR GOTO ReportErr
   OPEN #InpFile,Text
   ON ERROR
   WHILE NOT(EOF(#InpFile)) DO
      READ #InpFile,Text
      PRINT Text
   ENDWHILE
END
ReportErr
PRINT “Cannot open”;Text

As with all statements of the read/write class, the special variable XferCount may be used to determine exactly how many bytes were transferred after the operation.

INPUT, FINPUT, PRINT, FPRINT

These statements are used to communicate with the outside world in an ASCII string format. The INPUT statement has two forms, which differ in the prompt issued to the user. The general syntax of each form follows:

INPUT Var
INPUT “Custom Prompt”, Var

In the first case, the stdout device will show a “?” prompt awaiting user input. In the second case, what ever is enclosed in the quotes will be displayed as a prompt.

A CARRIAGE RETURN terminates input. (ENTER on some keyboards).

Also an optional argument is #PathNum where PathNum is a path number or path variable.

INPUT #Switches,Var

The FINPUT statement is identical to the INPUT statement except that no prompt is issued.

The PRINT statement allows the outputting of variables or expressions and will (unless otherwise instructed) issue a CARRIAGE RETURN followed by a LINE FEED. The variables or expressions must be separated by either a comma or semicolon. If a comma is used as a separator, the output will be padded with spaces (tabbed) to the next position evenly divisible by 16. If a semicolon is used, the next variable or expression will be immediately following. If a comma or semicolon is used as the last argument of the PRINT statement, the CARRIAGE RETURN and LINE FEED will be inhibited. All non-string variables and expressions are automatically converted to string format (ASCII) before being output. Boolean variables are converted to TRUE or FALSE strings. The general syntax is as follows:

PRINT Expr,Expr,...Expr

Also an optional argument is #PathNum where PathNum is a path number or path variable.

PRINT #PathNum,Expr

The FPRINT statement is identical to the PRINT statement except that only one variable or expression is allowed, no separators are allowed, and only the CARRIAGE RETURN is output (no LINE FEED).

All of the statements on this page use a memory buffer, which at the time of this writing is set to a size of 500 bytes. Any data element exceeding this size will be truncated at the buffer size! To input or output data in excess of the buffer size, use one of the other types of I/O statements such as READ/WRITE, GET/PUT, or BUFREAD, BUFWRITE. Since PRINT and INPUT use this buffering, they are slower in operation than the other I/O statements mentioned.

SEEK, FILSIZ(),FILPOS(), DELETE

The SEEK statement is used to position is used to set the file pointer address for the path specified. This is used to randomly access files and is normally used in conjunction with the GET, PUT, BUFREAD, and BUFWRITE statements in this regard. Note that the SEEK statement may seek to an absolute position or a position relative to its current position by using the FILPOS() function. The ability to do a relative seek allows one to effectively “unread” data by positioning back to the beginning of that data. The FILSIZ() function simply returns the size of the file specified by Path Number. By comparing the values returned by the FILSIZ() and FILPOS() functions, it is possible to know how much of a file is left to read. The DELETE statement is used to delete a file,by-file name.

The general form of the SEEK statement is as follows:

SEEK #PathNum,NumExpr

The general form of the DELETE statement is as follows:

DELETE FileName

The general form of the FILSIZ() and FILPOS() functions is as follows:

FILSIZ(#PathNum)
FILPOS(#PathNum)

Examples of deleting a file are:

DELETE “OldFile”

Or

DIM A$:STRING[28]
Start
   INPUT “Enter file to delete >”,A$
   DELETE A$

An example using the SEEK statement and the FILSIZ() and FILPOS() functions follows:

DIM InpFile:BYTE
Dim Temp:BYTE
Start
   OPEN #InpFile,”TestFile”
   REM seek to middle of file
   SEEK #InpFile,FILSIZ(#InpFile)/2
   REM seek to previous byte
   SEEK #InpFile,FILPOS(#InpFile)-1

BITCHG(), BITCLR(), BITSET(), BITTST(), SHL(), SHR(), ROL(), ROR()

This group of functions is provided to allow the manipulation and testing of individual bits within variables and the shifting and rotating of integer type variables.

All of these functions take the same general form:

FuncName(IntVar,IntConst)

Where FuncName is the function desired, IntVar is an integer type variable (INTEGER, SHORT, or BYTE), and IntConst is an integer constant (which includes named compiler variables).

The IntConst argument for the BITXXX functions is the bit number to be manipulated or tested. The bit numbers are numbered starting with bit 0 for the LSB. The highest bit number for a BYTE is 7, for a SHORT is 15, and for a LONG (INTEGER) is 31. The IntConst argument for the shift/rotate functions is the number of bit positions to shift/rotate. The maximum number of bits to shift/rotate at one time is 8. The IntConst argument is checked for type but not for value so inappropriate values may result in an assembler error when compiling.

The shift functions are logical shifts in which a 0 bit is shifted into the LSB on SHL() and into the MSB on SHR(). In the rotate functions (ROL, ROR), the MSB and LSB are “connected” for a circular effect.

These functions are not found in other Basics but are very powerful and useful in almost any application and are much more efficient than alternatives involving the LAND() and LOR() functions.

The BITTST() function returns a result of type BOOLEAN and is normally used as a compare expression in a control structure such as IF, WHILE, UNTIL, or EXITIF.

Some examples:

BITSET(Test,3)\ turns on bit 3 of variable Test
BITCLR(Test,0)\ turns off bit 0 of variable Test
BITCHG(Test,12)\ reverses bit 12 of variable Test
IF BITTST(Test,3) THEN\ tests bits 3 of variable Test
Test=SHL(Test,2)\ shifts the contents of Test 2 places left (same as Test=Test*4)

EXCHANGE (SWAP), PRINT USING, SUBSTR()

The EXCHANGE (alias SWAP) statement is used to exchange to variables of the same type and size. This is useful in performing sorting operations. For example:

DIM A$:STRING[40]
DIM B$(100):STRING[40]
Start
   ...
EXCHANGE a$,B$(22)

Whole arrays may also be exchanged as well as variables of user defined data types. It should also be mentioned here that whole arrays might also be transferred as well as exchanged.

PRINT USING allows formatted output. The arguments to the PRINT USING statement consist of the format (or template) (first arg) followed by one or more “filler” arguments. The “filler” arguments may be constants or variables and are used to fill the “fields” of the format (or template). The field operators are < for left justified, > for right justified, and ^ for centered. The fields are defined as contiguous occurrence of one of the field operators. For example, <<<< indicates a left justified field of up to 4 characters. Characters other than the three field operators in the format argument are taken as literal string characters. For example:

DIM Template:STRING[80]
DIM A:FLOAT
Start
Template=”>>>>>>> dollars”
A$=1.11
PRINT USING(Template,A$)

Will print the “1.11” right justified followed by the word “dollars”.

The SUBSTR() function is used to find a string in a string. The general syntax is:

SUBSTR(Str1,Str2<,Pos>)

Where Str1 is the string to be searched for in Str2. If Str1 is found in Str2, the SUBSTR() function returns the starting position of Str1 in Str2. If it is not found, a 0 is returned. The optional Pos argument specifies the position in the string to start the search. The default is position 1.

CASE$(), LCASE$(), MAKEUPPER, MAKELOWER

UCASE$() returns a string converted to uppercase. Correspondingly LCASE$() returns a string converted to lower case. The current implementation sets a limit of 500 bytes string size for the conversion. The syntax is:

UCASE$(StrVar) and LCASE$(StrVar)

MAKEUPPER and MAKELOWER correspond to the two functions (UCASE$(), LCASE$()). The syntax is:

MAKEUPPER StrVar and MAKELOWER StrVar

There is no limit on the string size here. The string is converted in place, which makes these statements faster than the corresponding functions.

DIM A$ AS STRING * 28
A$=”Test”
PRINT UCASE$(A$),LCASE$(A$)
'Prints: TEST test

FILL, INIT, FINDADDR ( ), FINDOFFS ( )

The syntax for FILL is:

FILL Addr, Quan [, Pattern]

FILL places the pattern ‘Pattern’ in memory starting at Addr for Quan byte locations. If the ‘Pattern’ argument is missing, 0’s are the pattern. Use this statement with caution as FILLing carelessly can result in destruction of data and/or system crashes.

The syntax for INIT is:

INIT VAR [, Pattern]

The INIT statement is similar to the FILL statement except that the parameters are obtained from the Var parameters rather than explicit arguments. INIT is much safer to use than FILL for this reason.

If Var is a Buffer that has been opened, the pattern will be written into the buffer from BUFADR(BufName) for BUFSIZ(BufName) byte locations. If the buffer BufName has been closed (BUFFER BufName = 0), INIT BufName will cause unpredictable (probably disastrous) results.

The syntax for FINDADDR() and FINDOFFS() is:

FINDADDR(Addr, Quan, Pattern)
FINDOFFS(Addr, Quan, Pattern)

Both functions work the same except that FINDADDR returns the address of the first byte location, which matches ‘Pattern’ while FINDOFFS returns the offset from ‘Addr’. Both functions search for a byte match of ‘Pattern’ starting at ‘Addr’ for ‘Quan’ bytes.

Next Page: Chapter 11
Table of Contents

Home || Why Omnibasic || Features || FAQ || Examples
Reviews || Links || Privacy Statement || Top of Page

 

   Innomation Systems, Inc.

117 Morrison Ave. Morrison, MO 65061 (573) 294-6130

OmniBasic is a trademark of Innomation Systems, Inc., other trademarks are the property of their respective owners.
Innomation Systems, Inc. reserves the right to change prices and specifications without prior notice.
Copyright © 2000, 2001, 2002 Innomation Systems, Inc.