User input, receiving

You can receive user input while your program is running by scanning #process-input. #process-input represents standard input, which, by default, is the keyboard. In order to receive the user's input as it is typed, you must turn off the buffering that OmniMark performs on #process-input. You do this with the declaration declare #process-input has unbuffered.

To prompt the user, you output a prompt and then scan #process-input, as in the following program. Note that you can scan #process-input as many times as you need to:

  declare #process-input has unbuffered
  
  process
     using output as file "rhyme.txt"
     submit "Mary had a little lamb."
     
  find ("big" | "little") => current-size 
     
      put #error 'The current size is "'
              || current-size || '"%n'
              || "Enter the correct size: "  
     do scan #process-input
        match any-text* => correct-size "%n"
          output correct-size
     done     
  
  find ("Mary" | "Tom") => current-owner 
     
      put #error 'The current lamb owner is "'
              || current-owner || '"%n'
              || "Enter the correct owner: "  
     do scan #process-input
        match any-text* => correct-owner "%n"
          output correct-owner
     done  
        
  find any => character
     output character   

This program will create the file rhyme.txt with the revised version of the input rhyme. In this program, the prompt was sent to #error to avoid interrupting the flow of data to the current output, which is the the file "rhyme.txt". #error is useful for prompting because it is not buffered, meaning that the prompt is sent directly to the screen without delay.

If you need to prompt the user repeatedly, you can create a function to prompt for user input:

  define string function get-user-input 
   value string prompt
   as
     put #error prompt
     do scan #process-input
        match any-text* => user-input "%n"
           return user-input
     done  

You can also carry on a conversation with the user in a single scan. Here is a program that implements a simple calculator. The program evaluates each expression that the user enters and outputs the answer. Because there is no other output going on, the program uses simple output statements to prompt the user. To make this work, #process-output must be declared unbuffered as well as #process-input:

  declare #process-input has unbuffered
  declare #process-output has unbuffered
  global stream prompt initial {"%ncalc> "}
  import "ombcd.xmd" unprefixed
  macro valid-number is 
     (["+-"]? digit+ ("." digit+)?)
  macro-end
  
  process
     output prompt
     submit #process-input
     
  find 
   valid-number => num1
   ["+-*/"] => operator
   valid-number => num2
   "%n"
       
     do scan operator
        match "+"
           output "d" % (bcd num1 + bcd num2) || prompt
        match "-"
           output "d" % (bcd num1 - bcd num2) || prompt
        match "*"
           output "d" % (bcd num1 * bcd num2) || prompt
        match "/"
           output "d" % (bcd num1 / bcd num2) || prompt
     done     
  
     catch #program-error
          output "Invalid operation." || prompt
     
  find ul ("exit" | "bye" | "quit") "%n"
     halt
     
  find any-text* "%n"
     output "Invalid input." || prompt

Note that this technique for getting user input will not work if your OmniMark program is called by another process which binds standard-input. In this case, #process-input will represent data passed from the calling process and not the input from the keyboard.

Other methods of getting user input include the use of HTML forms talking to CGI programs written in OmniMark and network clients talking to servers written in OmniMark.