Basic Input/Output

The pure virtual classes io::Reader and io::Writer are defined for low-level read and write operations on streams.
High level formatting functions can operate on any type of concrete io::Reader or io::Writer instance.

Wrapper classes io::IStream and io::OStream are provided for generic iostreams. Instances of these classes for the standard iostreams, std::cin, std::cout, and std::cerr are available through io::Stdin, io::Stdout, and io::Stderr, respectively.

File I/O can be done with the io::File class.


Format strings to functions printf, fprintf, and sprintf resemble their C counterparts with few exceptions for simplicity.


Additionally, the format-less functions print and println (as well as fprint, fprintln, sprint, and sprintln) are provided, which format arguments in some generally reasonable default fashion.
The only difference between print and println being that println appends a newline.

fmt::printf("testing %d %d %d\n", 1, 2, 3);
fmt::println("testing ", 1, 2, 3);
// Each output "testing 1 2 3", followed by a newline

Note that spaces are inserted between arguments only when neither argument is a string (char*, char[], or std::string).



%v    Scans or formats any value
%%    Literal %; consumes no value


%b or %t    false or true
%B or %T    FALSE or TRUE
%d          0 or 1


%b    Binary (base 2)
%c    Character or Unicode code point (single byte only when scanning)
%d    Decimal (base 10)
%o    Octal (base 8)
%u    Unicode code point
%x    Hexadecimal (base 16) with lowercase letters for a-f
%X    Hexadecimal (base 16) with uppercase letters for A-F

Floating point values

%b    Binary format, expressing mantissa and exponent; e.g. 123p456
%e    Scientific notation with exponent; e.g. 1234.56e78
%E    Scientific notation with exponent; e.g. 1234.56E78
%f    Format without exponent; e.g. 1234.5678
%g    Whichever of %e or %f produces shorter output
%G    Whichever of %E or %f produces shorter output

Strings (char pointers, arrays, or std::string)

%s    Text of string
%x    Hexadecimal (base 16) bytes with lowercase letters for a-f
%X    Hexadecimal (base 16) bytes with uppercase letters for A-F


%p    Hexadecimal (base 16), with leading 0x and lowercase letters for a-f
%P    Hexadecimal (base 16), with leading 0X and uppercase letters for A-F


+      Always print a sign for numeric values
-      Left justify within width
#      Alternate format: add leading 0 for octal (%#o),
       0x or 0X for hex (%#x, %#X), suppress 0x or 0X for pointer (%#p, %#P)
' '    (Space) Leave a space for elided sign in numeric values (% d);
       Put spaces between bytes in hex strings (% x, % X)
,      Adds locale-specific grouping to integers and floats
0      Pad numeric values with leading zeroes

Width and precision arguments may be given as *, in which case their value is taken from the next argument; e.g.:

fmt::printf("%*s", width, "str");
fmt::printf("%.*s", precision, "str");
fmt::printf("%*.*s", width, precision, "str");

Named Substitution

A family of formatting functions are also defined which perform substitutions in any order using a series of named fields. These functions are named printx, printxln, fprintx, fprintxln, sprintx, and sprintxln.

fmt::printxln("{who} took the {what} to {where}.",
        { "what", "One Ring" },
        { "where", "Mt. Doom" },
        { "who", "Frodo" },
// Prints "Frodo took the One Ring to Mt. Doom."

Flags can be passed to these functions, too. However, the % character is omitted.

fmt::printxln("{x}", { { "x", "*.*s", width, precision, "str" } });

fmt::printxln("Pi is: {pi}", { { "pi", ".2f", 3.14159 } });
fmt::printxln("Pi is: {pi}", { { "pi", ".*f", 2, 3.14159 } });
// Each output "Pi is: 3.14"

Custom Formatting

Custom formatters may be defined by overriding the fmt::formatter template.
These must be defined in the fmt namespace; e.g.

#include <mur_io/fmt.h>

class MyType {};

namespace fmt
    template <>
    struct formatter<MyType>
        static void format(io::Buffer &buf, const MyType &t, const format_spec&)
            fprint(buf, "Hello, world!");

fmt::printf("My type says: %v\n", MyType());
fmt::println("My type says: ", MyType());
// Each output "My type says: Hello, world!" followed by newline


Scan format strings to functions scanf, fscanf, and sscanf are mostly the same as for formatting functions. The exceptions are:

  • There is no precision field in format strings
  • * is not accepted for width fields
  • , flag is ignored
  • %u will scan a Unicode code point, encoded in UTF-8, but %c will always scan a single byte

For any whitespace in a format string, one or more whitespace characters will be passed over in the input. All other non-format characters will be required to be present in the input stream or scanning will end and an error will be returned.
For those functions not taking a format string, whitespace will be skipped between input arguments.
scanln requires a newline or end of input after all scanned arguments.

All scanning functions return an object of type fmt::scan_result, which contains two fields, n and err, and can also be converted to bool.

int x;
auto result = fmt::sscan("42", x)

if (result) // bool(result) also works
    // Outputs "42"

result = fmt::sscan("ohnobro", x)

if (!result)
    // result.error() gives an error message string
    fmt::println("Scan fail: ", result.error());

Custom Scanning

Custom scanners may be defined by overriding the fmt::scanner template.
These must be defined in the fmt namespace; e.g.

#include <mur_io/fmt.h>

struct Reverser
    std::string str;

namespace fmt
    template <>
    struct scanner<Reverser>
        static bool scan(const std::string &s, Reverser &rev, const format_spec&)
            rev.str.assign(s.rbegin(), s.rend());
            return true;

Reverser reverser;
auto result = fmt::sscan("Hello!", reverser);

if (result)
    // Outputs "!olleH"