std1.0.0-beta-7 SafeC docs

Source audio/audio_error.sc

View in the repository

// SafeC Standard Library — audio & MIDI: AudioError and the small string
// helpers std/audio uses (see audio_error.h).
#pragma once
#include <std/audio/audio_error.h>

namespace std {

unsigned long audio_strlen_(const ?&char s) {
    unsigned long n = 0UL;
    unsafe {
        const char* p = (const char*)s;
        if (p == (const char*)0) return 0UL;
        // Bounded, so LLVM doesn't turn it into a strlen() call: wasm32
        // modules have no libc to import one from.
        while (n < 0x7FFFFFFFUL && p[n] != (char)0) n = n + 1UL;
    }
    return n;
}

void audio_strcpy_(&char dst, unsigned long cap, const ?&char src) {
    if (cap == 0UL) return;
    unsafe {
        char* d = (char*)dst;
        const char* s = (const char*)src;
        unsigned long i = 0UL;
        if (s != (const char*)0) {
            while (i + 1UL < cap && s[i] != (char)0) { d[i] = s[i]; i = i + 1UL; }
        }
        d[i] = (char)0;
    }
}

void audio_strcat_(&char dst, unsigned long cap, const ?&char src) {
    unsigned long n = audio_strlen_(dst);
    if (n + 1UL >= cap) return;
    unsafe {
        char* d = (char*)dst;
        audio_strcpy_((&char)(d + n), cap - n, src);
    }
}

int audio_streq_(const ?&char a, const ?&char b) {
    unsafe {
        const char* x = (const char*)a;
        const char* y = (const char*)b;
        if (x == (const char*)0 || y == (const char*)0) return x == y;
        unsigned long i = 0UL;
        while (x[i] != (char)0 && x[i] == y[i]) i = i + 1UL;
        return x[i] == y[i];
    }
}

int audio_strprefix_(const ?&char s, const ?&char prefix) {
    unsafe {
        const char* x = (const char*)s;
        const char* p = (const char*)prefix;
        if (x == (const char*)0 || p == (const char*)0) return 0;
        unsigned long i = 0UL;
        while (p[i] != (char)0) {
            if (x[i] != p[i]) return 0;
            i = i + 1UL;
        }
        return 1;
    }
}

void audio_strcat_int_(&char dst, unsigned long cap, long long v) {
    char tmp[24];
    int n = 0;
    int neg = v < 0LL;
    unsigned long long u = neg ? (unsigned long long)(0LL - v) : (unsigned long long)v;
    if (u == 0ULL) { tmp[0] = '0'; n = 1; }
    while (u > 0ULL && n < 22) { tmp[n] = (char)(48 + (int)(u % 10ULL)); u = u / 10ULL; n = n + 1; }
    char out[24];
    int k = 0;
    if (neg) { out[0] = '-'; k = 1; }
    while (n > 0) { n = n - 1; out[k] = tmp[n]; k = k + 1; }
    out[k] = (char)0;
    audio_strcat_(dst, cap, &out[0]);
}

void audio_strcat_hex_(&char dst, unsigned long cap, unsigned int v) {
    char out[11];
    out[0] = '0';
    out[1] = 'x';
    for (int i = 0; i < 8; i = i + 1) {
        unsigned int nib = (v >> (unsigned int)(28 - 4 * i)) & 0xFU;
        out[2 + i] = (char)(nib < 10U ? 48U + nib : 55U + nib);
    }
    out[10] = (char)0;
    audio_strcat_(dst, cap, &out[0]);
}

struct AudioError AudioError::none() {
    struct AudioError e;
    e.code = AUDIO_OK;
    e.message[0] = (char)0;
    return e;
}

struct AudioError AudioError::make(int code, const &char message) {
    struct AudioError e;
    e.code = code;
    audio_strcpy_(&e.message[0], (unsigned long)AUDIO_ERROR_MESSAGE_MAX, message);
    return e;
}

struct AudioError AudioError::make2(int code, const &char prefix, const &char detail) {
    struct AudioError e;
    e.code = code;
    audio_strcpy_(&e.message[0], (unsigned long)AUDIO_ERROR_MESSAGE_MAX, prefix);
    audio_strcat_(&e.message[0], (unsigned long)AUDIO_ERROR_MESSAGE_MAX, ": ");
    audio_strcat_(&e.message[0], (unsigned long)AUDIO_ERROR_MESSAGE_MAX, detail);
    return e;
}

struct AudioError AudioError::make_code(int code, const &char prefix, long long value) {
    struct AudioError e;
    e.code = code;
    audio_strcpy_(&e.message[0], (unsigned long)AUDIO_ERROR_MESSAGE_MAX, prefix);
    audio_strcat_(&e.message[0], (unsigned long)AUDIO_ERROR_MESSAGE_MAX, " (");
    audio_strcat_int_(&e.message[0], (unsigned long)AUDIO_ERROR_MESSAGE_MAX, value);
    audio_strcat_(&e.message[0], (unsigned long)AUDIO_ERROR_MESSAGE_MAX, ")");
    return e;
}

int AudioError::ok() const { return self.code == AUDIO_OK || self.code == AUDIO_ERR_WARNING; }
int AudioError::failed() const { return !(self.code == AUDIO_OK || self.code == AUDIO_ERR_WARNING); }

int audio_fail_(&AudioError e, int code, const &char message) {
    *e = AudioError::make(code, message);
    return code;
}
int audio_fail2_(&AudioError e, int code, const &char prefix, const &char detail) {
    *e = AudioError::make2(code, prefix, detail);
    return code;
}
int audio_fail_code_(&AudioError e, int code, const &char prefix, long long value) {
    *e = AudioError::make_code(code, prefix, value);
    return code;
}

int audio_fail_hex_(&AudioError e, int code, const &char prefix, unsigned int value) {
    e.code = code;
    audio_strcpy_(&e.message[0], (unsigned long)AUDIO_ERROR_MESSAGE_MAX, prefix);
    audio_strcat_(&e.message[0], (unsigned long)AUDIO_ERROR_MESSAGE_MAX, " (");
    audio_strcat_hex_(&e.message[0], (unsigned long)AUDIO_ERROR_MESSAGE_MAX, value);
    audio_strcat_(&e.message[0], (unsigned long)AUDIO_ERROR_MESSAGE_MAX, ")");
    return code;
}

const &char audio_error_name(int code) {
    if (code == AUDIO_OK) return "ok";
    if (code == AUDIO_ERR_WARNING) return "warning";
    if (code == AUDIO_ERR_UNSUPPORTED) return "unsupported";
    if (code == AUDIO_ERR_NO_DEVICES) return "no devices";
    if (code == AUDIO_ERR_INVALID_DEVICE) return "invalid device";
    if (code == AUDIO_ERR_INVALID_PARAM) return "invalid parameter";
    if (code == AUDIO_ERR_INVALID_USE) return "invalid use";
    if (code == AUDIO_ERR_DEVICE_BUSY) return "device busy";
    if (code == AUDIO_ERR_SYSTEM) return "system error";
    if (code == AUDIO_ERR_THREAD) return "thread error";
    if (code == AUDIO_ERR_NO_MEMORY) return "out of memory";
    if (code == AUDIO_ERR_UNAVAILABLE) return "unavailable";
    return "unknown error";
}

} // namespace std