swirl Guide to OmniMark 5   OmniMark home
docs home 
IndexConceptsTasksSyntaxLibrariesOMX VariablesErrors
 
    Related Syntax  
Output

Output in OmniMark is part of the streaming architecture of the language. Data is processed as it streams and all streaming data has a source and a destination. Within an OmniMark program, the source of streaming data is always the current input scope, and the destination is always the current output scope. To direct output to a particular destination, such as a file, you must attach the file to an OmniMark stream variable and make that stream variable part of the current output scope.

In order to direct output to a particular destination, therefore, you must do the following:

  1. create a stream variable as a conduit for your output
  2. attach a data destination to that stream
  3. create an output scope and make that stream part of the output scope

Once you do this, all output in your program will go to the destination attached to your stream. This program shows how this works:

  process
     local stream out-file
     open out-file as file "out.txt"
     using output as out-file
      submit "in.txt"

  find "$" digit+ => dollars "." digit{2} => cents
     output dollars || "," || cents || "$"

Here is how this code accomplishes the steps outlined above:

  1. The code local stream out-file creates a stream variable called "out-file".
  2. The code open out-file as file "out.txt" attaches the file "out.txt" to the stream out-file.
  3. The code using output as out-file creates an output scope and places the stream out-file in that scope.

The output scope created by using output as out-file exists for all code governed by the using statement. In this case, that code is the submit statement on the next line. The submit initiates scanning by find rules. Therefore, any data that streams to output during the submit flows to that output scope. Any find rules that fire as a result of the submit are inside the output scope of the sumbmit, so any output they generate goes to the output scope.

The find rule itself does not specify where its output goes. It simply goes to the current output scope.

This separation between the business of generating output and the business of deciding where output goes is fundamental to OmniMark. It allows you to write code to create output and call that code from many different places. Each place you call that code from can first establish an appropriate current output scope. The code that generates output is highly reusable because it operates completely independently of where the output is going.

The role of streams

Notice in the code above that the open statement is opening a stream and attaching that stream to a file. It is not opening the file. It is OmniMark's job to actually open the file and write to it. In some cases, OmniMark may not open and write to the file until much later. Data destinations are always abstracted either by OmniMark itself or by an OMX component. In your program you write only to OmniMark streams (by making them part of current output and writing to current output). You never write directly to a destination. You do not need to know any of the details of how a stream is attached to a destination or what kind of destination it is attached to.

The consequence of this is that there is exactly one output mechanism in OmniMark that applies to all output operations. This means that all OmniMark keywords that create output use the same mechanism and thus can all work on the full range of output destinations from buffers, to files, to network data streams.

Equivalence of output operations

OmniMark has three operations that create output:

You can use any one of them to write to any output destination. For example, you can use set to place a value in a file:

   set file "mary.txt" to "Mary had a little lamb" 

Conversely, you can use output to write a value to a variable:

  open Mary as buffer
  using output as Mary
   do
     output "Mary had a little lamb"
     output "Its fleece was white as snow"
     output "And everywhere that Mary went"
     output "The lamb was sure to go"
  done

This is much more efficient than writing:

  set Mary to "Mary had a little lamb"
  set Mary to Mary || "Its fleece was white as snow"
  set Mary to Mary || "And everywhere that Mary went"
  set Mary to Mary || "The lamb was sure to go"

This is a powerful feature of OmniMark. It enables you to choose the type of data assignment mechanism appropriate to the scale of operation you want to perform. You can use set for any kind of small-scale assignment, whether to a file or a variable, without any of the bother of opening files or buffers. For large-scale operations, you can use output and perform multiple updates without the need to specify the destination, or even worry about the kind of destination involved. Choosing the method appropriate to the scale of operation you are performing will greatly simplify your code.

Default output and the #main-output stream

An OmniMark program starts with a default output scope with a default stream attached to a default destination. The name of the default stream is #main-output and its default attachment is standard output (stdout). stdout is the screen, unless it is redirected by a calling process, such as a web server (which binds stdout to itself when launching a CGI script).

This means that if you create an OmniMark program that does not direct its output in any way, the output will appear on the screen:

  process
     output "Hello world%n"

You can change the attachment of #main-output on the command line using the -of command line option. This attaches #main-input to the file named in the -of parameter. This allows you to write programs in OmniMark without specifying their output, and specify the output file on the command line when you run the program.

If #main-input is redirected in this way, you still have access to stdout through the built-in stream #process-output, which is permanently attached to stdout.

Changing the destination of the current output scope

The statement using output as both establishes a new output scope and places streams in that output scope. However, you can change the streams in the current output scope without creating a new output scope. To do this, you use the output-to command:

  process
     local stream foo-file
     local stream bar-file
     open foo-file as file "foo.txt"
     open bar-file as file "bar.txt"
     using output as foo-file
      do
        output "one"
        output-to bar-file
        output "two"
      done

The code above changes the stream in the output scope created by the using output as statement from foo-file to bar-file.

Output to multiple destinations

It is possible to send output to multiple destinations simultaneously by placing more than one stream in the current output scope:

  global stream my-file
  global stream my-buffer

  process
     open my-file as file "myfile.txt"
     open my-buffer as buffer
     using output as my-file & my-buffer
      submit "Mary had a little lamb"

Referencing the streams in the current output scope

You can refer to the streams in the current output scope with the keyword #current-output. For instance, this code uses #current-output to add a new stream to an existing output scope:

  global stream my-file
  global stream my-buffer

  process
     open my-file as file "myfile.txt"
     using output as my-file
      submit "Mary had a little lamb"

  find "had"
     open my-buffer as buffer
     output-to my-buffer & #current-output
     output "I've been had!"

This code will place "I've been had!" in both the file "myfile.txt" and the variable my-buffer.

      Related Syntax
   open
   output
   output-to
   put
   using output as
 
----

Top [ INDEX ] [ CONCEPTS ] [ TASKS ] [ SYNTAX ] [ LIBRARIES ] [ OMX ] [ OMX ] [ ERRORS ]

Generated: August 11, 2000 at 3:06:25 pm
If you have any comments about this section of the documentation, send email to docerrors@omnimark.com

Copyright © OmniMark Technologies Corporation, 1988-2000.