Input/Output Streams¶
The following kinds of streams are provided:
- Input/Output on Buffers
- Input/Output on memory
- Input/Output on FILE* streams
- Input/Output on Unix file descriptors
- Input/Output on Sockets
Formatted output¶
A number of functions support specifying a format string, and will accept a variable amount of additional function arguments, depending on the format specifiers present in the format string. All those functions use the same formatting mechanism, as described here.
Format specifiers are sequences of characters started with a dollar
symbol ($
), followed by at a character, which determines the type
and amount of the additional function arguments being consumed.
The recognized format specifiers are:
Specifier | Type(s) | Output format. |
---|---|---|
$c |
int | Character. |
$l |
long int | Decimal number. |
$L |
unsigned long int | Decimal number. |
$i |
int | Decimal number. |
$I |
unsigned int | Decimal number. |
$X |
unsigned long int | Hexadecimal number. |
$O |
unsigned long int | Octal number. |
$p |
void* | Pointer, as hexadecimal number. |
$f |
float | Floating point number. |
$F |
double | Floating point number. |
$s |
const char* | A \0 -terminated string. |
$B |
w_buf_t* | Arbitrary data (usually a string). |
$S |
size_t, const char* | String of a particular length. |
$e |
Last value of errno , as an integer. |
|
$E |
Last value of errno , as a string. |
|
$R |
w_io_result_t | String representing the return value of an input/output operation (see Output for w_io_result_t below). |
Output for w_io_result_t
¶
The $R
format specifier will consume a w_io_result_t
value,
and format it as a string, in one of the following ways:
IO<EOF>
- End-of-file marker. This is printed when
w_io_eof()
would returntrue
for the value. IO<string>
- This format is used for errors, the string describes the error.
Most of the time the error strings correspond to the values obtained
by using
strerror (w_io_result_error (value))
on the value. IO<number>
- This format is used for successful operations, the number is the
amount of bytes that were handled during the input/output operation,
and it can be zero, e.g. for the result of
w_io_close()
.
Reusing¶
The main entry point of the formatting mechanism is the
w_io_format()
function, which works for any kind of output stream.
To allow for easier integration with other kinds of output, an alternate
version of the function, w_io_formatv()
, which accepts a
va_list
, is provided as well.
By providing a custom output stream implementation, it is possible to reuse
the formatting mechanism for your own purposes. The w_buf_format()
function, which writes formatted data to a buffer, is implemented using this
technique.
The following example implements a function similar to asprintf()
, which
allocates memory as needed to fit the formatted output, using
w_io_formatv()
in combination with a w_io_buf_t
stream:
char*
str_format (const char *format, ...)
{
// Using NULL uses a buffer internal to the w_io_buf_t.
w_io_buf_t buffer_io;
w_io_buf_init (&buffer_io, NULL, false);
// Writing to a buffer always succeeds, the result can be ignored.
va_list args;
va_start (args, format);
W_IO_NORESULT (w_io_formatv ((w_io_t*) &buffer_io, format, args));
va_end (args);
// The data area of the buffer is heap allocated, so it is safe to
// return a pointer to it even when the w_io_buf_t is in the stack.
return w_io_buf_str (&buffer_io);
}
Types¶
-
w_io_result_t
¶ Represents the result of an input/output operation, which is one of:
- An error, which signals the failure of the operation. The
w_io_failed()
can be used to check whether an input/output operation failed. If case of failure, the error code can be obtained usingw_io_result_error()
; otherwise the operation succeeded and it can have one of the other values. - An indication that the end-of-file marker has been reached — typically
used when reading data from a stream. The
w_io_eof()
function can be used to check for the end-of-file marker. - A successful operation, indicating the amount of data involved. This
is the case when an operation neither failed, neither it is the
end-of-file marker. The amount of bytes handled can be retrieved using
w_io_result_bytes()
.
It is possible to obtain a textual representation of values of this type by using the
$R
format specifier with any of the functions that use the Formatted output system.- An error, which signals the failure of the operation. The
-
w_io_t
¶ Represents an input/output stream.
Macros¶
-
W_IO_RESULT
(bytes)¶ Makes a
w_io_result_t
value which indicates a successful operation which handled the given amount of bytes.
-
W_IO_RESULT_ERROR
(error)¶ Makes a
w_io_result_t
value which indicates a failure due to given error.
-
W_IO_RESULT_EOF
¶ Makes a
w_io_result_t
value which indicates a successful operation that reached the end-of-file marker.
-
W_IO_RESULT_SUCCESS
¶ Makes a
w_io_result_t
value which indicates a successful operation.
-
W_IO_CHAIN
(result, expression)¶ This macro expands to code that evaluates an expression, which must return a
w_io_result_t
value. If the operation failed, it will cause the current function to return the error, otherwise the amount of bytes returned byw_io_result_bytes()
are added to the amount in the variable of typew_io_result_t()
passed as the result parameter.Typical usage involves using the macro is inside a function that performs a number of reads (or writes), and the overall status of a “chain” of input/output operations is to be reported back as a result.
The expanded macro is roughly equivalent to:
w_io_result_t expr_result = expression; if (w_io_failed (expr_result)) return expr_result; result.bytes += w_io_result_bytes (expr_result);
As an example, consider a data stream which contains “messages” of the form
SIZE:DATA
, with the SIZE of the message encoded as a plain text integer, followed by a colon, and SIZE bytes of arbitrary data. The following function reads such messages, one at a time, returning the result of reading from the input as aw_io_result_t
value —which can be checked for end-of-file or errors—, and returning the DATA in a buffer and its expected size:w_io_result_t read_message (w_io_t *input, w_buf_t *message, unsigned long *size) { w_io_result_t bytes = W_IO_RESULT (0); // Read the length of the record. If reading fails, the macro // causes the function to return early with an error result. // The amount of bytes read is added to "bytes". W_IO_CHAIN (bytes, w_io_fscan_ulong (input, size)); // Read the separator. Again: the macro causes an early error // return on failure, or incrementing "bytes" on success. char separator = '\0'; W_IO_CHAIN (bytes, w_io_read (input, &separator, 1)); if (separator != ':') return W_IO_RESULT_ERROR (EBADMSG); // Read the message contents. Again: the macro causes an early // error on failure, or incrementing "bytes" on success. w_buf_resize (message, record_size); W_IO_CHAIN (bytes, w_io_read (input, w_buf_data (message), *size); return bytes; // Returns the total amount of bytes read. }
-
W_IO_CHECK
(expression)¶ This macro expands to code that evaluates an expression, which must return a
w_io_result_t
value. If the operation failed, it will cause the current function to return the error. It is roughly equivalent to:w_io_result_t expr_result = expression; if (w_io_failed (expr_result)) return expr_result;
-
W_IO_CHECK_RETURN
(expression, value)¶ Similar to
W_IO_CHECK
, but instead of returning aw_io_result_t
if the expression fails to perform input/output, the given value is returned instead. It is roughly equivalent to:if (w_io_failed (expression)) return value;
-
W_IO_NORESULT
(expression)¶ This macro expands to code that evaluates an expression, which must return a
w_io_result_t
value, and ignoring that result value. This is typically used when a an input/output operation is known to never fail, and the result status will not be checked, or when the operation might fail, but it does not matter whether it did.
Functions¶
-
w_io_result_t
w_io_close
(w_io_t *stream)¶ Closes an input/output stream.
-
w_io_result_t
w_io_read
(w_io_t *stream, void *buffer, size_t count)¶ Reads up to count bytes from the an input stream, placing the data in in memory starting at buffer.
Passing a count of zero always succeeds and has no side effects.
If reading succeeds, the amount of bytes read may be smaller than the requested count. The reason may be that the end-of-file marker has been reached (and it will be notified at the next attempt of reading data), or because no more data is available for reading at the moment.
-
w_io_result_t
w_io_write
(w_io_t *stream, const void *buffer, size_t count)¶ Writes up to count bytes from the data in memory starting at buffer to an output stream.
Passing a count of zero always succeeds and has no side effects.
-
int
w_io_getchar
(w_io_t *stream)¶ Reads the next character from a input stream.
If the enf-of-file marker is reached,
W_IO_EOF
is returned. On errors, negative values are returned.
-
w_io_result_t
w_io_putchar
(w_io_t *stream, int character)¶ Writes a character to an output stream.
-
void
w_io_putback
(w_io_t *stream, int character)¶ Pushes a character back into an input stream, making it available during the next read operation.
Warning
Pushing more than one character is not supported, and only the last pushed one will be saved.
-
w_io_result_t
w_io_flush
(w_io_stream *stream)¶ For an output stream, forces writing buffered data to the stream.
For in input stream, discards data that may have been fetched from the stream but still not consumed by the application.
-
int
w_io_get_fd
(w_io_t *stream)¶ Obtains the underlying file descriptor used by a stream.
Warning
Not all types of input/output streams have an associated file descriptor, and a negative value will be returned for those.
-
w_io_result_t
w_io_format
(w_io_t *stream, const char *format, ...)¶ Writes data with a given format to an output stream. The amount of consumed arguments depends on the format string.
See Formatted output for more information.
-
w_io_result_t
w_io_formatv
(w_io_t *stream, const char *format, va_list arguments)¶ Writes data with a given format to an output stream, consuming the needed additional arguments from the supplied
va_list
. The amount of consumed arguments depends on the format string.See Formatted output for more information.
-
w_io_result_t
w_print
(format, ...)¶ Writes data in the given format to the standard output stream
w_stdout
. The amount of consumed arguments depends on the format string.See Formatted output for more information.
-
w_io_result_t
w_printerr
(format, ...)¶ Writes data in the given format to the standard error stream
w_stderr
. The amount of consumed arguments depends on the format string.See Formatted output for more information.
-
w_io_result_t
w_io_read_until
(w_io_t *stream, w_buf_t *buffer, w_buf_t *overflow, int character, unsigned read_bytes)¶ Reads data from a stream until a certain character is read. Data is read in chunks of read_bytes size, and placed in a buffer, with the excess characters placed in an overflow buffer, which can be passed back to continue scanning for the stop character in subsequent calls.
Passing zero for the read_bytes size will make the function use a default chunk size — usually the size of a memory page.
This function is intended to read records of data of variable size which are separated using a certain character as a delimiter. For example, usually fortune data files have items separated by
%
characters. The following function would read such a file:void read_fortunes (w_io_t *input) { w_buf_t fortune = W_BUF; w_buf_t overflow = W_BUF; for (;;) { w_io_result_t r = w_io_read_line (input, &fortune, &overflow, 0); if (w_io_failed (r)) { w_printerr ("Error reading fortunes: $R\n" r); break; } if (w_io_eof (r)) break; handle_fortune (&fortune); } w_buf_clear (&overflow); w_buf_clear (&fortune); }
-
bool
w_io_failed
(w_io_result_t result)¶ Checks whether the result of an input/output operation was a failure.
If the result happens to be a failure,
w_io_result_error()
can be used to retrieve the error code.
-
bool
w_io_eof
(w_io_result_t result)¶ Checks whether the result of an input/output operation was the end-of-file marker.
-
int
w_io_result_error
(w_io_result_t result)¶ Obtains the code of the error that caused an input/output operation to return a failure result.
This function only returns meaningful values when result indicates a failed operation. This condition can be checked using
w_io_failed()
.
-
size_t
w_io_result_bytes
(w_io_result_t result)¶ Obtains the amount of bytes which were involved as the result of an input/output operation.
When the result signals a failed operation, or the end-of-file marker, the returned value is always zero.
-
w_io_result_t
w_io_read_line
(w_io_t *stream, w_buf_t *line, w_buf_t *overflow, unsigned read_bytes)¶ Reads a line of text from an input stream.
This is a convenience function that calls
w_io_read_until()
passing'\n'
as delimiter character.