I/O Operations in MUMPS
Learn console output formatting, terminal input, and sequential file I/O in MUMPS with practical Docker-ready examples using YottaDB
Input and output in MUMPS revolve around a single unifying idea: the current device. Whether you are writing to the terminal, reading a keystroke, or streaming lines to a file, you use the same three commands – WRITE, READ, and USE – and only the device changes underneath them. This device-oriented model dates back to the language’s origins on 1960s hospital terminals, but it maps cleanly onto modern files and pipes.
As an imperative, procedural language, MUMPS keeps I/O explicit and sequential. You OPEN a device, USE it to make it current, then WRITE to it or READ from it, and finally CLOSE it. The terminal (the “principal device”) is open automatically, which is why the Hello World program could WRITE without any setup. Everything else – files in particular – follows the same open/use/close rhythm.
This tutorial covers formatted console output beyond a simple string, reading input from the terminal (including timeouts and single keystrokes), and reading and writing sequential files. Every command has an abbreviation (W, R, U, O, C), and we show both forms so you can read real-world MUMPS code, which leans heavily on the terse variants.
Formatted Console Output
The WRITE command does more than print strings. It understands format control characters – ! for a new line and ?n to tab to a specific column – and MUMPS ships intrinsic functions like $JUSTIFY and $FNUMBER for aligning and formatting numbers. Because MUMPS is typeless, numbers and strings flow through WRITE identically, with numeric values rendered in their canonical form.
Create a file named ioformat.m:
ioformat ; Formatted output in MUMPS
write "=== Output Formatting ===",!
;
; ?n tabs the cursor to a fixed column, useful for tables
write "Name",?15,"Score",!
write "Alice",?15,"95",!
write "Bob",?15,"88",!
;
; Numbers are coerced to their canonical string form automatically
set pi=3.14159
write "Pi is approximately ",pi,!
;
; $JUSTIFY(value,width,decimals) rounds and right-aligns a number
write "Justified: ",$justify(pi,10,2),!
;
; $FNUMBER inserts thousands separators
write "Formatted: ",$fnumber(1234567,","),!
;
; Multiple values and arithmetic can share a single WRITE
set x=10,y=20
write "Sum of ",x," and ",y," is ",x+y,!
quit
Key points about output formatting:
!forces a new line. It can appear multiple times (,!,!) to emit blank lines.?15moves the cursor to column 15, padding with spaces. If the cursor is already past that column,WRITEdoes nothing for it.$JUSTIFY(pi,10,2)rounds3.14159to two decimals and right-justifies the result in a 10-character field, producing3.14.$FNUMBER(1234567,",")inserts commas to produce1,234,567.
Reading Input from the Terminal
The READ command pulls input from the current device into a variable. A string literal placed before the variable acts as a prompt. READ supports a timeout (var:seconds), after which it sets the special variable $TEST to indicate whether input arrived, and a single-character mode (*var) that returns the ASCII code of one keystroke without waiting for Enter.
Create a file named ioread.m:
ioread ; Reading input from the terminal
; Read a full line of text into a variable
read "What is your name? ",name
write "Hello, ",name,"!",!
;
; Read with a 5-second timeout; $TEST is 1 if input arrived, 0 if it timed out
read "Favorite number (5s): ",num:5
if $test write "You entered: ",num,!
if '$test write "Timed out - no input.",!
;
; *var reads a single keystroke and stores its ASCII code
read "Press any key to continue... ",*char
write !
write "You pressed character code ",char,!
quit
Because this program depends on live keystrokes, it needs an interactive terminal (docker run -it ...). Here is a sample session where the user types Ada, then 42, then presses the a key:
What is your name? Ada
Hello, Ada!
Favorite number (5s): 42
You entered: 42
Press any key to continue...
You pressed character code 97
Notes on terminal input:
READ namereads a full line, stopping at Enter. The prompt string is optional but idiomatic.READ num:5waits at most 5 seconds. Check$TEST('$testis the logical NOT) before trusting the value.READ *charreads one keystroke immediately and stores its numeric code –97is the ASCII value of lowercasea. Use$CHAR(char)to convert a code back to a character.
Sequential File I/O
Files are just another device. You OPEN a file with deviceparameters describing how you intend to use it (NEWVERSION to create/truncate for writing, READONLY to read), USE it to redirect WRITE/READ, and CLOSE it when finished. Switching back to $PRINCIPAL (the terminal) makes subsequent WRITEs appear on screen again. When reading, the special variable $ZEOF becomes 1 once the last READ reaches end-of-file.
Create a file named iofile.m:
iofile ; File I/O - write lines to a file, then read them back
set file="/app/notes.txt"
;
; --- Write three lines to the file ---
; NEWVERSION creates the file, truncating any existing content
open file:(newversion)
use file
write "First line",!
write "Second line",!
write "Third line",!
use $principal
close file
write "Wrote 3 lines to ",file,!
;
; --- Read the file back one line at a time ---
open file:(readonly)
set count=0
for use file read line quit:$zeof set count=count+1 use $principal write "Line ",count,": ",line,!
use $principal
close file
write "Read ",count," lines total.",!
quit
How the file example works:
OPEN file:(newversion)createsnotes.txtfor writing. WithoutNEWVERSION, an existing file would be appended to instead of replaced.USE filemakes the file the current device, so the followingWRITEs go to disk rather than the screen.USE $principalswitches output back to the terminal.- The argumentless
FORloops indefinitely;QUIT:$ZEOFexits the moment aREADreaches end-of-file. The read that hits EOF returns an empty string and sets$ZEOF, soQUIT:$ZEOFskips it before the counter is incremented. CLOSE fileflushes and releases the file. The filenotes.txtis left in your working directory after the run.
Running with Docker
Use the same YottaDB image from the language overview. The volume mount exposes your .m routines and lets file output land back in your working directory.
| |
Expected Output
Running ioformat produces:
=== Output Formatting ===
Name Score
Alice 95
Bob 88
Pi is approximately 3.14159
Justified: 3.14
Formatted: 1,234,567
Sum of 10 and 20 is 30
Running iofile produces (and leaves a notes.txt file behind in your working directory):
Wrote 3 lines to /app/notes.txt
Line 1: First line
Line 2: Second line
Line 3: Third line
Read 3 lines total.
Key Concepts
- Everything is a device – the terminal, files, and pipes all use the same
OPEN/USE/READ/WRITE/CLOSEcommands; only the current device changes. $PRINCIPALis the terminal and is open automatically, which is why Hello World couldWRITEwith no setup.USE $PRINCIPALreturns output to the screen after writing to a file.WRITEformats inline with!(new line) and?n(column tab), while$JUSTIFYand$FNUMBERhandle numeric alignment and thousands separators.READis flexible – read a full line, add a:secondstimeout and check$TEST, or read a single keystroke with*varto get its ASCII code.- File access is declared at
OPENvia deviceparameters:NEWVERSIONto create/truncate for writing,READONLYto read, and (by default) append for existing files. $ZEOFsignals end-of-file during reads, and the argumentlessFOR ... QUIT:$ZEOFidiom is the standard way to consume a sequential file line by line.- Abbreviations are everywhere –
W,R,U,O, andCstand in forWRITE,READ,USE,OPEN, andCLOSEin real-world MUMPS code.
Running Today
All examples can be run using Docker:
docker pull yottadb/yottadb-base:latest-master
Comments
Loading comments...
Leave a Comment