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
     using output as file "rhyme.txt"
        submit "Mary had a little lamb."
  find ("big" | "little") => current-size 
     put #log "The current size is %"" || current-size || "%"%n"
           || "Enter the correct size: "  
     do scan #process-input
     match any-text* => correct-size "%n"
        output correct-size
  find ("Mary" | "Tom") => current-owner 
     put #log "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
  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 #log to avoid interrupting the flow of data to the current output, which is the the file rhyme.txt. #log 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)
     put #log prompt
     do scan #process-input
     match any-text* => user-input "%n"
        return user-input

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 actions to prompt the user. To make this work, #process-output must be declared unbuffered as well as #process-input:

  import "ombcd.xmd" unprefixed
  declare #process-input has unbuffered
  declare #process-output has unbuffered
  constant string prompt initial {"%ncalc> "}
  define switch function
     valid-number ()
     return #current-input matches (["+-"]? digit+ ("." digit+)?)
     output prompt
     submit #process-input
  find valid-number () => left ["+-*/"] => operator valid-number () => right "%n"
     do scan operator
     match "+"
        output "d" % (bcd left + bcd right)
     match "-"
        output "d" % (bcd left - bcd right)
     match "*"
        output "d" % (bcd left * bcd right)
     match "/"
        output "d" % (bcd left / bcd right)
   catch #program-error
     output "Invalid operation."
     output prompt
  find ul ("exit" | "bye" | "quit") "%n"
  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.