changeset 169:eb0a7ab71023

misc: extreme cleanup, closes #2506 While here, remove unneeded stuff.
author David Demelier <markand@malikania.fr>
date Tue, 20 Oct 2020 17:39:13 +0200
parents aab824406d3d
children e60a13969acb
files doxygen/CMakeLists.txt doxygen/mainpage.c doxygen/page-faq.c doxygen/page-howto-error.c doxygen/page-howto-ownership.c doxygen/page-portability.c libcore/CMakeLists.txt libcore/core/action.h libcore/core/animation.c libcore/core/animation.h libcore/core/drawable.h libcore/core/error.c libcore/core/error.h libcore/core/error_p.h libcore/core/event.h libcore/core/font.c libcore/core/font.h libcore/core/game.h libcore/core/image.c libcore/core/image.h libcore/core/plat.h libcore/core/rbuf.c libcore/core/rbuf.h libcore/core/sound.c libcore/core/sound.h libcore/core/sprite.c libcore/core/sprite.h libcore/core/sys.c libcore/core/sys.h libcore/core/texture.c libcore/core/texture.h libcore/core/util.c libcore/core/util.h libcore/core/window.c libcore/core/window.h librpg/rpg/map.c tests/CMakeLists.txt tests/test-rbuf.c
diffstat 38 files changed, 321 insertions(+), 603 deletions(-) [+]
line wrap: on
line diff
--- a/doxygen/CMakeLists.txt	Tue Oct 20 15:09:39 2020 +0200
+++ b/doxygen/CMakeLists.txt	Tue Oct 20 17:39:13 2020 +0200
@@ -25,9 +25,12 @@
 		INPUT
 		doxygen/groups.c
 		doxygen/mainpage.c
-		doxygen/page-howto-initialization.c
+		doxygen/page-examples.c
 		doxygen/page-faq.c
-		doxygen/page-examples.c
+		doxygen/page-howto-error.c
+		doxygen/page-howto-initialization.c
+		doxygen/page-howto-ownership.c
+		doxygen/page-portability.c
 		libadventure
 		libcore
 		libui
--- a/doxygen/mainpage.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/doxygen/mainpage.c	Tue Oct 20 17:39:13 2020 +0200
@@ -26,9 +26,8 @@
  * Molko's Adventure is a 2D solo RPG written in pure C, using SDL2 and SDL2
  * addons.
  *
- * As its heart, the game is split into two parts, the core (**src/core**) and
- * the game data and scenario (**src/adventure**). It is then possible to anyone
- * to create its own similar game using the same core. However please note that:
+ * As its heart, the game is split into multiple parts, libraries, game data and
+ * game code.
  *
  * - It is not a game engine! Many aspects in the core are still tightly coupled
  *   with the original game design. We wanted the core to be kept simple without
@@ -40,9 +39,8 @@
  *
  * # Usage
  *
- * If you plan to create your own game, simply copy the whole **src/core**
- * directory to your project and add all .c files to the compilation process. No
- * prior configuration is required, every features are detected using `#ifdef`s.
+ * If you plan to create your own game, simply copy the whole directory
+ * directory to your project and select which libraries you need.
  *
  * \note If you find a bug regarding your platform, feel free to send bug
  *       reports and patches.
@@ -51,111 +49,15 @@
  * with _p.h are usually reserved for the implementation and should not be used
  * unless you know what you're doing.
  *
- * # Documentation nomenclature
- *
- * Every modules are organized per files and referenced this way. For example,
- * if you need to access the error handling, you just have to use \ref error.h
- * file.
- *
- * ## Structures
- *
- * Almost every structure are exposed directly to the user and allocated on the
- * stack. Each member is documented with the following prefix format (XYZ)
- * where:
- *
- * The letter *X* defines the following restriction
- *
- * - `+`: The property is readable/editable by the user,
- * - `-`: The property is readable by the user,
- * - `*`: The property is not meant to be used directly by the user.
- *
- * The letter *Y* can be set to `&` in that case means it is only referenced
- * and is not an owned property (usually a non-owning pointer). Which means
- * user is responsible for deallocation if required.
- *
- * The finall letter *Z* can be set to `?` which means it is optional (like a
- * nullable pointer).
+ * # Libraries
  *
- * Examples:
- *
- * ```c
- * struct foo {
- *     int x;                // (+) Position in x.
- *     int y;                // (+) Position in y.
- *     struct theme *th;     // (+&?) Theme to use.
- *     unsigned int elapsed; // (-) Elapsed time since last frame.
- *     struct texture text;  // (*) Texture used for rendering.
- * };
- * ```
- *
- * Within this structure, the fields `x` and `y` are completely accessible to
- * the user for both reading/writing. The field `th` is an optional non-owning
- * pointer to a theme which is also readable/writable. The field `elapsed` is
- * readable but should not be modified. Finally, the field `text` is private
- * and should not be touched by the user.
- *
- * ## Functions
- *
- * When functions needs to initialize and destroy objects, the following
- * conventions is used:
- *
- * - `foo_init`: initialize the object,
- * - `foo_finish`: dispose the object and possible owned allocations.
+ * The following libraries are available and built separately:
  *
