DOS String Streams¶
A string stream is a BPTR filehandle whose backing store is a chunk of memory rather than a file, handler, or NIL sink. The same buffered-I/O API (FGetC, FPutC, FGets, FRead, FWrite, …) then reads from or writes to that memory region. dos.library uses this internally to feed command lines into a Shell and to implement the Run command's stdin-from-string behaviour; the same technique is available to applications that want to make in-memory data look like a file to a library that only takes filehandles.
Construction is a small hack: open a NIL: filehandle (which carries no data and blocks no resources), then redirect its buffer pointers at the memory region you want to expose as a "file".
Building a read-only string stream¶
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/stdio.h>
#include <string.h>
/* Open a BPTR whose input is the in-memory buffer `data` (length `len`).
* The buffer must remain valid for as long as the filehandle is open.
* Returns ZERO on failure. */
BPTR OpenStringStream(const UBYTE *data, LONG len)
{
BPTR file = Open("NIL:", MODE_OLDFILE);
if (!file) return 0;
/* The handle must be longword-aligned; AllocVec gives that for free. */
UBYTE *buf = AllocVec(len, MEMF_PUBLIC);
if (!buf) {
Close(file);
return 0;
}
memcpy(buf, data, len);
struct FileHandle *fh = BADDR(file);
fh->fh_Buf = MKBADDR(buf); /* buffer base, as BCPL pointer */
fh->fh_Pos = 0; /* current read position in the buffer */
fh->fh_End = len; /* one past the last valid byte */
return file; /* caller Close()s and FreeVec()s buf */
}
Once the filehandle is open, all buffered read functions consume from the buffer as if it were a file:
BPTR in = OpenStringStream((UBYTE *)"Hello World!\n", 13);
if (in) {
BPTR out = Output();
LONG ch;
while ((ch = FGetC(in)) >= 0) {
FPutC(out, ch);
}
/* Tear down. Note: the buffer was AllocVec'd internally; we own it. */
struct FileHandle *fh = BADDR(in);
APTR buf = BADDR(fh->fh_Buf);
Close(in);
FreeVec(buf);
}
Alignment requirement.
fh_Bufis aBPTR(BCPL index), so the buffer must be longword-aligned.AllocVec()guarantees this; if you pointfh_Bufat a buffer you allocated yourself, align it manually (see BPTR, BSTR, and BCPL Legacy for theD_Smacro).Buffer ownership.
Close()releases the filehandle but does not free the buffer. The application mustFreeVec()(or equivalent) the buffer it installed.
Why this works¶
The FileHandle struct contains three fields that describe the buffered-I/O window:
| Field | Meaning |
|---|---|
fh_Buf |
BPTR to the buffer base |
fh_Pos |
Index of the next byte to read (or write) |
fh_End |
One past the last valid byte |
A NIL: handle starts with all three set such that reads and writes are no-ops on an empty buffer. Pointing them at real data turns the filehandle into a stream over that data.
This is the same technique dos.library uses internally to feed a Shell command line into the new Shell, and to install a string as a process's stdin.
Writing through a string stream¶
The same hack works for output: open NIL: for write, point fh_Buf at a sufficiently large buffer, set fh_Pos = 0 and fh_End to the buffer size. FPuts, FPrintf, Flush and friends will then write into the buffer; whatever the application chooses to do with the bytes — log them, parse them — is its own affair.
The FSkip example in section 5.7.4 of the manual operates on the same fields (fh_Pos, fh_End) to implement buffer-aware seeking without going through Seek().
Limitations¶
- No seek backwards past the buffer origin.
fh_Pos < 0is the "no buffer" sentinel for some functions; setting it negative is a way to force aSeek()round-trip on the next read. - No thread-safety. Like every
FileHandle, the buffer pointers are not protected. Don't share a string-stream filehandle across tasks. fh_Endis the buffer's high-water mark. Buffered writes can advancefh_Posbeyondfh_Endwithout growing the buffer; the caller must size the buffer appropriately and useFlush()carefully.
See Also¶
- dos.library Reference
- Interactive Files and Handler Detection
- BPTR, BSTR, and BCPL Legacy
- DOS Packets
Sources: Thomas Richter, "ROM Kernel Reference Manual: AmigaDOS" (First Edition, 2024), Chapter 5.7 — Working with File Handles (section 5.7.2 — String Streams).
Raw: raw/rkm/rkm-dos-book.md
Updated: 2026-10-02