diff --git a/bazel/wrlib/BUILD.bazel b/bazel/wrlib/BUILD.bazel index ae593512..d11b3ba0 100644 --- a/bazel/wrlib/BUILD.bazel +++ b/bazel/wrlib/BUILD.bazel @@ -1,9 +1,26 @@ load("@rules_rust//rust:defs.bzl", "rust_library") +rust_library( + name = "error_code", + srcs = ["error_code.rs"], + edition = "2021", + visibility = ["//visibility:public"], +) + +cc_test( + name = "error_code_cc_test", + srcs = ["error_code_test.c"], + deps = [":error_code"], +) + rust_library( name = "wrlib_rs", srcs = ["wrlib.rs"], - deps = [":wrlib"], + deps = [ + ":ppm", + ":rimage", + ":wrlib", + ], visibility = ["//visibility:public"], edition = "2021", ) diff --git a/bazel/wrlib/error_code.rs b/bazel/wrlib/error_code.rs new file mode 100644 index 00000000..4c073408 --- /dev/null +++ b/bazel/wrlib/error_code.rs @@ -0,0 +1,107 @@ +use std::{ + os::raw::{c_char, c_int}, + sync::RwLock, +}; + +static ERROR_STATUS: RwLock = RwLock::new(ErrorCode::None); + +#[repr(i16)] +#[derive(Debug, Clone, Copy)] +pub enum ErrorCode { + /// No known error status. + None = 0, + + /// Can't open file. + Open = 1, + + /// Error reading from file. + Read = 2, + + /// Error writing to file. + Write = 3, + + /// Out of memory. + NoMemory = 4, + + /// Out of color cells. + NoColor = 5, + + /// Image file is corrupted or invalid. + BadImageFile = 6, + + /// Image file format is unknown. + BadFormat = 7, + + /// No such image index in file. + BadIndex = 8, + + /// Invalid visual ID requested for context. + BadVisualId = 16, + + /// Failed to create std colormap. + StdCmapFail = 17, + + /// Internal X11 error. + XError = 127, + + /// Should not happen. + Internal = 128, +} + +/// Sets the global error status in a thread-safe way. Panics if the error +/// status lock has been poisoned. +pub fn wraster_set_error_code(code: ErrorCode) { + *ERROR_STATUS.write().unwrap() = code; +} + +/// Sets the global error status to a literal `value`. Panics if `value` does +/// not correspond to a valid error value. +#[no_mangle] +pub unsafe extern "C" fn wraster_report_error_code(value: c_int) { + let value = match value { + 0 => ErrorCode::None, + 1 => ErrorCode::Open, + 2 => ErrorCode::Read, + 3 => ErrorCode::Write, + 4 => ErrorCode::NoMemory, + 5 => ErrorCode::NoColor, + 6 => ErrorCode::BadImageFile, + 7 => ErrorCode::BadFormat, + 8 => ErrorCode::BadIndex, + 16 => ErrorCode::BadVisualId, + 17 => ErrorCode::StdCmapFail, + 127 => ErrorCode::XError, + 128 => ErrorCode::Internal, + _ => panic!("unknown error code: {}", value), + }; + *ERROR_STATUS.write().unwrap() = value; +} + +/// Returns the current error status. Panics if the error status lock has been +/// poisoned. +#[no_mangle] +pub extern "C" fn wraster_current_error_code() -> i16 { + *ERROR_STATUS.read().unwrap() as i16 +} + +/// Returns a human-readable description of the current error status. Panics if +/// the error status lock has been poisoned. +#[no_mangle] +pub extern "C" fn wraster_current_error_message() -> *const c_char { + // TODO: i18n of these messages. + match *ERROR_STATUS.read().unwrap() { + ErrorCode::None => c"no error".as_ptr(), + ErrorCode::Open => c"could not open file".as_ptr(), + ErrorCode::Read => c"error reading from file".as_ptr(), + ErrorCode::Write => c"error writing to file".as_ptr(), + ErrorCode::NoMemory => c"out of memory".as_ptr(), + ErrorCode::NoColor => c"out of color cells".as_ptr(), + ErrorCode::BadImageFile => c"invalid or corrupted image file".as_ptr(), + ErrorCode::BadFormat => c"image format is not supported".as_ptr(), + ErrorCode::BadIndex => c"file does not contain requested image index".as_ptr(), + ErrorCode::BadVisualId => c"request for an invalid Visual ID".as_ptr(), + ErrorCode::StdCmapFail => c"failed to create X standard colormap".as_ptr(), + ErrorCode::XError => c"internal X error".as_ptr(), + ErrorCode::Internal => c"internal error".as_ptr(), + } +} diff --git a/bazel/wrlib/error_code_test.c b/bazel/wrlib/error_code_test.c new file mode 100644 index 00000000..2010e6f0 --- /dev/null +++ b/bazel/wrlib/error_code_test.c @@ -0,0 +1,40 @@ +#include +#include + +/* error codes */ +#define RERR_NONE 0 +#define RERR_OPEN 1 /* cant open file */ +#define RERR_READ 2 /* error reading from file */ +#define RERR_WRITE 3 /* error writing to file */ +#define RERR_NOMEMORY 4 /* out of memory */ +#define RERR_NOCOLOR 5 /* out of color cells */ +#define RERR_BADIMAGEFILE 6 /* image file is corrupted or invalid */ +#define RERR_BADFORMAT 7 /* image file format is unknown */ +#define RERR_BADINDEX 8 /* no such image index in file */ + +#define RERR_BADVISUALID 16 /* invalid visual ID requested for context */ +#define RERR_STDCMAPFAIL 17 /* failed to created std colormap */ + +#define RERR_XERROR 127 /* internal X error */ +#define RERR_INTERNAL 128 /* should not happen */ + +void wraster_report_error_code(int value); + +const char* wraster_current_error_message(); + +int wraster_current_error_code(); + +int main(int argc, char** argv) { + assert(wraster_current_error_code() == RERR_NONE); + assert(strcmp(wraster_current_error_message(), "no error") == 0); + + wraster_report_error_code(RERR_WRITE); + + assert(wraster_current_error_code() == RERR_WRITE); + assert(strcmp(wraster_current_error_message(), "error writing to file") == 0); + + wraster_report_error_code(RERR_OPEN); + + assert(wraster_current_error_code() == RERR_OPEN); + assert(strcmp(wraster_current_error_message(), "could not open file") == 0); +}