- * In case of opaque objects, the creation function is named under the module
- * discretion (e.g. `foo_open`, `foo_new`) but the destruction function is
- * usually named `foo_free`.
- *
- * # Usage conventions
- *
- * This chapter describes lots of aspects about using this core API.
- *
- * ## Memory and ownership
- *
- * Within the core, functions usually never take ownership of user objects. They
- * mostly assume that objects are still alive during usage of the core API.  If
- * the opposite case happen, it is clearly stated in the documentation. Unless
- * stated, user must always make sure objects are kept alive.
- *
- * If a function needs its own copy of something, it usually take a const
- * pointer and copy it into its internals. But make sure that every member are
- * still pointer to valid memory if this is a concern.
- *
- * Example: the \ref script.h modules is used to create a sequence of action, on
- * its internal it stores a singly-linked list of \ref action that are copied
- * from the user. But since the \ref action structure contains arbitrary data,
- * those must be kept until the action is no longer used.
- *
- * \code
- * struct action my_action action = {
- * 	.data = my_action_data,
- * 	.update = my_action_update
- * };
- * struct script script;
- *
- * script_init(&script);
- * script_append(&script, &action);
- * \endcode
- *
- * Even though \ref script_append copy the action into an internal object,
- * the *my_action_data* must still be valid until the script ended.
- *
- * ## Modules
- *
- * Whenever possible, functions that needs a structure context will always take
- * it as first argument.
- *
- * This let the user to control lifetime and allocation storage for most of the
- * API objects.
- *
- * Example:
- *
- * \code
- * struct clock clock;
- *
- * clock_start(&clock);
- * clock_elapsed(&clock);
- * \endcode
+ * | Library | Description                                  | Dependencies                           |
+ * |---------|----------------------------------------------|----------------------------------------|
+ * | libcore | Low level audio, video, windowing and input. | SDL2, SDL2_mixer, SDL2_ttf, SDL2_image |
+ * | libui   | Minimalist UI routines to draw interfaces    | libcore                                |
+ * | librpg  | Group of modules related to RPG games        | libcore, libui                         |
  *
  * ## Thread safety and reentrancy
  *
@@ -166,10 +68,4 @@
  * objects.
  *
  * \note This may change in the future.
- *
- * ## Error handling
- *
- * Functions that may fail usually return a boolean. If an error occured, it is
- * stored in a global variable that are accessed through the \ref error.h
- * module.
  */
--- a/doxygen/page-faq.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/doxygen/page-faq.c	Tue Oct 20 17:39:13 2020 +0200
@@ -44,11 +44,11 @@
  * happening under the hood without having to check if functions will generate
  * dynamic allocations or not.
  *
- * However, we also love modernity and as such, C18 is the minimal requirement
+ * However, we also love modernity and as such, C11 is the minimal requirement
  * to build and run Molko's Adventure.
  *
  * \note The code does not make any assumption about the platform it runs, it
- *       expects to have a fully conformant C18 implementation. Microsoft MSVC
+ *       expects to have a fully conformant C11 implementation. Microsoft MSVC
  *       is known to **not** support this C version.
  * 
  * # Can I make a MMORPG with that?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doxygen/page-howto-error.c	Tue Oct 20 17:39:13 2020 +0200
