I/O

Arc has a large variety of I/O operations that support file, string, and network I/O. Because Arc's I/O system is based on MzScheme, the MzScheme I/O documentation provides useful background.

Arc's I/O system is built in layers. The foundation provides basic operations. On top of this, more functional operations are constructed. The w/ (with/) series of operations are generally the most convenient.

One main I/O abstraction in Arc is the port: an input port produces bytes and an output port consumes bytes. A port may be created by opening a file or socket. In addition, Arc supports string I/O, where a string can provide data as an input port, or can receive data as an output port.

For input, Arc provides support to read a byte, character, line, or Scheme S-expression. (Because Arc inherit's MzScheme's Unicode support, one Unicode character may involve more than one byte.) Some of Arc's input operations indicate end-of-file through a user-specified eof value. This can be a symbol such as 'eof or nil.

Arc's read methods take a variety of arguments: some require a port, some default to stdin, and some allow a string as input. Some take an arbitrary number of body statements, while some take a "thunk", a function to evaluate.

Arc provides multiple operations for output. The prn procedure is useful for general-purpose printing, as well as for debugging. By wrapping it with w/stdout, the output can be directed to a file or string.

Arc supports formatted output, with very limited control over formatting. The prf operation uses a format string, which can contain two types of formatting directives. A "#" followed by a form causes the form to be evaluated. A "~" followed by an ignored character causes the directive to be replaced by the next argument. For example:

arc> (let x 42 (prf "#(+ 1 1) ~x #x\n" 111))
2 111 42
""

One convenient pattern in Arc is to read and write S-expressions to avoid encoding and parsing data. Multiple operations support reading S-expressions, either individually or an entire set at once, from multiple sources. If the syntactic correctness of the input is uncertain, saferead can be used.

Arc also includes multiple string I/O operations that allow a string to be used for input or output. The simplest operations are fromstring and tostring, for input or output respectively. See MzScheme String Ports for background on String Port I/O.

Input

readb [input-port]
Reads a byte from the input-port (or default of stdin). Returns nil on end-of-file.
>(readb (pipe-from "echo hello"))
104
readc [input-port]
Reads a character from the input-port (or default of stdin). Returns nil on end-of-file.
>(readc (pipe-from "echo ©"))
#\©
peekc input-port
Peeks at the next character from the input port, but leaves the character for future reads. It uses stdin if the argument is nil. It returns the character, or nil for end-of-file.
>(peekc (pipe-from "echo hello"))
#\h
readline [input-port]
Reads a line from the specified port or stdin. The line is read up to a newline, nil, or eof. An initial newline does not terminate the input and appears in the output. A trailing newline is not included in the returned value.
>(w/instring ins "\n\na\nc\n\nd"
  (whiler l (readline ins) nil (prn "{" l "}")))
{
}
{a}
{c}
{
d}

