Previous chapter is Chapter 1, "About This Manual".
Next chapter is Chapter 3, "The C Interface to External Functions".
The external function API is designed to let OmniMark programmers use external functions without any knowledge about either the API or internal operation of the external function libraries. In order to make effective use of the API, external function programmers need to know what the external functions look like to an OmniMark programmer.
OmniMark maintains data shelves in three types, counter, stream and switch, for use by OmniMark code. External functions may require data that do not fit into one of these types. OmniMark permits the creation of new types to provide external functions with the data that they require. These new types are called opaque types, because the data in an opaque type is not visible to any command in the OmniMark programming language. OmniMark programs can only modify the data in an opaque item or shelf by using SET to copy from another item or shelf of the same type, or by calling an external function to do the modification.
You can define as many different opaque data types as you need, and you can use them anywhere that you would use the OmniMark types (counter, stream and switch), Opaque data shelves and items are managed by the OmniMark shelf management facility. OmniMark will prevent a SET command from assigning one opaque type to another, just as the assignment of a counter to a switch is prevented. At the end of DO ... DONE block of code, a local opaque shelf will go out of scope, releasing resources, just like a local stream shelf.
Some external functions manipulate data, and complete all their work before they return to the OmniMark program that called them. The definition and use of these functions is identical to the use and declaration of internal functions except that:
External functions, like internal functions, can take any number and kind of arguments, or no arguments at all. External functions can return
External functions and internal functions are called the same way in OmniMark code. Use of a function depends only on the type of data returned (if any) and on the function arguments. For example, a function that returns double the value of a counter may be defined as either:
DEFINE COUNTER FUNCTION double VALUE COUNTER n AS
DO
RETURN n * 2
DONE
DEFINE COUNTER FUNCTION double VALUE COUNTER n AS "doubler" IN FUNCTION-LIBRARY "xtramath.dll"
Either function allows you to set the counter m to 15 with the code
LOCAL COUNTER m
...
SET m TO double 7 + 1
Some external functions provide a service. The work of the function is not completed by the time the function returns to OmniMark. Instead, the function installs a set of subfunctions to continue the work later, when required by the execution of OmniMark code. These external functions have no counterpart in the OmniMark internal functions.
There are currently three kinds of external function that provide services to OmniMark programs:
External outputs make it possible to output data in ways that would be more difficult, or even impossible, if you were restricted to using OmniMark code. For example, the OmniMark programming language does not provide any tools for writing data to a socket. If you write an external output that sends data to another process, you can use the external output to treat the other process as if it were an output file.
An external output, like a file or a buffer, is a data destination that can be attached to a stream item. You can therefore use the external output just like a buffer or a file to send data to the destination. You can write all your output to an external output in a single operation with a SET statement, or you can write incrementally with OPEN, PUT and CLOSE statements.
DEFINE EXTERNAL OUTPUT my-output-destination (VALUE STREAM my-info)
AS "my_output_fun""
IN FUNCTION-LIBRARY "myoutlib"
GLOBAL STREAM my-stream
PROCESS
SET my-output-destination("my info") to "This is my data"
OPEN my-stream AS my-output-destination("my info")
PUT my-stream "This is"
PUT my-stream " my data"
CLOSE my-stream
There is an important difference between a stream attached to an external output and a stream attached to a buffer. You can either overwrite the data in a buffer, or append data to the buffer, depending on the OmniMark commands that you use. An external output may be sending data to a destination that cannot be overwritten. In such cases, the SET command and the OPEN commands will both cause new data to be appended, rather than overwriting previous data.
External sources make it possible to obtain data in ways that would be more difficult, or even impossible, if you were restricted to using OmniMark code. For example, the OmniMark programming language does not provide any tools for getting data from a socket. If you write an external source that receives data from another process, you can use the external source to treat the other process as if it were an input file.
An external source function can be used like a closed stream that is attached to a buffer. It can be read all at once, with a SET statement, or you can read the source incrementally, as you would in a REPEAT SCAN statement:
DEFINE EXTERNAL SOURCE my-input-source (VALUE STREAM my-info)
AS "my_input_fun""
IN FUNCTION-LIBRARY "myinlib"
GLOBAL STREAM my-stream
SET my-stream to my-input-source("my info")
REPEAT SCAN my-input-source("my info")
MATCH "my"
OUTPUT "your"
MATCH any=text
OUTPUT "%x(text)"
AGAIN
There is an important difference between external sources and buffers. Buffers can be read more than once, but an external source may be obtaining data from a source that supplies new data on each access. Consequently, it may not be possible to use operators like LENGTH OF in any meaningful way on an external source:
LOCAL COUNTER my-length
LOCAL STREAM my-stream
SET my-length TO LENGTH OF my-input-source("my info") ;reads some data
SET my-stream TO my-input-source("my info") ;may be new data, different length
You will have to determine whether you can reread the same data on an application-specific basis, which can sometimes be tricky. For example, if you defined a function that takes a URL as an argument and returns a Web page, you would normally get the same data twice, but you would get different data if the page were updated between the two accesses. In such cases, it might be better to SET a buffer to the external source, and then work with the buffer.
Reading from an external source is like reading from a file or a buffer. OmniMark keeps requesting data, in incremental amounts, until the first request that produces no more characters, and then assumes that the end of data has been reached.
An opaque data function creates a new data type that can be used like the OmniMark types (COUNTER, STREAM, and SWITCH), except that
As an example, suppose that you want to maintain some floating point numbers, and you want to convert these numbers to and from their representation as OmniMark strings. You can declare an opaque FloatVar type, with external functions that do the translation. The following code will set the value of an item, copy that item to another item, and output that value from the second item.
DECLARE OPAQUE FloatVar ;create an opaque type
CREATED BY "CreateFloatVar"
IN FUNCTION-LIBRARY "floatvar"
DEFINE EXTERNAL FloatVar FUNCTION SetFloat
(READ-ONLY STREAM FloatVal)
AS "SetFloat"
IN FUNCTION-LIBRARY "floatvar"
DEFINE EXTERNAL STREAM FUNCTION GetFloat
(READ-ONLY FloatVar FloatVal)
AS "GetFloat"
IN FUNCTION-LIBRARY "floatvar"
GLOBAL FloatVar first-number ;create two opaque shelves
GLOBAL FloatVar second-number
SET first-number TO SetFloat("3.1415926")
SET second-number TO first-number
OUTPUT GetFloat(second-number)
OmniMark enforces type matching in the assignment of values for opaque types, just as it does for the standard OmniMark types:
GLOBAL FloatVar first-number ;two different types
GLOBAL SomeOtherVar other-data
GLOBAL SWITCH first-switch
...
SET first-number TO other-data ;This action will fail
SET first-switch TO 5 ;This action will fail
OmniMark will acquire and release resources for opaque data, and will let opaque shelves go out of scope at the appropriate times;
DO
LOCAL FloatVar first-number ;create shelf, acquire resources
...
SET first-number TO SetFloat("3.1415926")
...
DONE ;first-number out of scope, its resources are released
Next chapter is Chapter 3, "The C Interface to External Functions".
Copyright © OmniMark Technologies Corporation 1988-1999. All rights reserved.
EUM44, release 1, 1997/11/21.