@@ -0,0 +1,76 @@
+/**
+ * \page howto-error Howto: error handling
+ * \tableofcontents
+ *
+ * How error handling is used within the API and the user code.
+ *
+ * # Synopsis
+ *
+ * Error handling is always a complicated task in the software development. In
+ * Molko's Adventure there is three kinds of errors:
+ *
+ * 1. Programming error.
+ * 2. Recoverable error at runtime.
+ * 3. Unexpected error at runtime.
+ *
+ * # Kind of errors
+ *
+ * ## Assertions
+ *
+ * One of the easiest errors to detect are about programming errors. In the
+ * Molko's Adventure API they are usually detected at runtime when you use a
+ * function with preconditions unmet. In that case standard C `assert` is used.
+ *
+ * For example, it happens when you:
+ *
+ * - Pass a NULL pointer where the function expects non-NULL,
+ * - Pass invalid arguments such as out of bounds indicies.
+ *
+ * Always read carefully preconditions that are annotated through the
+ * documentation.
+ *
+ * ## Recoverable errors
+ *
+ * Next, come recoverable errors. Those arise when you may expect a failure from
+ * the API and can do something else.
+ *
+ * For example, it happens when you:
+ *
+ * - Open a font file that is invalid,
+ * - Open a music file that is no longer on the disk.
+ *
+ * In these situations, the API indicates usually by a return code that the
+ * function was unable to complete correctly (and you can use \ref error to
+ * retrieve the specified error). In some case, you *MUST* not ignore the return
+ * value because if the function takes an input as argument it will be kept
+ * untouched. For example, the \ref texture_new function may fail to create a
+ * texture and in that case it is left untouched.
+ *
+ * ## Unexpected errors
+ *
+ * Finally, come what we call unexpected errors. Those happen while they are not
+ * supposed to.
+ *
+ * For example, it happens when there is a severe issue either in the kernel,
+ * graphics or any other library that aren't raised by the API itself.
+ *
+ * This includes (but not limited to):
+ *
+ * - A rendering error (caused by an internal issue).
+ *
+ * In these situations, the API calls the function \ref panic which definitely
+ * calls the \ref panic_handler. The default implementation prints an error and
+ * exit with a code of 1. User may pass a custom function but should quit the
+ * game because the API does not take care of deallocating data before calling
+ * panic.
+ *
+ * # Error handling in Molko's Adventure API
+ *
+ * The following table shows what is used and when.
+ *
+ * |         | `assert`           | Booleans            | panic                                     | Notes                             |
+ * |---------|--------------------|---------------------|-------------------------------------------|-----------------------------------|
+ * | libcore | Programming errors | As much as possible | Only in memory utilities from util.h      | Never called from libcore itself. |
+ * | libui   | Programming errors | When applicable     | Mostly in rendering errors                | None.                             |
+ * | librpg  | Programming errors | When applicable     | Mostly in rendering errors                | None.                             |
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doxygen/page-howto-ownership.c	Tue Oct 20 17:39:13 2020 +0200
@@ -0,0 +1,120 @@
+/**
+ * \page howto-ownership Howto: ownership and memory management
+ * \tableofcontents
+ *
+ * How memory and ownership is used within Molko's Adventure API.
+ *
+ * # Synopsis
+ *
+ * In C, memory management can be a cumbersome issue and a major common complain
+ * when it comes to leak.
+ *
+ * As such, the API itself does not use dynamic allocations in most of the case.
+ * Instead it is kept to the user responsability to handle storage of data. In
+ * that manner the code stays simpler, stronger and more flexible. The API
+ * itself does not have to deal with memory management and deallocation, it only
+ * expect data from user and work with that.
+ *
+ * You can imagine a situation with a DVD player and some movies on DVDs. You
+ * have one DVD player where you put some DVDs inside but the DVD player never
+ * make its own copy, it simply reads your disc and you get it back afterwards.
+ *
+ * Following this philosophy, the Molko's Adventure API for this scenario would
+ * look like this:
+ *
+ * ```c
+ * struct dvd_player player;
+ * struct dvd dvd;
+ *
+ * dvd_open(&dvd, "/dev/sr0");
+ *
+ * dvd_player_turn_on();
+ * dvd_player_insert(&player, &dvd);
+ * dvd_player_play(&player);
+ * dvd_player_turn_off();
+ * ```
+ *
+ * # Memory handling
+ *
+ * ## Arrays
+ *
+ * Some modules in the API may require an array. Depending on the situation they
+ * can be passed as parameter or are usually of a fixed reasonable size in
+ * structures.
+ *
+ * They are always annotated with a macro to let the user flexibility over it if
+ * necessary.
+ *
+ * Example, a player has a set of spells.
+ *
+ * ```c
+ * #define PLAYER_SPELL_MAX (16)
+ *
+ * struct player {
+ *     struct spell *spells[PLAYER_SPELL_MAX];
+ * };
+ * ```
+ *
+ * ## Strings
+ *
+ * When dealing with strings, they are almost always referenced and not copied
+ * unless explicitly required. As such, no allocation/deallocation required
+ * either.
+ *
+ * ```c
+ * struct player {
+ *     const char *name; // Not allocated, no deallocation
+ * ```
+ *
+ * # Ownership
+ *
+ * Alongside the memory handling comes the ownership. Related to the DVD
+ * scenario explained above, not having to *own* a resource within a structure
+ * means no allocation/deallocation required.
+ *
+ * Also, since C does not have a scoped mechanism, all fields in structured are
+ * publicly available and to avoid allocating them on the heap they are always
+ * declared to the user even if they need internal data.
+ *
+ * As a documentation notice, fields are always annotated using (XYZ) prefix 
+ * with some symbols to indicate whether user is allowed to touch or not.
+ *
+ * The letter *X* defines the following restriction
+ *
+ * - `+`: The property is readable/editable by the user,
+ * - `-`: The property is readable by the user,
+ * - `*`: The property is not meant to be used directly by the user.
+ *
+ * The letter *Y* can be set to `&` in that case means it is only referenced
+ * and is not an owned property (usually a non-owning pointer). Which means
+ * user is responsible for deallocation if required.
+ *
+ * The finall letter *Z* can be set to `?` which means it is optional (like a
+ * nullable pointer).
+ *
+ * Examples:
+ *
+ * ```c
+ * struct foo {
+ *     int x;                // (+) Position in x.
+ *     int y;                // (+) Position in y.
+ *     struct theme *th;     // (+&?) Theme to use.
+ *     unsigned int elapsed; // (-) Elapsed time since last frame.
+ *     struct texture text;  // (*) Texture used for rendering.
+ * };
+ * ```
+ *
+ * Within this structure, the fields `x` and `y` are completely accessible to
+ * the user for both reading/writing. The field `th` is an optional non-owning
+ * pointer to a theme which is also readable/writable. The field `elapsed` is
+ * readable but should not be modified. Finally, the field `text` is private
+ * and should not be touched by the user.
+ *
+ * # Memory handling in Molko's Adventure API
+ *
+ * |         | Dynamic allocation? | Notes                                                   |
+ * |---------|---------------------|---------------------------------------------------------|
+ * | libcore | None                | The util.h provides convenient allocators for the user. |
+ * | libui   | None                |                                                         |
+ * | librpg  | In map.h module     | Maps are big chunk of data.                             |
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doxygen/page-portability.c	Tue Oct 20 17:39:13 2020 +0200
@@ -0,0 +1,34 @@
+/**
+ * \page portability Portability
+ * \tableofcontents
+ *
+ * A note about portability in Molko's Adventure API.
+ *
+ * # C standard used
+ *
+ * The code is based mostly written in C99 with a subset of C11. The following
+ * features from C11 are required:
+ *
+ * - `<stdnoreturn.h>` header.
+ *
+ * # POSIX
+ *
+ * A few routines from the POSIX specification are also used:
+ *
+ * - `<sys/stat.h>` header.
+ * - `read(2)` function.
+ * - `open(2)` function.
+ * - `getopt(3)`,
+ * - `fmemopen(3)`.
+ *
+ * Efforts are ongoing to provide fallback implementations for systems that lack
+ * those functionalities.
+ *
+ * # System tested
+ *
+ * - macOS (10.15 and later),
+ * - Linux (glibc and musl variants),
+ * - FreeBSD, NetBSD and OpenBSD.
+ *
+ * Windows is currently not supported right now but will be in the future.
+ */
--- a/libcore/CMakeLists.txt	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/CMakeLists.txt	Tue Oct 20 17:39:13 2020 +0200
@@ -33,7 +33,6 @@
 	${libcore_SOURCE_DIR}/core/drawable.h
 	${libcore_SOURCE_DIR}/core/error.c
 	${libcore_SOURCE_DIR}/core/error.h
-	${libcore_SOURCE_DIR}/core/error_p.h
 	${libcore_SOURCE_DIR}/core/event.c
 	${libcore_SOURCE_DIR}/core/event.h
 	${libcore_SOURCE_DIR}/core/font.c