nil
sread input-port eof
Reads a S-expression from the input port. Returns eof on end-of-file.
>(sread (pipe-from "echo '(1 2) (3)'") "junk")
(1 2)
read [input-source [eof]]
Reads a S-expression from the input-source, which can be either a string or an input-port. If the end of file is reached, nil is returned or the specified eof value.
>(read "(+ 1 1)(foo bar)")
(+ 1 1)
>(w/instring ins "(foo 42)" (read ins))
(foo 42)
>(read "" 'eof)
eof
readstring1 string [eof]
Reads a S-expression from the string. This is the same as read, except only handles a string.
>(readstring1 "(+ 1 1)")
(+ 1 1)
saferead input-source
Reads a S-expression from the input-source, which can be either a string or an input-port. If the end of file is reached, nil is returned or the specified eof value. If an error is encountered in the input, returns nil.
>(saferead "1 + 1")
1
>(saferead "###")
nil
readall input-source [eof]
Reads S-expressions from the input-source, which can be either a string or an input-port. Returns a list of the S-expressions. If the end of file is reached, nil is returned or the eof value if specified.
>(w/instring ins "(+ 1 1)abc (foo)" (readall ins))
((+ 1 1) abc (foo))
>(readall "[_]")
((fn (_) (_)))
load path
Loads the file of Arc code into the REPL environment.
>(load "strings.arc")
nil

Output

disp [arg [output-port]]
Displays the argument on the output-port (or current-output-port) using MzScheme's display procedure. Returns nil.
>(disp '(1 2))
(1 2)
nil
>(disp "abc")
abc
nil
>(disp #\a)
a
nil
>(disp "a\nb")
a
b
nil
write [arg [output-port]]
Writes the argument to the output-port (or current-output-port). Returns nil. The write and disp operations are slightly different: write quotes strings and characters, while disp displays them. See the MzScheme Default Printer documentation for details.
>(write "abc")
"abc"
nil
>(write #\a)
#\a
nil
>(write "a\nb")
"a\nb"
nil
writeb int [output-port]
Writes the byte to the output-port (or default of current-output-port).
>(writeb 65)
A
65
writec char [output-port]
Writes the character to the output-port (or default of current-output-port).
>(writec #\日)
#\日
pr [arg ...]
Prints arguments using disp. Returns the first argument.
>(pr 1 "a")
1a
1
prn [arg ...]
Prints arguments followed by a newline.
>(prn 1 "a")
1a

1
prall elts [initial-string [separator-string]]
Prints each element of list elts. The initial-string is printed first. The elements are separated by separator-string. Returns elts.
>(prall '(1 2 3))
1, 2, 3
(1 2 3)
>(prall '(1 2 3) "Value: " "-")
Value: 1-2-3
(1 2 3)
prs [arg ...]
Prints the arguments, separated by a space. Returns the arguments as a list.
>(prs 1 2 3)
1 2 3
(1 2 3)
prf str [arg ...]
Prints args using the format string.
>(let hi "hello" (prf "#hi #(+ 1 2)"))
hello 3
""
>(prf "Num ~a and ~~" 1 2)
Num 1 and 2
"Num "
out expr
Prints what expr prints. expr is evaluated at macro expansion time. New in arc3.
>(out (pr 42))
42
"42"
parse-format str
Parses a format string. An internal helper for prf.
ero [arg ...]
Writes the args to stderr. Returns the first arg.
>(ero "This appears on stderr")
"This appears on stderr"
warn msg [arg ...]
Displays warning msg, followed by the arguments.
>(warn "Problem" '(1 2) 3)
Warning: Problem. (1 2) 3 

nil

File I/O

readfile filename
Reads a file containing Lisp forms. Returns a list of the forms.
>(readfile "foo.arc")
Error: open-input-file: cannot open input file
  path: /path
/to/doc/foo.arc
  system error: No such file or directory; e
rrno=2

readfile1 filename
Reads a single Lisp form from the specified file.
>(readfile1 "foo.arc")
Error: open-input-file: cannot open input file
  path: /path
/to/doc/foo.arc
  system error: No such file or directory; e
rrno=2

writefile obj filename
Writes obj to the specified file. The contents are first written to filename.tmp, and then that is moved to filename.
>(writefile '(1 2) "bar.arc")
(1 2)
infile filename ['binary | 'text]
Opens the specified path for reading. By default, the file is opened in binary mode, and bytes are returned as read from the file. In text mode, return and linefeed bytes are filtered in a platform-specific way. (On Windows, return followed by linefeed is filtered to a single linefeed.)
>(infile "foo.arc")
Error: open-input-file: cannot open input file
  path: /path
/to/doc/foo.arc
  system error: No such file or directory; e
rrno=2

w/infile var filename [body ...]
Opens filename for reading with infile, assigns the input-port to var, executes body, and closes the file.
>(w/infile inf "foo.arc" (read inf))
Error: open-input-file: cannot open input file
  path: /path
/to/doc/foo.arc
  system error: No such file or directory; e
rrno=2

outfile filename ['append]
Opens the specified path for writing. By default, the file is truncated if it already exists. Returns an output-port. Arc supports only 'text mode for outfile.
>(outfile "/tmp/junk" 'append)
#<output-port:/tmp/junk>
w/outfile var filename [body ...]
Opens filename for writing with outfile, assigns the output-port to var, executes body, and closes the file.
>(w/outfile outf "bar.arc" (w/stdout outf (prn "Hello")))
"Hello"
w/appendfile var filename [body ...]
Opens filename for appending with outfile, assigns the output-port to var, executes body, and closes the file.
>(w/appendfile af "bar.arc" w/stdout af (prn "Hello"))
Hello

"Hello"
close port [...]
Closes a port or ports. In arc0, close took a single argument only.
>(close (outfile "/tmp/junk"))
nil
pipe-from command
Executes command in the underlying OS. Then opens an input-port to the results. Note that this is not a genuine pipe as the command completes before the results can be read.
>(readline (pipe-from "echo hello"))
"hello"
flushout
Flushes output. New in arc3.
>(flushout)
t

Disk variables

diskvar var file
Creates a variable that will be loaded from file and stored in file. If file exists, var is initialzed from file. New in arc3.
>(diskvar foo "file.txt")
nil
disktable var file
Creates a table variable that will be loaded from file and stored in file. New in arc3.
>(disktable bar "file.txt")
nil
todisk var [expr]
Writes var to disk, optionally setting it to expr first. New in arc3.
>(todisk bar)
Error: Function call on inappropriate object nil (#
<procedure: bar>)

fromdisk var file init load save
If var is not bound, var is initialized either by calling load function on file or using init. The save function is saved for later use. Internal function. New in arc3.

stdin, stdout, and stderr

stdin
stdin: returns the input-port stdin
>(stdin)
#<input-port:stdin>
stdout
current-output-port: returns the output-port stdout
>(stdout)
#<output-port:string>
stderr
current-error-port: returns the output-port stderr
>(stderr)
#<output-port:stderr>
>(write "Error message" (stderr))
nil
call-w/stdin input-port thunk
Sets stdin to the specified port and then executes the thunk.
>(call-w/stdin (instring "Hello") readline)
"Hello"
w/stdin input-port [body ...]
Sets stdin to the specified port and then executes the body.
>(w/instring ins "Hello" (w/stdin ins (readline)))
"Hello"
call-w/stdout output-port thunk
Calls thunk, setting stdin to the specified port.
>(let sop (outstring)
  (call-w/stdout sop (fn () (prn '(1 2))))
  (inside sop))
"(1 2)\n"
w/stdout output-port [body ...]
Executes the body port with stdout redirected to the output-port. This is a wrapper around call-w/stdout.
>(let sop (outstring)
  (w/stdout sop (prn '(1 2)))
  (inside sop))
"(1 2)\n"

String Port I/O

instring string [name]
Creates an input port to read UTF-8 bytes from the string. This is MzScheme's open-input-string.
>(readline (instring "hello"))
"hello"
w/instring var str [body ...]
Creates an string input-port from str with instring, assigns it to var, executes body, and then closes the input port.
>(w/instring ins "(+ 1 1)" (read ins))
(+ 1 1)
fromstring str [body ...]
Executes the body, using the contents of str as stdin.
>(fromstring "(+ 1 1)" (read))
(+ 1 1)
outstring [name]
Creates an output-port that accumulates the output into a byte string. The string can be retrieved with inside. This is MzScheme's open-output-string.
>(outstring)
#<output-port:string>
inside string-output-port
Returns (as a string) the bytes accumulated in a string-output-port generated by outstring. This is MzScheme's get-output-string.
>(let sop (outstring) (write "hello" sop) (inside sop))
"\"hello\""
w/outstring var [body ...]
Creates a string output-port with outstring, assigns it to var, and executes body.
>(w/outstring os (prn "hi") (inside os))
hi

""
tostring [body ...]
Executes the body. Any output that was sent to stdout is captured and returned as a string.
>(tostring (prn "hello") (prn "world"))
"hello\nworld\n"

Copyright 2008 Ken Shirriff.