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.