@@ -53,8 +52,6 @@
 	${libcore_SOURCE_DIR}/core/panic.c
 	${libcore_SOURCE_DIR}/core/panic.h
 	${libcore_SOURCE_DIR}/core/plat.h
-	${libcore_SOURCE_DIR}/core/rbuf.c
-	${libcore_SOURCE_DIR}/core/rbuf.h
 	${libcore_SOURCE_DIR}/core/save.c
 	${libcore_SOURCE_DIR}/core/save.h
 	${libcore_SOURCE_DIR}/core/script.c
--- a/libcore/core/action.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/action.h	Tue Oct 20 17:39:13 2020 +0200
@@ -115,6 +115,7 @@
  * \pre act != NULL
  * \param act the action
  * \param ticks the number of milliseconds since last frame
+ * \return Status of act->update or false if act->update is NULL.
  */
 bool
 action_update(struct action *act, unsigned int ticks);
@@ -180,6 +181,7 @@
  * \param st the stack
  * \param act the action
  * \note The pointer must be kept alive.
+ * \return True if the action was added correctly (enough space).
  */
 bool
 action_stack_add(struct action_stack *st, struct action *act);
@@ -201,7 +203,7 @@
  * \pre st != NULL
  * \param st the stack
  * \param ticks the number of milliseconds since last frame
- * \return true if all actions completed
+ * \return True if all actions completed.
  */
 bool
 action_stack_update(struct action_stack *st, unsigned int ticks);
@@ -220,7 +222,7 @@
  *
  * \pre st != NULL
  * \param st the stack
- * \return false if there is at least one action in the stack
+ * \return False if there is at least one action in the stack.
  */
 bool
 action_stack_completed(const struct action_stack *st);
--- a/libcore/core/animation.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/animation.c	Tue Oct 20 17:39:13 2020 +0200
@@ -32,7 +32,7 @@
 static void
 draw(struct drawable *dw)
 {
-	return animation_draw(dw->data, dw->x, dw->y);
+	animation_draw(dw->data, dw->x, dw->y);
 }
 
 void
@@ -85,10 +85,10 @@
 	       an->column >= an->sprite->ncols;
 }
 
-void
+bool
 animation_draw(struct animation *an, int x, int y)
 {
-	sprite_draw(an->sprite, an->row, an->column, x, y);
+	return sprite_draw(an->sprite, an->row, an->column, x, y);
 }
 
 void
--- a/libcore/core/animation.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/animation.h	Tue Oct 20 17:39:13 2020 +0200
@@ -74,7 +74,7 @@
  * \pre an != NULL
  * \param an the animation
  * \param ticks the elapsed ticks since the last call
- * \return true if the animation is complete
+ * \return True if the animation is complete.
  */
 bool
 animation_update(struct animation *an, unsigned int ticks);
@@ -86,8 +86,9 @@
  * \param an the animation
  * \param x the X coordinate
  * \param y the Y coordinate
+ * \return False in case of rendering error.
  */
-void
+bool
 animation_draw(struct animation *an, int x, int y);
 
 /**
--- a/libcore/core/drawable.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/drawable.h	Tue Oct 20 17:39:13 2020 +0200
@@ -141,8 +141,7 @@
  * \pre dw != NULL
  * \param st the stack
  * \param dw the drawable to reference
- * \return true if the drawable was placed correctly and false if there wasn't
- *         enough room.
+ * \return True if the drawable was added correctly (enough space).
  */
 bool
 drawable_stack_add(struct drawable_stack *st, struct drawable *dw);
@@ -155,7 +154,7 @@
  * \pre st != NULL
  * \param st the drawable stack
  * \param ticks the number of ticks since last frame
- * \return true if all drawable were rendered
+ * \return True if all drawable were rendered.
  */
 bool
 drawable_stack_update(struct drawable_stack *st, unsigned int ticks);
@@ -174,7 +173,7 @@
  *
  * \pre st != NULL
  * \param st the stack
- * \return false if there is at least one drawable in the stack
+ * \return False if there is at least one drawable in the stack.
  */
 bool
 drawable_stack_completed(const struct drawable_stack *st);
--- a/libcore/core/error.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/error.c	Tue Oct 20 17:39:13 2020 +0200
@@ -17,13 +17,9 @@
  */
 
 #include <assert.h>
-#include <errno.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 
 #include "error.h"
-#include "error_p.h"
 
 #include <SDL.h>
 
@@ -58,21 +54,3 @@
 
 	return false;
 }
-
-bool
-error_errno(void)
-{
-	errorf("%s", strerror(errno));
-
-	return false;
-}
-
-/* private: error_p.h */
-
-bool
-error_sdl(void)
-{
-	errorf("%s", SDL_GetError());
-
-	return false;
-}
--- a/libcore/core/error.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/error.h	Tue Oct 20 17:39:13 2020 +0200
@@ -59,13 +59,4 @@
 bool
 verrorf(const char *fmt, va_list ap) PLAT_PRINTF(1, 0);
 
-/**
- * Convenient helper that sets last error from global C errno and then return
- * false.
- *
- * \return Always false.
- */
-bool
-error_errno(void);
-
 #endif /* !MOLKO_ERROR_H */
--- a/libcore/core/error_p.h	Tue Oct 20 15:09:39 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * error.h -- (PRIVATE) error routines
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_ERROR_P_H
-#define MOLKO_ERROR_P_H
-
-#include <stdbool.h>
-
-/**
- * Convenient handler that sets the game error to the last SDL error and then
- * return false.
- *
- * \return false
- */
-bool
-error_sdl(void);
-
-#endif /* !MOLKO_ERROR_P_H */
--- a/libcore/core/event.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/event.h	Tue Oct 20 17:39:13 2020 +0200
@@ -84,7 +84,7 @@
  * Fetch the next event or return false if there are not.
  *
  * \param ev the event
- * \return true if the event was filled or false otherwise
+ * \return True if the event was filled or false otherwise.
  */
 bool
 event_poll(union event *ev);
--- a/libcore/core/font.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/font.c	Tue Oct 20 17:39:13 2020 +0200
@@ -23,7 +23,6 @@
 
 #include "color.h"
 #include "error.h"
-#include "error_p.h"
 #include "font.h"
 #include "texture_p.h"
 #include "util.h"
@@ -35,7 +34,7 @@
 	assert(path);
 
 	if (!(font->handle = TTF_OpenFont(path, size)))
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	return true;
 }
@@ -50,7 +49,7 @@
 
 	if (!(ops = SDL_RWFromConstMem(buffer, buflen)) ||
 	   (!(font->handle = TTF_OpenFontRW(ops, true, size))))
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	return true;
 }
@@ -97,7 +96,7 @@
 	}
 
 	if (!(surface = func(font->handle, text, fg)))
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	return texture_from_surface(tex, surface);
 }
@@ -117,7 +116,7 @@
 	assert(text);
 
 	if (TTF_SizeUTF8(font->handle, text, (int *)w, (int *)h) != 0)
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	return true;
 }
--- a/libcore/core/font.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/font.h	Tue Oct 20 17:39:13 2020 +0200
@@ -137,7 +137,7 @@
  * \param text the UTF-8 text
  * \param w pointer to width (may be NULL)
  * \param h pointer to height (may be NULL)
- * \return false in case of error and pointers to w and h are left unmodified
+ * \return False in case of error and pointers to w and h are left unmodified.
  */
 bool
 font_query(const struct font *font, const char *text, unsigned int *w, unsigned int *h);
--- a/libcore/core/game.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/game.h	Tue Oct 20 17:39:13 2020 +0200
@@ -28,11 +28,6 @@
 
 #include "inhibit.h"
 
-/**
- * \brief Max number of actions allowed at the same time.
- */
-#define GAME_ACTIONS_MAX 128
-
 struct state;
 
 union event;
--- a/libcore/core/image.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/image.c	Tue Oct 20 17:39:13 2020 +0200
@@ -21,7 +21,7 @@
 
 #include <SDL_image.h>
 
-#include "error_p.h"
+#include "error.h"
 #include "texture.h"
 #include "window.h"
 #include "window_p.h"
@@ -46,7 +46,7 @@
 	assert(path);
 
 	if (!(tex->handle = IMG_LoadTexture(RENDERER(), path)))
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	dimensions(tex);
 
@@ -61,7 +61,7 @@
 	SDL_RWops *ops = SDL_RWFromConstMem(buffer, size);
 
 	if (!ops || !(tex->handle = IMG_LoadTexture_RW(RENDERER(), ops, true)))
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	dimensions(tex);
 
--- a/libcore/core/image.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/image.h	Tue Oct 20 17:39:13 2020 +0200
@@ -28,6 +28,8 @@
 #include <stdbool.h>
 #include <stddef.h>
 
+#include "plat.h"
+
 struct texture;
 
 /**
@@ -40,7 +42,7 @@
  * \return False on errors.
  */
 bool
-image_open(struct texture *tex, const char *path);
+image_open(struct texture *tex, const char *path) PLAT_NODISCARD;
 
 /**
  * Open a file from a memory buffer.
@@ -55,6 +57,6 @@
  * \return False on errors.
  */
 bool
-image_openmem(struct texture *tex, const void *buffer, size_t size);
+image_openmem(struct texture *tex, const void *buffer, size_t size) PLAT_NODISCARD;
 
 #endif /* !MOLKO_IMAGE_H */
--- a/libcore/core/plat.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/plat.h	Tue Oct 20 17:39:13 2020 +0200
@@ -36,10 +36,16 @@
  */
 #define PLAT_PRINTF(p1, p2)
 
+/**
+ * Annotate a function when the result must never be discarded.
+ */
+#define PLAT_NODISCARD
+
 #else
 
 #if defined(__GNUC__) || defined(__clang__)
 #       define PLAT_PRINTF(p1, p2) __attribute__ ((format (printf, p1, p2)))
+#       define PLAT_NODISCARD __attribute__ ((warn_unused_result))
 #else
 #       define PLAT_PRINTF(p1, p2)
 #endif
--- a/libcore/core/rbuf.c	Tue Oct 20 15:09:39 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * rbuf.c -- basic utility for reading input buffers
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <assert.h>
-
-#include "rbuf.h"
-
-void
-rbuf_open(struct rbuf *rb, const void *data, size_t datasz)
-{
-	assert(rb);
-	assert(data);
-
-	rb->s = data;
-	rb->e = rb->s + datasz;
-}
-
-bool
-rbuf_readline(struct rbuf *rb, char *output, size_t outputsz)
-{
-	assert(rb);
-	assert(output);
-	assert(outputsz > 0);
-
-	if (rb->s == rb->e)
-		return false;
-
-	for (--outputsz; rb->s != rb->e && *rb->s != '\n' && outputsz; outputsz--)
-		*output++ = *rb->s++;
-
-	/* Not enough space? */
-	if (!outputsz && rb->s != rb->e && *rb->s != '\n')
-		return false;
-
-	/* Remove this '\n' if still present. */
-	if (rb->s != rb->e && *rb->s == '\n')
-		rb->s++;
-
-	*output = '\0';
-
-	return true;
-}
--- a/libcore/core/rbuf.h	Tue Oct 20 15:09:39 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * rbuf.h -- basic utility for reading input buffers
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MOLKO_RBUF_H
-#define MOLKO_RBUF_H
-
-/**
- * \file rbuf.h
- * \brief Basic utility for reading input buffers.
- */
-
-#include <stdbool.h>
-#include <stddef.h>
-
-/**
- * \brief Input object to store progression.
- */
-struct rbuf {
-	const char *s;  /*!< (-) Pointer to current character. */
-	const char *e;  /*!< (-) Pointer to end of array. */
-};
-
-/**
- * Open this input buffer.
- *
- * \pre rb != NULL
- * \pre data != NULL
- * \param rb the input object
- * \param data the data to read
- * \param datasz the size of buffer
- */
-void
-rbuf_open(struct rbuf *rb, const void *data, size_t datasz);
-
-/**
- * Read the next line from the input.
- *
- * This function writes at most outputsz - 1 and is always NULL terminated
- * unless the function returns false which indicates either end of buffer or
- * too small output size.
- *
- * Example of use (`some_data` is assumed to be a buffer).
- *
- * \code
- * struct rbuf rb;
- * char line[1024];
- *
- * rbuf_open(&rb, some_data, sizeof (some_data));
- *
- * while (rbuf_readline(&rb, line, sizeof (line))) {
- *     printf("line contents: >[%s]<\n", line);
- * }
- * \endcode
- *
- * \pre rb != NULL
- * \pre output != NULL
- * \pre outputsz > 0
- * \param rb the input object
- * \param output the output buffer
- * \param outputsz the output buffer size
- * \return true if a line was read correctly
- */
-bool
-rbuf_readline(struct rbuf *rb, char *output, size_t outputsz);
-
-#endif /* !MOLKO_RBUF_H */
--- a/libcore/core/sound.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/sound.c	Tue Oct 20 17:39:13 2020 +0200
@@ -21,8 +21,8 @@
 
 #include <SDL_mixer.h>
 
+#include "error.h"
 #include "sound.h"
-#include "error_p.h"
 
 bool
 sound_open(struct sound *snd, const char *path)
@@ -31,7 +31,7 @@
 	assert(path);
 
 	if (!(snd->handle = Mix_LoadMUS(path)))
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	return true;
 }
@@ -46,7 +46,7 @@
 
 	if (!(ops = SDL_RWFromConstMem(buffer, buffersz)) ||
 	    !(snd->handle = Mix_LoadMUS_RW(ops, true)))
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	return true;
 }
@@ -61,7 +61,7 @@
 	if (snd->flags & SOUND_LOOP)
 		n = -1;
 	if (Mix_PlayMusic(snd->handle, n) < 0)
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	return true;
 }
--- a/libcore/core/sound.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/sound.h	Tue Oct 20 17:39:13 2020 +0200
@@ -27,6 +27,8 @@
 #include <stdbool.h>
 #include <stddef.h>
 
+#include "plat.h"
+
 /**
  * \brief Sound flags.
  */
@@ -53,7 +55,7 @@
  * \return False on errors.
  */
 bool
-sound_open(struct sound *snd, const char *path);
+sound_open(struct sound *snd, const char *path) PLAT_NODISCARD;
 
 /**
  * Open a sound audio from a buffer.
--- a/libcore/core/sprite.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/sprite.c	Tue Oct 20 17:39:13 2020 +0200
@@ -46,14 +46,14 @@
 	return texture_ok(sprite->texture) && sprite->cellw != 0 && sprite->cellh != 0;
 }
 
-void
+bool
 sprite_draw(struct sprite *sprite, unsigned int r, unsigned int c, int x, int y)
 {
 	assert(sprite_ok(sprite));
 	assert(r < sprite->nrows);
 	assert(c < sprite->ncols);
 
-	texture_scale(
+	return texture_scale(
 		sprite->texture,
 		c * sprite->cellw,      /* src y */
 		r * sprite->cellh,      /* src x */
--- a/libcore/core/sprite.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/sprite.h	Tue Oct 20 17:39:13 2020 +0200
@@ -87,7 +87,7 @@
  * Tells if the sprite has a texture and isn't null sized.
  *
  * \param sprite the sprite to check (may be NULL)
- * \return True if it is initialized correctly
+ * \return True if it is initialized correctly.
  */
 bool
 sprite_ok(const struct sprite *sprite);
@@ -103,8 +103,9 @@
  * \param c the column number
  * \param x the X destination
  * \param y the Y destination
+ * \return False in case of rendering error.
  */
-void
+bool
 sprite_draw(struct sprite *sprite, unsigned int r, unsigned int c, int x, int y);
 
 #endif /* !MOLKO_SPRITE_H */
--- a/libcore/core/sys.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/sys.c	Tue Oct 20 17:39:13 2020 +0200
@@ -32,7 +32,6 @@
 #endif
 
 #include "error.h"
-#include "error_p.h"
 #include "sys.h"
 
 #if defined(_WIN32)
@@ -107,15 +106,15 @@
 #endif
 
 	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 	if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG)
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 	if (TTF_Init() < 0)
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 	if (Mix_Init(MIX_INIT_OGG) != MIX_INIT_OGG)
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 	if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096) < 0)
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	return true;
 }
--- a/libcore/core/sys.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/sys.h	Tue Oct 20 17:39:13 2020 +0200
@@ -39,7 +39,7 @@
  * \return False on error.
  */
 bool
-sys_init(void);
+sys_init(void) PLAT_NODISCARD;
 
 /**
  * Get the base system directory path.
--- a/libcore/core/texture.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/texture.c	Tue Oct 20 17:39:13 2020 +0200
@@ -19,7 +19,6 @@
 #include <assert.h>
 
 #include "error.h"
-#include "error_p.h"
 #include "texture.h"
 #include "texture_p.h"
 #include "util.h"
@@ -36,7 +35,7 @@
 
 	if (!tex->handle) {
 		tex->w = tex->h = 0;
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 	}
 
 	tex->w = w;
@@ -64,7 +63,7 @@
 	};
 
 	if (SDL_RenderCopy(RENDERER(), tex->handle, NULL, &dst) < 0)
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	return true;
 }
@@ -95,7 +94,7 @@
 	};
 
 	if (SDL_RenderCopyEx(RENDERER(), tex->handle, &src, &dst, angle, NULL, SDL_FLIP_NONE) < 0)
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	return true;
 }
@@ -121,7 +120,7 @@
 
 	if (!(tex->handle = SDL_CreateTextureFromSurface(RENDERER(), surface))) {
 		tex->w = tex->h = 0;
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 	}
 
 	tex->w = surface->w;
--- a/libcore/core/texture.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/texture.h	Tue Oct 20 17:39:13 2020 +0200
@@ -29,6 +29,8 @@
 
 #include <stdbool.h>
 
+#include "plat.h"
+
 /**
  * \brief Texture object.
  */
@@ -48,7 +50,7 @@
  * \return False on error.
  */
 bool
-texture_new(struct texture *tex, unsigned int w, unsigned int h);
+texture_new(struct texture *tex, unsigned int w, unsigned int h) PLAT_NODISCARD;
 
 /**
  * Check if the texture is valid.
--- a/libcore/core/util.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/util.c	Tue Oct 20 17:39:13 2020 +0200
@@ -59,48 +59,6 @@
 	return memcpy(mem, ptr, size);
 }
 
-char *
-eprintf(const char *fmt, ...)
-{
-	assert(fmt);
-
-	va_list ap;
-	char *ret;
-
-	va_start(ap, fmt);
-	ret = evprintf(fmt, ap);
-	va_end(ap);
-
-	return ret;
-}
-
-char *
-evprintf(const char *fmt, va_list args)
-{
-	assert(fmt);
-
-	va_list ap;
-	int size;
-	char *ret;
-
-	/* Count number of bytes required. */
-	va_copy(ap, args);
-
-	if ((size = vsnprintf(NULL, 0, fmt, ap)) < 0)
-		panicf("%s", strerror(errno));
-
-	/* Do actual copy. */
-	ret = emalloc(size + 1);
-	va_copy(ap, args);
-
-	if (vsnprintf(ret, size, fmt, ap) != size) {
-		free(ret);
-		panicf("%s", strerror(errno));
-	}
-
-	return ret;
-}
-
 void
 delay(unsigned int ms)
 {
--- a/libcore/core/util.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/util.h	Tue Oct 20 17:39:13 2020 +0200
@@ -51,7 +51,7 @@
  * \post returned pointer will never be NULL
  */
 void *
-emalloc(size_t size);
+emalloc(size_t size) PLAT_NODISCARD;
 
 /**
  * Wrapper around calloc(3) that exits on allocation failure.
@@ -62,7 +62,7 @@
  * \post returned pointer will never be NULL
  */
 void *
-ecalloc(size_t n, size_t size);
+ecalloc(size_t n, size_t size) PLAT_NODISCARD;
 
 /**
  * Copy the region specified by ptr.
@@ -74,25 +74,7 @@
  * \post returned pointer will never be NULL
  */
 void *
-ememdup(const void *ptr, size_t size);
-
-/**
- * Create a dynamically allocated string in the printf(3) format string.
- *
- * \pre fmt != NULL
- * \return The heap allocated string.
- * \post Returned string will never be NULL.
- */
-char *
-eprintf(const char *fmt, ...) PLAT_PRINTF(1, 2);
-
-/**
- * Similar to \ref eprintf with arguments pointer.
- *
- * \copydoc eprintf
- */
-char *
-evprintf(const char *fmt, va_list ap) PLAT_PRINTF(1, 0);
+ememdup(const void *ptr, size_t size) PLAT_NODISCARD;
 
 /**
  * Put the thread to sleep for a given amount of milliseconds.
--- a/libcore/core/window.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/window.c	Tue Oct 20 17:39:13 2020 +0200
@@ -21,7 +21,7 @@
 
 #include <SDL.h>
 
-#include "error_p.h"
+#include "error.h"
 #include "util.h"
 #include "window.h"
 #include "window_p.h"
@@ -64,7 +64,7 @@
 
 	if (SDL_CreateWindowAndRenderer(w, h, SDL_WINDOW_OPENGL,
 	    &handle.win, &handle.renderer) < 0)
-		return error_sdl();
+		return errorf("%s", SDL_GetError());
 
 	SDL_SetWindowTitle(handle.win, title);
 
--- a/libcore/core/window.h	Tue Oct 20 15:09:39 2020 +0200
+++ b/libcore/core/window.h	Tue Oct 20 17:39:13 2020 +0200
@@ -27,6 +27,8 @@
 
 #include <stdbool.h>
 
+#include "plat.h"
+
 /**
  * \brief Global exposed window structure.
  */
@@ -40,14 +42,14 @@
  * \brief Window mouse cursor.
  */
 enum window_cursor {
-	WINDOW_CURSOR_ARROW,
-	WINDOW_CURSOR_EDIT,
-	WINDOW_CURSOR_WAIT,
-	WINDOW_CURSOR_CROSSHAIR,
-	WINDOW_CURSOR_SIZE,
-	WINDOW_CURSOR_NO,
-	WINDOW_CURSOR_HAND,
-	WINDOW_CURSOR_LAST
+	WINDOW_CURSOR_ARROW,            /*!< Standard arrow.*/
+	WINDOW_CURSOR_EDIT,             /*!< Text edit cursor "I". */
+	WINDOW_CURSOR_WAIT,             /*!< Busy cursor. */
+	WINDOW_CURSOR_CROSSHAIR,        /*!< Cross-hair for selection. */
+	WINDOW_CURSOR_SIZE,             /*!< Size/moving. */
+	WINDOW_CURSOR_NO,               /*!< Action forbidden. */
+	WINDOW_CURSOR_HAND,             /*!< Hand. */
+	WINDOW_CURSOR_LAST              /*!< Number of cursors. */
 };
 
 /**
@@ -65,7 +67,7 @@
  * \return true on success
  */
 bool
-window_open(const char *title, unsigned int width, unsigned int height);
+window_open(const char *title, unsigned int width, unsigned int height) PLAT_NODISCARD;
 
 /**
  * Change the window cursor.
--- a/librpg/rpg/map.c	Tue Oct 20 15:09:39 2020 +0200
+++ b/librpg/rpg/map.c	Tue Oct 20 17:39:13 2020 +0200
@@ -22,7 +22,6 @@
 #include <string.h>
 
 #include <core/error.h>
-#include <core/error_p.h>
 #include <core/image.h>
 #include <core/painter.h>
 #include <core/sprite.h>
--- a/tests/CMakeLists.txt	Tue Oct 20 15:09:39 2020 +0200
+++ b/tests/CMakeLists.txt	Tue Oct 20 17:39:13 2020 +0200
@@ -34,7 +34,6 @@
 		${tests_SOURCE_DIR}/assets/maps/error-width.map
 		${tests_SOURCE_DIR}/assets/maps/sample-map.map
 )
-molko_define_test(TARGET rbuf SOURCES test-rbuf.c)
 molko_define_test(TARGET save SOURCES test-save.c)
 molko_define_test(TARGET state SOURCES test-state.c)
 molko_define_test(TARGET drawable SOURCES test-drawable.c)
--- a/tests/test-rbuf.c	Tue Oct 20 15:09:39 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-/*
- * test-rbuf.c -- test error routines
- *
- * Copyright (c) 2020 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#define GREATEST_USE_ABBREVS 0
-#include <greatest.h>
-
-#include <core/rbuf.h>
-
-/* Don't use "" to avoid '\0' */
-const char data1[] = { 'a', 'b', 'c', '\n', 'd', 'e', 'f', '\n' };
-const char data2[] = { 'a', 'b', 'c', '\n', 'd', 'e', 'f' };
-const char data3[] = { 'a', 'b', 'c', '\n', '\n', 'd', 'e', 'f', '\n' };
-const char data4[] = { 'a', 'b', 'c', '\n', 'd', 'e', 'f', 'g', 'h', '\n' };
-
-GREATEST_TEST
-simple(void)
-{
-	struct rbuf rb;
-	char line[128];
-
-	rbuf_open(&rb, data1, sizeof (data1));
-
-	memset(line, '?', sizeof (line));
-	GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line)));
-	GREATEST_ASSERT_STR_EQ("abc", line);
-
-	memset(line, '?', sizeof (line));
-	GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line)));
-	GREATEST_ASSERT_STR_EQ("def", line);
-
-	GREATEST_PASS();
-}
-
-GREATEST_TEST
-simple_noeol(void)
-{
-	struct rbuf rb;
-	char line[128];
-
-	rbuf_open(&rb, data2, sizeof (data2));
-
-	memset(line, '?', sizeof (line));
-	GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line)));
-	GREATEST_ASSERT_STR_EQ("abc", line);
-
-	memset(line, '?', sizeof (line));
-	GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line)));
-	GREATEST_ASSERT_STR_EQ("def", line);
-
-	GREATEST_PASS();
-}
-
-GREATEST_TEST
-simple_emptylines(void)
-{
-	struct rbuf rb;
-	char line[128];
-
-	rbuf_open(&rb, data3, sizeof (data3));
-
-	memset(line, '?', sizeof (line));
-	GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line)));
-	GREATEST_ASSERT_STR_EQ("abc", line);
-
-	memset(line, '?', sizeof (line));
-	GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line)));
-	GREATEST_ASSERT_STR_EQ("", line);
-
-	memset(line, '?', sizeof (line));
-	GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line)));
-	GREATEST_ASSERT_STR_EQ("def", line);
-
-	GREATEST_PASS();
-}
-
-GREATEST_SUITE(simple_suite)
-{
-	GREATEST_RUN_TEST(simple);
-	GREATEST_RUN_TEST(simple_noeol);
-	GREATEST_RUN_TEST(simple_emptylines);
-}
-
-GREATEST_TEST
-fail_toosmall(void)
-{
-	struct rbuf rb;
-	char line[4];
-
-	rbuf_open(&rb, data4, sizeof (data4));
-
-	memset(line, '?', sizeof (line));
-	GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line)));
-	GREATEST_ASSERT_STR_EQ("abc", line);
-
-	memset(line, '?', sizeof (line));
-	GREATEST_ASSERT(!rbuf_readline(&rb, line, sizeof (line)));
-
-	GREATEST_PASS();
-}
-
-GREATEST_TEST
-fail_end(void)
-{
-	struct rbuf rb;
-	char line[128];
-
-	rbuf_open(&rb, data1, sizeof (data1));
-
-	memset(line, '?', sizeof (line));
-	GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line)));
-	GREATEST_ASSERT_STR_EQ("abc", line);
-
-	memset(line, '?', sizeof (line));
-	GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line)));
-	GREATEST_ASSERT_STR_EQ("def", line);
-
-	memset(line, '?', sizeof (line));
-	GREATEST_ASSERT(!rbuf_readline(&rb, line, sizeof (line)));
-
-	GREATEST_PASS();
-}
-
-GREATEST_SUITE(fail_suite)
-{
-	GREATEST_RUN_TEST(fail_toosmall);
-	GREATEST_RUN_TEST(fail_end);
-}
-
-GREATEST_MAIN_DEFS();
-
-int
-main(int argc, char **argv)
-{
-	GREATEST_MAIN_BEGIN();
-	GREATEST_RUN_SUITE(simple_suite);
-	GREATEST_RUN_SUITE(fail_suite);
-	GREATEST_MAIN_END();
-}