Browse Source

SIN: Reformat the whole codebase using tweaked .clang-format

yes, sorry, was actually quite well formatted (clang-format default) ... but its probably just me working on the code ever. So, i will just use my preferences here.
I find it important. visual guy and all other excuses...
master
heck 2 years ago
parent
commit
53575550f0
  1. 37
      .clang-format
  2. 2
      Makefile.conf
  3. 60
      src/base.h
  4. 18
      src/cli_main.c
  5. 69
      src/field.c
  6. 3
      src/field.h
  7. 36
      src/gbuffer.c
  8. 85
      src/gbuffer.h
  9. 76
      src/osc_out.c
  10. 25
      src/osc_out.h
  11. 94
      src/oso.c
  12. 31
      src/oso.h
  13. 147
      src/sim.c
  14. 9
      src/sim.h
  15. 95
      src/sokol_time.h
  16. 118
      src/sysmisc.c
  17. 53
      src/sysmisc.h
  18. 207
      src/term_util.c
  19. 44
      src/term_util.h
  20. 1401
      src/tui_main.c
  21. 19
      src/vmio.c
  22. 13
      src/vmio.h

37
.clang-format

@ -3,3 +3,40 @@ ReflowComments: false
MacroBlockBegin: "^BEGIN_OPERATOR" MacroBlockBegin: "^BEGIN_OPERATOR"
MacroBlockEnd: "^END_OPERATOR" MacroBlockEnd: "^END_OPERATOR"
Language: Cpp
DerivePointerAlignment: true
SortIncludes: Never
PointerAlignment: Left
AlignAfterOpenBracket: AlwaysBreak
AlignOperands: AlignAfterOperator
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
BinPackArguments: false
BinPackParameters: false
ExperimentalAutoDetectBinPacking: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: true
ColumnLimit: 100
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
PenaltyBreakBeforeFirstCallParameter: 0
PenaltyReturnTypeOnItsOwnLine: 1000000
PenaltyBreakAssignment: 1000000
PenaltyExcessCharacter: 10
IndentCaseLabels: true
IndentWidth: 4
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
SpaceAfterTemplateKeyword: false
AccessModifierOffset: -4
AllowShortBlocksOnASingleLine: Always
IndentPPDirectives: BeforeHash
IndentExternBlock: Indent
Cpp11BracedListStyle: false

2
Makefile.conf

@ -1,4 +1,4 @@
TARGET=tui_main TARGET=orca_tui
LANG_VERSION=c99 LANG_VERSION=c99

60
src/base.h

@ -9,54 +9,52 @@
// clang or gcc or other // clang or gcc or other
#if defined(__clang__) #if defined(__clang__)
#define ORCA_OPT_MINSIZE __attribute__((minsize)) #define ORCA_OPT_MINSIZE __attribute__((minsize))
#elif defined(__GNUC__) #elif defined(__GNUC__)
#define ORCA_OPT_MINSIZE __attribute__((optimize("Os"))) #define ORCA_OPT_MINSIZE __attribute__((optimize("Os")))
#else #else
#define ORCA_OPT_MINSIZE #define ORCA_OPT_MINSIZE
#endif #endif
// (gcc / clang) or msvc or other // (gcc / clang) or msvc or other
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#define ORCA_FORCEINLINE __attribute__((always_inline)) inline #define ORCA_FORCEINLINE __attribute__((always_inline)) inline
#define ORCA_NOINLINE __attribute__((noinline)) #define ORCA_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define ORCA_FORCEINLINE __forceinline #define ORCA_FORCEINLINE __forceinline
#define ORCA_NOINLINE __declspec(noinline) #define ORCA_NOINLINE __declspec(noinline)
#else #else
#define ORCA_FORCEINLINE inline #define ORCA_FORCEINLINE inline
#define ORCA_NOINLINE #define ORCA_NOINLINE
#endif #endif
// (gcc / clang) or other // (gcc / clang) or other
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#define ORCA_ASSUME_ALIGNED(_ptr, _alignment) \ #define ORCA_ASSUME_ALIGNED(_ptr, _alignment) __builtin_assume_aligned(_ptr, _alignment)
__builtin_assume_aligned(_ptr, _alignment) #define ORCA_PURE __attribute__((pure))
#define ORCA_PURE __attribute__((pure)) #define ORCA_LIKELY(_x) __builtin_expect(_x, 1)
#define ORCA_LIKELY(_x) __builtin_expect(_x, 1) #define ORCA_UNLIKELY(_x) __builtin_expect(_x, 0)
#define ORCA_UNLIKELY(_x) __builtin_expect(_x, 0) #define ORCA_OK_IF_UNUSED __attribute__((unused))
#define ORCA_OK_IF_UNUSED __attribute__((unused)) #define ORCA_UNREACHABLE __builtin_unreachable()
#define ORCA_UNREACHABLE __builtin_unreachable()
#else #else
#define ORCA_ASSUME_ALIGNED(_ptr, _alignment) (_ptr) #define ORCA_ASSUME_ALIGNED(_ptr, _alignment) (_ptr)
#define ORCA_PURE #define ORCA_PURE
#define ORCA_LIKELY(_x) (_x) #define ORCA_LIKELY(_x) (_x)
#define ORCA_UNLIKELY(_x) (_x) #define ORCA_UNLIKELY(_x) (_x)
#define ORCA_OK_IF_UNUSED #define ORCA_OK_IF_UNUSED
#define ORCA_UNREACHABLE assert(false) #define ORCA_UNREACHABLE assert(false)
#endif #endif
// array count, safer on gcc/clang // array count, safer on gcc/clang
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#define ORCA_ASSERT_IS_ARRAY(_array) \ #define ORCA_ASSERT_IS_ARRAY(_array) \
(sizeof(char[1 - 2 * __builtin_types_compatible_p( \ (sizeof(char[1 - 2 * __builtin_types_compatible_p(__typeof(_array), __typeof(&(_array)[0]))]) - \
__typeof(_array), __typeof(&(_array)[0]))]) - \
1) 1)
#define ORCA_ARRAY_COUNTOF(_array) \ #define ORCA_ARRAY_COUNTOF(_array) \
(sizeof(_array) / sizeof((_array)[0]) + ORCA_ASSERT_IS_ARRAY(_array)) (sizeof(_array) / sizeof((_array)[0]) + ORCA_ASSERT_IS_ARRAY(_array))
#else #else
// pray // pray
#define ORCA_ARRAY_COUNTOF(_array) (sizeof(_array) / sizeof(_array[0])) #define ORCA_ARRAY_COUNTOF(_array) (sizeof(_array) / sizeof(_array[0]))
#endif #endif
#define ORCA_Y_MAX UINT16_MAX #define ORCA_Y_MAX UINT16_MAX
@ -76,7 +74,8 @@ typedef ssize_t Isz;
typedef char Glyph; typedef char Glyph;
typedef U8 Mark; typedef U8 Mark;
ORCA_FORCEINLINE static Usz orca_round_up_power2(Usz x) { ORCA_FORCEINLINE static Usz orca_round_up_power2(Usz x)
{
assert(x <= SIZE_MAX / 2 + 1); assert(x <= SIZE_MAX / 2 + 1);
x -= 1; x -= 1;
x |= x >> 1; x |= x >> 1;
@ -91,7 +90,8 @@ ORCA_FORCEINLINE static Usz orca_round_up_power2(Usz x) {
} }
ORCA_OK_IF_UNUSED ORCA_OK_IF_UNUSED
static bool orca_is_valid_glyph(Glyph c) { static bool orca_is_valid_glyph(Glyph c)
{
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9')
return true; return true;
if (c >= 'A' && c <= 'Z') if (c >= 'A' && c <= 'Z')

18
src/cli_main.c

@ -5,7 +5,8 @@
#include "vmio.h" #include "vmio.h"
#include <getopt.h> #include <getopt.h>
static ORCA_NOINLINE void usage(void) { // clang-format off static ORCA_NOINLINE void usage(void)
{ // clang-format off
fprintf(stderr, fprintf(stderr,
"Usage: cli [options] infile\n\n" "Usage: cli [options] infile\n\n"
"Options:\n" "Options:\n"
@ -16,10 +17,11 @@ fprintf(stderr,
" -h or --help Print this message and exit.\n" " -h or --help Print this message and exit.\n"
);} // clang-format on );} // clang-format on
int main(int argc, char **argv) { int main(int argc, char **argv)
static struct option cli_options[] = {{"help", no_argument, 0, 'h'}, {
{"quiet", no_argument, 0, 'q'}, static struct option cli_options[] = { { "help", no_argument, 0, 'h' },
{NULL, 0, NULL, 0}}; { "quiet", no_argument, 0, 'q' },
{ NULL, 0, NULL, 0 } };
char *input_file = NULL; char *input_file = NULL;
int ticks = 1; int ticks = 1;
@ -33,7 +35,8 @@ int main(int argc, char **argv) {
case 't': case 't':
ticks = atoi(optarg); ticks = atoi(optarg);
if (ticks == 0 && strcmp(optarg, "0")) { if (ticks == 0 && strcmp(optarg, "0")) {
fprintf(stderr, fprintf(
stderr,
"Bad timestep argument %s.\n" "Bad timestep argument %s.\n"
"Must be 0 or a positive integer.\n", "Must be 0 or a positive integer.\n",
optarg); optarg);
@ -88,8 +91,7 @@ int main(int argc, char **argv) {
for (Usz i = 0; i < max_ticks; ++i) { for (Usz i = 0; i < max_ticks; ++i) {
mbuffer_clear(mbuf_r.buffer, field.height, field.width); mbuffer_clear(mbuf_r.buffer, field.height, field.width);
oevent_list_clear(&oevent_list); oevent_list_clear(&oevent_list);
orca_run(field.buffer, mbuf_r.buffer, field.height, field.width, i, orca_run(field.buffer, mbuf_r.buffer, field.height, field.width, i, &oevent_list, 0);
&oevent_list, 0);
} }
mbuf_reusable_deinit(&mbuf_r); mbuf_reusable_deinit(&mbuf_r);
oevent_list_deinit(&oevent_list); oevent_list_deinit(&oevent_list);

69
src/field.c

@ -2,13 +2,15 @@
#include "gbuffer.h" #include "gbuffer.h"
#include <ctype.h> #include <ctype.h>
void field_init(Field *f) { void field_init(Field *f)
{
f->buffer = NULL; f->buffer = NULL;
f->height = 0; f->height = 0;
f->width = 0; f->width = 0;
} }
void field_init_fill(Field *f, Usz height, Usz width, Glyph fill_char) { void field_init_fill(Field *f, Usz height, Usz width, Glyph fill_char)
{
assert(height <= ORCA_Y_MAX && width <= ORCA_X_MAX); assert(height <= ORCA_Y_MAX && width <= ORCA_X_MAX);
Usz num_cells = height * width; Usz num_cells = height * width;
f->buffer = malloc(num_cells * sizeof(Glyph)); f->buffer = malloc(num_cells * sizeof(Glyph));
@ -17,9 +19,13 @@ void field_init_fill(Field *f, Usz height, Usz width, Glyph fill_char) {
f->width = (U16)width; f->width = (U16)width;
} }
void field_deinit(Field *f) { free(f->buffer); } void field_deinit(Field *f)
{
free(f->buffer);
}
void field_resize_raw(Field *f, Usz height, Usz width) { void field_resize_raw(Field *f, Usz height, Usz width)
{
assert(height <= ORCA_Y_MAX && width <= ORCA_X_MAX); assert(height <= ORCA_Y_MAX && width <= ORCA_X_MAX);
Usz cells = height * width; Usz cells = height * width;
f->buffer = realloc(f->buffer, cells * sizeof(Glyph)); f->buffer = realloc(f->buffer, cells * sizeof(Glyph));
@ -27,23 +33,42 @@ void field_resize_raw(Field *f, Usz height, Usz width) {
f->width = (U16)width; f->width = (U16)width;
} }
void field_resize_raw_if_necessary(Field *field, Usz height, Usz width) { void field_resize_raw_if_necessary(Field *field, Usz height, Usz width)
{
if (field->height != height || field->width != width) { if (field->height != height || field->width != width) {
field_resize_raw(field, height, width); field_resize_raw(field, height, width);
} }
} }
void field_copy(Field *src, Field *dest) { void field_copy(Field *src, Field *dest)
{
field_resize_raw_if_necessary(dest, src->height, src->width); field_resize_raw_if_necessary(dest, src->height, src->width);
gbuffer_copy_subrect(src->buffer, dest->buffer, src->height, src->width, gbuffer_copy_subrect(
dest->height, dest->width, 0, 0, 0, 0, src->height, src->buffer,
dest->buffer,
src->height,
src->width,
dest->height,
dest->width,
0,
0,
0,
0,
src->height,
src->width); src->width);
} }
static inline bool glyph_char_is_valid(char c) { return c >= '!' && c <= '~'; } static inline bool glyph_char_is_valid(char c)
{
return c >= '!' && c <= '~';
}
void field_fput(Field *f, FILE *stream) { void field_fput(Field *f, FILE *stream)
enum { Column_buffer_count = 4096 }; {
enum
{
Column_buffer_count = 4096
};
char out_buffer[Column_buffer_count]; char out_buffer[Column_buffer_count];
Usz f_height = f->height; Usz f_height = f->height;
Usz f_width = f->width; Usz f_width = f->width;
@ -62,12 +87,16 @@ void field_fput(Field *f, FILE *stream) {
} }
} }
Field_load_error field_load_file(char const *filepath, Field *field) { Field_load_error field_load_file(char const *filepath, Field *field)
{
FILE *file = fopen(filepath, "r"); FILE *file = fopen(filepath, "r");
if (file == NULL) { if (file == NULL) {
return Field_load_error_cant_open_file; return Field_load_error_cant_open_file;
} }
enum { Bufsize = 4096 }; enum
{
Bufsize = 4096
};
char buf[Bufsize]; char buf[Bufsize];
Usz first_row_columns = 0; Usz first_row_columns = 0;
Usz rows = 0; Usz rows = 0;
@ -116,7 +145,8 @@ Field_load_error field_load_file(char const *filepath, Field *field) {
return Field_load_error_ok; return Field_load_error_ok;
} }
char const *field_load_error_string(Field_load_error fle) { char const *field_load_error_string(Field_load_error fle)
{
char const *errstr = "Unknown"; char const *errstr = "Unknown";
switch (fle) { switch (fle) {
case Field_load_error_ok: case Field_load_error_ok:
@ -141,12 +171,14 @@ char const *field_load_error_string(Field_load_error fle) {
return errstr; return errstr;
} }
void mbuf_reusable_init(Mbuf_reusable *mbr) { void mbuf_reusable_init(Mbuf_reusable *mbr)
{
mbr->buffer = NULL; mbr->buffer = NULL;
mbr->capacity = 0; mbr->capacity = 0;
} }
void mbuf_reusable_ensure_size(Mbuf_reusable *mbr, Usz height, Usz width) { void mbuf_reusable_ensure_size(Mbuf_reusable *mbr, Usz height, Usz width)
{
Usz capacity = height * width; Usz capacity = height * width;
if (mbr->capacity < capacity) { if (mbr->capacity < capacity) {
mbr->buffer = realloc(mbr->buffer, capacity); mbr->buffer = realloc(mbr->buffer, capacity);
@ -154,4 +186,7 @@ void mbuf_reusable_ensure_size(Mbuf_reusable *mbr, Usz height, Usz width) {
} }
} }
void mbuf_reusable_deinit(Mbuf_reusable *mbr) { free(mbr->buffer); } void mbuf_reusable_deinit(Mbuf_reusable *mbr)
{
free(mbr->buffer);
}

3
src/field.h

@ -19,7 +19,8 @@ void field_resize_raw_if_necessary(Field *field, Usz height, Usz width);
void field_copy(Field *src, Field *dest); void field_copy(Field *src, Field *dest);
void field_fput(Field *field, FILE *stream); void field_fput(Field *field, FILE *stream);
typedef enum { typedef enum
{
Field_load_error_ok = 0, Field_load_error_ok = 0,
Field_load_error_cant_open_file = 1, Field_load_error_cant_open_file = 1,
Field_load_error_too_many_columns = 2, Field_load_error_too_many_columns = 2,

36
src/gbuffer.c

@ -1,11 +1,20 @@
#include "gbuffer.h" #include "gbuffer.h"
void gbuffer_copy_subrect(Glyph *src, Glyph *dest, Usz src_height, void gbuffer_copy_subrect(
Usz src_width, Usz dest_height, Usz dest_width, Glyph *src,
Usz src_y, Usz src_x, Usz dest_y, Usz dest_x, Glyph *dest,
Usz height, Usz width) { Usz src_height,
if (src_height <= src_y || src_width <= src_x || dest_height <= dest_y || Usz src_width,
dest_width <= dest_x) Usz dest_height,
Usz dest_width,
Usz src_y,
Usz src_x,
Usz dest_y,
Usz dest_x,
Usz height,
Usz width)
{
if (src_height <= src_y || src_width <= src_x || dest_height <= dest_y || dest_width <= dest_x)
return; return;
Usz ny_0 = src_height - src_y; Usz ny_0 = src_height - src_y;
Usz ny_1 = dest_height - dest_y; Usz ny_1 = dest_height - dest_y;
@ -48,8 +57,16 @@ void gbuffer_copy_subrect(Glyph *src, Glyph *dest, Usz src_height,
} }
} }
void gbuffer_fill_subrect(Glyph *gbuffer, Usz f_height, Usz f_width, Usz y, void gbuffer_fill_subrect(
Usz x, Usz height, Usz width, Glyph fill_char) { Glyph *gbuffer,
Usz f_height,
Usz f_width,
Usz y,
Usz x,
Usz height,
Usz width,
Glyph fill_char)
{
if (y >= f_height || x >= f_width) if (y >= f_height || x >= f_width)
return; return;
Usz rows_0 = f_height - y; Usz rows_0 = f_height - y;
@ -74,7 +91,8 @@ void gbuffer_fill_subrect(Glyph *gbuffer, Usz f_height, Usz f_width, Usz y,
} }
} }
void mbuffer_clear(Mark *mbuf, Usz height, Usz width) { void mbuffer_clear(Mark *mbuf, Usz height, Usz width)
{
Usz cleared_size = height * width; Usz cleared_size = height * width;
memset(mbuf, 0, cleared_size); memset(mbuf, 0, cleared_size);
} }

85
src/gbuffer.h

@ -1,9 +1,15 @@
#pragma once #pragma once
#include "base.h" #include "base.h"
ORCA_PURE static inline Glyph gbuffer_peek_relative(Glyph *gbuf, Usz height, ORCA_PURE static inline Glyph gbuffer_peek_relative(
Usz width, Usz y, Usz x, Glyph *gbuf,
Isz delta_y, Isz delta_x) { Usz height,
Usz width,
Usz y,
Usz x,
Isz delta_y,
Isz delta_x)
{
Isz y0 = (Isz)y + delta_y; Isz y0 = (Isz)y + delta_y;
Isz x0 = (Isz)x + delta_x; Isz x0 = (Isz)x + delta_x;
if (y0 < 0 || x0 < 0 || (Usz)y0 >= height || (Usz)x0 >= width) if (y0 < 0 || x0 < 0 || (Usz)y0 >= height || (Usz)x0 >= width)
@ -11,16 +17,23 @@ ORCA_PURE static inline Glyph gbuffer_peek_relative(Glyph *gbuf, Usz height,
return gbuf[(Usz)y0 * width + (Usz)x0]; return gbuf[(Usz)y0 * width + (Usz)x0];
} }
static inline void gbuffer_poke(Glyph *gbuf, Usz height, Usz width, Usz y, static inline void gbuffer_poke(Glyph *gbuf, Usz height, Usz width, Usz y, Usz x, Glyph g)
Usz x, Glyph g) { {
assert(y < height && x < width); assert(y < height && x < width);
(void)height; (void)height;
gbuf[y * width + x] = g; gbuf[y * width + x] = g;
} }
static inline void gbuffer_poke_relative(Glyph *gbuf, Usz height, Usz width, static inline void gbuffer_poke_relative(
Usz y, Usz x, Isz delta_y, Isz delta_x, Glyph *gbuf,
Glyph g) { Usz height,
Usz width,
Usz y,
Usz x,
Isz delta_y,
Isz delta_x,
Glyph g)
{
Isz y0 = (Isz)y + delta_y; Isz y0 = (Isz)y + delta_y;
Isz x0 = (Isz)x + delta_x; Isz x0 = (Isz)x + delta_x;
if (y0 < 0 || x0 < 0 || (Usz)y0 >= height || (Usz)x0 >= width) if (y0 < 0 || x0 < 0 || (Usz)y0 >= height || (Usz)x0 >= width)
@ -29,16 +42,33 @@ static inline void gbuffer_poke_relative(Glyph *gbuf, Usz height, Usz width,
} }
ORCA_NOINLINE ORCA_NOINLINE
void gbuffer_copy_subrect(Glyph *src, Glyph *dest, Usz src_grid_h, void gbuffer_copy_subrect(
Usz src_grid_w, Usz dest_grid_h, Usz dest_grid_w, Glyph *src,
Usz src_y, Usz src_x, Usz dest_y, Usz dest_x, Glyph *dest,
Usz height, Usz width); Usz src_grid_h,
Usz src_grid_w,
Usz dest_grid_h,
Usz dest_grid_w,
Usz src_y,
Usz src_x,
Usz dest_y,
Usz dest_x,
Usz height,
Usz width);
ORCA_NOINLINE ORCA_NOINLINE
void gbuffer_fill_subrect(Glyph *gbuf, Usz grid_h, Usz grid_w, Usz y, Usz x, void gbuffer_fill_subrect(
Usz height, Usz width, Glyph fill_char); Glyph *gbuf,
Usz grid_h,
Usz grid_w,
Usz y,
Usz x,
Usz height,
Usz width,
Glyph fill_char);
typedef enum { typedef enum
{
Mark_flag_none = 0, Mark_flag_none = 0,
Mark_flag_input = 1 << 0, Mark_flag_input = 1 << 0,
Mark_flag_output = 1 << 1, Mark_flag_output = 1 << 1,
@ -48,15 +78,15 @@ typedef enum {
} Mark_flags; } Mark_flags;
ORCA_OK_IF_UNUSED ORCA_OK_IF_UNUSED
static Mark_flags mbuffer_peek(Mark *mbuf, Usz height, Usz width, Usz y, static Mark_flags mbuffer_peek(Mark *mbuf, Usz height, Usz width, Usz y, Usz x)
Usz x) { {
(void)height; (void)height;
return mbuf[y * width + x]; return mbuf[y * width + x];
} }
ORCA_OK_IF_UNUSED ORCA_OK_IF_UNUSED
static Mark_flags mbuffer_peek_relative(Mark *mbuf, Usz height, Usz width, static Mark_flags mbuffer_peek_relative(Mark *mbuf, Usz height, Usz width, Usz y, Usz x, Isz offs_y, Isz offs_x)
Usz y, Usz x, Isz offs_y, Isz offs_x) { {
Isz y0 = (Isz)y + offs_y; Isz y0 = (Isz)y + offs_y;
Isz x0 = (Isz)x + offs_x; Isz x0 = (Isz)x + offs_x;
if (y0 >= (Isz)height || x0 >= (Isz)width || y0 < 0 || x0 < 0) if (y0 >= (Isz)height || x0 >= (Isz)width || y0 < 0 || x0 < 0)
@ -65,16 +95,23 @@ static Mark_flags mbuffer_peek_relative(Mark *mbuf, Usz height, Usz width,
} }
ORCA_OK_IF_UNUSED ORCA_OK_IF_UNUSED
static void mbuffer_poke_flags_or(Mark *mbuf, Usz height, Usz width, Usz y, static void mbuffer_poke_flags_or(Mark *mbuf, Usz height, Usz width, Usz y, Usz x, Mark_flags flags)
Usz x, Mark_flags flags) { {
(void)height; (void)height;
mbuf[y * width + x] |= (Mark)flags; mbuf[y * width + x] |= (Mark)flags;
} }
ORCA_OK_IF_UNUSED ORCA_OK_IF_UNUSED
static void mbuffer_poke_relative_flags_or(Mark *mbuf, Usz height, Usz width, static void mbuffer_poke_relative_flags_or(
Usz y, Usz x, Isz offs_y, Isz offs_x, Mark *mbuf,
Mark_flags flags) { Usz height,
Usz width,
Usz y,
Usz x,
Isz offs_y,
Isz offs_x,
Mark_flags flags)
{
Isz y0 = (Isz)y + offs_y; Isz y0 = (Isz)y + offs_y;
Isz x0 = (Isz)x + offs_x; Isz x0 = (Isz)x + offs_x;
if (y0 >= (Isz)height || x0 >= (Isz)width || y0 < 0 || x0 < 0) if (y0 >= (Isz)height || x0 >= (Isz)width || y0 < 0 || x0 < 0)

76
src/osc_out.c

@ -15,10 +15,9 @@ struct Oosc_dev {
struct addrinfo *head; struct addrinfo *head;
}; };
Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev **out_ptr, Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev **out_ptr, char const *dest_addr, char const *dest_port)
char const *dest_addr, {
char const *dest_port) { struct addrinfo hints = { 0 };
struct addrinfo hints = {0};
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM; hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0; hints.ai_protocol = 0;
@ -71,8 +70,7 @@ Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev **out_ptr,
} }
} }
#endif #endif
int udpfd = int udpfd = socket(chosen->ai_family, chosen->ai_socktype, chosen->ai_protocol);
socket(chosen->ai_family, chosen->ai_socktype, chosen->ai_protocol);
if (udpfd < 0) { if (udpfd < 0) {
#if 0 #if 0
fprintf(stderr, "Failed to open UDP socket, error number: %d\n", errno); fprintf(stderr, "Failed to open UDP socket, error number: %d\n", errno);
@ -88,15 +86,16 @@ Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev **out_ptr,
return Oosc_udp_create_error_ok; return Oosc_udp_create_error_ok;
} }
void oosc_dev_destroy(Oosc_dev *dev) { void oosc_dev_destroy(Oosc_dev *dev)
{
close(dev->fd); close(dev->fd);
freeaddrinfo(dev->head); freeaddrinfo(dev->head);
free(dev); free(dev);
} }
void oosc_send_datagram(Oosc_dev *dev, char const *data, Usz size) { void oosc_send_datagram(Oosc_dev *dev, char const *data, Usz size)
ssize_t res = sendto(dev->fd, data, size, 0, dev->chosen->ai_addr, {
dev->chosen->ai_addrlen); ssize_t res = sendto(dev->fd, data, size, 0, dev->chosen->ai_addr, dev->chosen->ai_addrlen);
(void)res; (void)res;
// TODO handle this in UI somehow // TODO handle this in UI somehow
#if 0 #if 0
@ -107,9 +106,13 @@ void oosc_send_datagram(Oosc_dev *dev, char const *data, Usz size) {
#endif #endif
} }
static bool oosc_write_strn(char *restrict buffer, Usz buffer_size, static bool oosc_write_strn(
Usz *buffer_pos, char const *restrict in_str, char *restrict buffer,
Usz in_str_len) { Usz buffer_size,
Usz *buffer_pos,
char const *restrict in_str,
Usz in_str_len)
{
// no overflow check, should be fine // no overflow check, should be fine
Usz in_plus_null = in_str_len + 1; Usz in_plus_null = in_str_len + 1;
Usz null_pad = (4 - in_plus_null % 4) % 4; Usz null_pad = (4 - in_plus_null % 4) % 4;
@ -129,12 +132,11 @@ static bool oosc_write_strn(char *restrict buffer, Usz buffer_size,
return true; return true;
} }
void oosc_send_int32s(Oosc_dev *dev, char const *osc_address, I32 const *vals, void oosc_send_int32s(Oosc_dev *dev, char const *osc_address, I32 const *vals, Usz count)
Usz count) { {
char buffer[2048]; char buffer[2048];
Usz buf_pos = 0; Usz buf_pos = 0;
if (!oosc_write_strn(buffer, sizeof(buffer), &buf_pos, osc_address, if (!oosc_write_strn(buffer, sizeof(buffer), &buf_pos, osc_address, strlen(osc_address)))
strlen(osc_address)))
return; return;
Usz typetag_str_size = 1 + count + 1; // comma, 'i'... , null Usz typetag_str_size = 1 + count + 1; // comma, 'i'... , null
Usz typetag_str_null_pad = (4 - typetag_str_size % 4) % 4; Usz typetag_str_null_pad = (4 - typetag_str_size % 4) % 4;
@ -167,19 +169,30 @@ void oosc_send_int32s(Oosc_dev *dev, char const *osc_address, I32 const *vals,
oosc_send_datagram(dev, buffer, buf_pos); oosc_send_datagram(dev, buffer, buf_pos);
} }
void susnote_list_init(Susnote_list *sl) { void susnote_list_init(Susnote_list *sl)
{
sl->buffer = NULL; sl->buffer = NULL;
sl->count = 0; sl->count = 0;
sl->capacity = 0; sl->capacity = 0;
} }
void susnote_list_deinit(Susnote_list *sl) { free(sl->buffer); } void susnote_list_deinit(Susnote_list *sl)
{
free(sl->buffer);
}
void susnote_list_clear(Susnote_list *sl) { sl->count = 0; } void susnote_list_clear(Susnote_list *sl)
{
sl->count = 0;
}
void susnote_list_add_notes(Susnote_list *sl, Susnote const *restrict notes, void susnote_list_add_notes(
Usz added_count, Usz *restrict start_removed, Susnote_list *sl,
Usz *restrict end_removed) { Susnote const *restrict notes,
Usz added_count,
Usz *restrict start_removed,
Usz *restrict end_removed)
{
Susnote *buffer = sl->buffer; Susnote *buffer = sl->buffer;
Usz count = sl->count; Usz count = sl->count;
Usz cap = sl->capacity; Usz cap = sl->capacity;
@ -212,10 +225,13 @@ void susnote_list_add_notes(Susnote_list *sl, Susnote const *restrict notes,
*end_removed = rem; *end_removed = rem;
} }
void susnote_list_advance_time(Susnote_list *sl, double delta_time, void susnote_list_advance_time(
Susnote_list *sl,
double delta_time,
Usz *restrict start_removed, Usz *restrict start_removed,
Usz *restrict end_removed, Usz *restrict end_removed,
double *soonest_deadline) { double *soonest_deadline)
{
Susnote *restrict buffer = sl->buffer; Susnote *restrict buffer = sl->buffer;
Usz count = sl->count; Usz count = sl->count;
*end_removed = count; *end_removed = count;
@ -240,9 +256,12 @@ void susnote_list_advance_time(Susnote_list *sl, double delta_time,
sl->count = count; sl->count = count;
} }
void susnote_list_remove_by_chan_mask(Susnote_list *sl, Usz chan_mask, void susnote_list_remove_by_chan_mask(
Susnote_list *sl,
Usz chan_mask,
Usz *restrict start_removed, Usz *restrict start_removed,
Usz *restrict end_removed) { Usz *restrict end_removed)
{
Susnote *restrict buffer = sl->buffer; Susnote *restrict buffer = sl->buffer;
Usz count = sl->count; Usz count = sl->count;
*end_removed = count; *end_removed = count;
@ -261,7 +280,8 @@ void susnote_list_remove_by_chan_mask(Susnote_list *sl, Usz chan_mask,
sl->count = count; sl->count = count;
} }
double susnote_list_soonest_deadline(Susnote_list const *sl) { double susnote_list_soonest_deadline(Susnote_list const *sl)
{
float soonest = 1.0f; float soonest = 1.0f;
Susnote const *buffer = sl->buffer; Susnote const *buffer = sl->buffer;
for (Usz i = 0, n = sl->count; i < n; ++i) { for (Usz i = 0, n = sl->count; i < n; ++i) {

25
src/osc_out.h

@ -3,15 +3,14 @@
typedef struct Oosc_dev Oosc_dev; typedef struct Oosc_dev Oosc_dev;
typedef enum { typedef enum
{
Oosc_udp_create_error_ok = 0, Oosc_udp_create_error_ok = 0,
Oosc_udp_create_error_getaddrinfo_failed = 1, Oosc_udp_create_error_getaddrinfo_failed = 1,
Oosc_udp_create_error_couldnt_open_socket = 2, Oosc_udp_create_error_couldnt_open_socket = 2,
} Oosc_udp_create_error; } Oosc_udp_create_error;
Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev **out_ptr, Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev **out_ptr, char const *dest_addr, char const *dest_port);
char const *dest_addr,
char const *dest_port);
void oosc_dev_destroy(Oosc_dev *dev); void oosc_dev_destroy(Oosc_dev *dev);
// Send a raw UDP datagram. // Send a raw UDP datagram.
@ -19,8 +18,7 @@ void oosc_send_datagram(Oosc_dev *dev, char const *data, Usz size);
// Send a list/array of 32-bit integers in OSC format to the specified "osc // Send a list/array of 32-bit integers in OSC format to the specified "osc
// address" (a path like /foo) as a UDP datagram. // address" (a path like /foo) as a UDP datagram.
void oosc_send_int32s(Oosc_dev *dev, char const *osc_address, I32 const *vals, void oosc_send_int32s(Oosc_dev *dev, char const *osc_address, I32 const *vals, Usz count);
Usz count);
// Susnote is for handling MIDI note sustains -- each MIDI on event should be // Susnote is for handling MIDI note sustains -- each MIDI on event should be
// matched with a MIDI note-off event. The duration/sustain length of a MIDI // matched with a MIDI note-off event. The duration/sustain length of a MIDI
@ -40,15 +38,22 @@ typedef struct {
void susnote_list_init(Susnote_list *sl); void susnote_list_init(Susnote_list *sl);
void susnote_list_deinit(Susnote_list *sl); void susnote_list_deinit(Susnote_list *sl);
void susnote_list_clear(Susnote_list *sl); void susnote_list_clear(Susnote_list *sl);
void susnote_list_add_notes(Susnote_list *sl, Susnote const *restrict notes, void susnote_list_add_notes(
Usz count, Usz *restrict start_removed, Susnote_list *sl,
Susnote const *restrict notes,
Usz count,
Usz *restrict start_removed,
Usz *restrict end_removed); Usz *restrict end_removed);
void susnote_list_advance_time( void susnote_list_advance_time(
Susnote_list *sl, double delta_time, Usz *restrict start_removed, Susnote_list *sl,
double delta_time,
Usz *restrict start_removed,
Usz *restrict end_removed, Usz *restrict end_removed,
// 1.0 if no notes remain or none are shorter than 1.0 // 1.0 if no notes remain or none are shorter than 1.0
double *soonest_deadline); double *soonest_deadline);
void susnote_list_remove_by_chan_mask(Susnote_list *sl, Usz chan_mask, void susnote_list_remove_by_chan_mask(
Susnote_list *sl,
Usz chan_mask,
Usz *restrict start_removed, Usz *restrict start_removed,
Usz *restrict end_removed); Usz *restrict end_removed);

94
src/oso.c

@ -5,16 +5,16 @@
#include <string.h> #include <string.h>
#if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute) #if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute)
#if __has_attribute(noinline) && __has_attribute(noclone) #if __has_attribute(noinline) && __has_attribute(noclone)
#define OSO_NOINLINE __attribute__((noinline, noclone)) #define OSO_NOINLINE __attribute__((noinline, noclone))
#elif __has_attribute(noinline) #elif __has_attribute(noinline)
#define OSO_NOINLINE __attribute__((noinline)) #define OSO_NOINLINE __attribute__((noinline))
#endif #endif
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define OSO_NOINLINE __declspec(noinline) #define OSO_NOINLINE __declspec(noinline)
#endif #endif
#ifndef OSO_NOINLINE #ifndef OSO_NOINLINE
#define OSO_NOINLINE #define OSO_NOINLINE
#endif #endif
#define OSO_INTERNAL OSO_NOINLINE static #define OSO_INTERNAL OSO_NOINLINE static
@ -25,7 +25,8 @@ typedef struct oso {
size_t len, cap; size_t len, cap;
} oso_header; } oso_header;
OSO_INTERNAL oso *oso_impl_reallochdr(oso_header *hdr, size_t new_cap) { OSO_INTERNAL oso *oso_impl_reallochdr(oso_header *hdr, size_t new_cap)
{
if (hdr) { if (hdr) {
oso_header *new_hdr = realloc(hdr, sizeof(oso_header) + new_cap + 1); oso_header *new_hdr = realloc(hdr, sizeof(oso_header) + new_cap + 1);
if (!new_hdr) { if (!new_hdr) {
@ -43,7 +44,8 @@ OSO_INTERNAL oso *oso_impl_reallochdr(oso_header *hdr, size_t new_cap) {
((char *)(hdr + 1))[0] = '\0'; ((char *)(hdr + 1))[0] = '\0';
return hdr + 1; return hdr + 1;
} }
OSO_INTERNAL oso *oso_impl_catvprintf(oso *s, char const *fmt, va_list ap) { OSO_INTERNAL oso *oso_impl_catvprintf(oso *s, char const *fmt, va_list ap)
{
size_t old_len; size_t old_len;
int required; int required;
va_list cpy; va_list cpy;
@ -60,7 +62,8 @@ OSO_INTERNAL oso *oso_impl_catvprintf(oso *s, char const *fmt, va_list ap) {
} }
OSO_NOINLINE OSO_NOINLINE
void osoensurecap(oso **p, size_t new_cap) { void osoensurecap(oso **p, size_t new_cap)
{
oso *s = *p; oso *s = *p;
if (new_cap > OSO_CAP_MAX) { if (new_cap > OSO_CAP_MAX) {
if (s) { if (s) {
@ -79,7 +82,8 @@ void osoensurecap(oso **p, size_t new_cap) {
} }
OSO_NOINLINE OSO_NOINLINE
void osomakeroomfor(oso **p, size_t add_len) { void osomakeroomfor(oso **p, size_t add_len)
{
oso *s = *p; oso *s = *p;
oso_header *hdr = NULL; oso_header *hdr = NULL;
size_t new_cap; size_t new_cap;
@ -102,12 +106,14 @@ void osomakeroomfor(oso **p, size_t add_len) {
*p = oso_impl_reallochdr(hdr, new_cap); *p = oso_impl_reallochdr(hdr, new_cap);
} }
void osoput(oso **p, char const *restrict cstr) { void osoput(oso **p, char const *restrict cstr)
{
osoputlen(p, cstr, strlen(cstr)); osoputlen(p, cstr, strlen(cstr));
} }
OSO_NOINLINE OSO_NOINLINE
void osoputlen(oso **p, char const *restrict cstr, size_t len) { void osoputlen(oso **p, char const *restrict cstr, size_t len)
{
oso *s = *p; oso *s = *p;
osoensurecap(&s, len); osoensurecap(&s, len);
if (s) { if (s) {
@ -117,12 +123,14 @@ void osoputlen(oso **p, char const *restrict cstr, size_t len) {
} }
*p = s; *p = s;
} }
void osoputoso(oso **p, oso const *other) { void osoputoso(oso **p, oso const *other)
{
if (!other) if (!other)
return; return;
osoputlen(p, (char const *)other, OSO_HDR(other)->len); osoputlen(p, (char const *)other, OSO_HDR(other)->len);
} }
void osoputvprintf(oso **p, char const *fmt, va_list ap) { void osoputvprintf(oso **p, char const *fmt, va_list ap)
{
oso *s = *p; oso *s = *p;
if (s) { if (s) {
OSO_HDR(s)->len = 0; OSO_HDR(s)->len = 0;
@ -130,7 +138,8 @@ void osoputvprintf(oso **p, char const *fmt, va_list ap) {
} }
*p = oso_impl_catvprintf(s, fmt, ap); *p = oso_impl_catvprintf(s, fmt, ap);
} }
void osoputprintf(oso **p, char const *fmt, ...) { void osoputprintf(oso **p, char const *fmt, ...)
{
oso *s = *p; oso *s = *p;
if (s) { if (s) {
OSO_HDR(s)->len = 0; OSO_HDR(s)->len = 0;
@ -141,9 +150,13 @@ void osoputprintf(oso **p, char const *fmt, ...) {
*p = oso_impl_catvprintf(s, fmt, ap); *p = oso_impl_catvprintf(s, fmt, ap);
va_end(ap); va_end(ap);
} }
void osocat(oso **p, char const *cstr) { osocatlen(p, cstr, strlen(cstr)); } void osocat(oso **p, char const *cstr)
{
osocatlen(p, cstr, strlen(cstr));
}
OSO_NOINLINE OSO_NOINLINE
void osocatlen(oso **p, char const *cstr, size_t len) { void osocatlen(oso **p, char const *cstr, size_t len)
{
oso *s = *p; oso *s = *p;
osomakeroomfor(&s, len); osomakeroomfor(&s, len);
if (s) { if (s) {
@ -155,44 +168,61 @@ void osocatlen(oso **p, char const *cstr, size_t len) {
} }
*p = s; *p = s;
} }
void osocatoso(oso **p, oso const *other) { void osocatoso(oso **p, oso const *other)
{
if (!other) if (!other)
return; return;
osocatlen(p, (char const *)other, OSO_HDR(other)->len); osocatlen(p, (char const *)other, OSO_HDR(other)->len);
} }
void osocatvprintf(oso **p, char const *fmt, va_list ap) { void osocatvprintf(oso **p, char const *fmt, va_list ap)
{
*p = oso_impl_catvprintf(*p, fmt, ap); *p = oso_impl_catvprintf(*p, fmt, ap);
} }
void osocatprintf(oso **p, char const *fmt, ...) { void osocatprintf(oso **p, char const *fmt, ...)
{
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
*p = oso_impl_catvprintf(*p, fmt, ap); *p = oso_impl_catvprintf(*p, fmt, ap);
va_end(ap); va_end(ap);
} }
void osoclear(oso **p) { void osoclear(oso **p)
{
oso *s = *p; oso *s = *p;
if (!s) if (!s)
return; return;
OSO_HDR(s)->len = 0; OSO_HDR(s)->len = 0;
((char *)s)[0] = '\0'; ((char *)s)[0] = '\0';
} }
void osofree(oso *s) { void osofree(oso *s)
{
if (s) if (s)
free(OSO_HDR(s)); free(OSO_HDR(s));
} }
void osowipe(oso **p) { void osowipe(oso **p)
{
osofree(*p); osofree(*p);
*p = NULL; *p = NULL;
} }
void ososwap(oso **a, oso **b) { void ososwap(oso **a, oso **b)
{
oso *tmp = *a; oso *tmp = *a;
*a = *b; *a = *b;
*b = tmp; *b = tmp;
} }
void osopokelen(oso *s, size_t len) { OSO_HDR(s)->len = len; } void osopokelen(oso *s, size_t len)
size_t osolen(oso const *s) { return s ? OSO_HDR(s)->len : 0; } {
size_t osocap(oso const *s) { return s ? OSO_HDR(s)->cap : 0; } OSO_HDR(s)->len = len;
void osolencap(oso const *s, size_t *out_len, size_t *out_cap) { }
size_t osolen(oso const *s)
{
return s ? OSO_HDR(s)->len : 0;
}
size_t osocap(oso const *s)
{
return s ? OSO_HDR(s)->cap : 0;
}
void osolencap(oso const *s, size_t *out_len, size_t *out_cap)
{
if (!s) { if (!s) {
*out_len = 0; *out_len = 0;
*out_cap = 0; *out_cap = 0;
@ -202,14 +232,16 @@ void osolencap(oso const *s, size_t *out_len, size_t *out_cap) {
*out_len = hdr->len; *out_len = hdr->len;
*out_cap = hdr->cap; *out_cap = hdr->cap;
} }
size_t osoavail(oso const *s) { size_t osoavail(oso const *s)
{
if (!s) if (!s)
return 0; return 0;
oso_header *h = OSO_HDR(s); oso_header *h = OSO_HDR(s);
return h->cap - h->len; return h->cap - h->len;
} }
void osotrim(oso *restrict s, char const *restrict cut_set) { void osotrim(oso *restrict s, char const *restrict cut_set)
{
if (!s) if (!s)
return; return;
char *str, *end, *start_pos, *end_pos; char *str, *end, *start_pos, *end_pos;

31
src/oso.h

@ -92,18 +92,18 @@
#include <stddef.h> #include <stddef.h>
#if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute) #if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute)
#if __has_attribute(format) #if __has_attribute(format)
#define OSO_PRINTF(...) __attribute__((format(printf, __VA_ARGS__))) #define OSO_PRINTF(...) __attribute__((format(printf, __VA_ARGS__)))
#endif #endif
#if __has_attribute(nonnull) #if __has_attribute(nonnull)
#define OSO_NONNULL(...) __attribute__((nonnull(__VA_ARGS__))) #define OSO_NONNULL(...) __attribute__((nonnull(__VA_ARGS__)))
#endif #endif
#endif #endif
#ifndef OSO_PRINTF #ifndef OSO_PRINTF
#define OSO_PRINTF(...) #define OSO_PRINTF(...)
#endif #endif
#ifndef OSO_NONNULL #ifndef OSO_NONNULL
#define OSO_NONNULL(...) #define OSO_NONNULL(...)
#endif #endif
typedef struct oso oso; typedef struct oso oso;
@ -122,19 +122,15 @@ void osoputlen(oso **p, char const *cstr, size_t len) OSO_NONNULL();
void osoputoso(oso **p, oso const *other) OSO_NONNULL(1); void osoputoso(oso **p, oso const *other) OSO_NONNULL(1);
// ^- Same as above, but using another `oso`. `*p` and `other` must not point // ^- Same as above, but using another `oso`. `*p` and `other` must not point
// to overlapping memory. // to overlapping memory.
void osoputvprintf(oso **p, char const *fmt, va_list ap) OSO_NONNULL(1, 2) void osoputvprintf(oso **p, char const *fmt, va_list ap) OSO_NONNULL(1, 2) OSO_PRINTF(2, 0);
OSO_PRINTF(2, 0); void osoputprintf(oso **p, char const *fmt, ...) OSO_NONNULL(1, 2) OSO_PRINTF(2, 3);
void osoputprintf(oso **p, char const *fmt, ...) OSO_NONNULL(1, 2)
OSO_PRINTF(2, 3);
// ^- Same as above, but do it by using printf. // ^- Same as above, but do it by using printf.
void osocat(oso **p, char const *cstr) OSO_NONNULL(); void osocat(oso **p, char const *cstr) OSO_NONNULL();
void osocatlen(oso **p, char const *cstr, size_t len) OSO_NONNULL(); void osocatlen(oso **p, char const *cstr, size_t len) OSO_NONNULL();
void osocatoso(oso **p, oso const *other) OSO_NONNULL(1); void osocatoso(oso **p, oso const *other) OSO_NONNULL(1);
void osocatvprintf(oso **p, char const *fmt, va_list ap) OSO_NONNULL(1, 2) void osocatvprintf(oso **p, char const *fmt, va_list ap) OSO_NONNULL(1, 2) OSO_PRINTF(2, 0);
OSO_PRINTF(2, 0); void osocatprintf(oso **p, char const *fmt, ...) OSO_NONNULL(1, 2) OSO_PRINTF(2, 3);
void osocatprintf(oso **p, char const *fmt, ...) OSO_NONNULL(1, 2)
OSO_PRINTF(2, 3);
// ^- Append string to oso string. Same rules as `osoput` family. // ^- Append string to oso string. Same rules as `osoput` family.
void osoensurecap(oso **p, size_t cap) OSO_NONNULL(); void osoensurecap(oso **p, size_t cap) OSO_NONNULL();
@ -169,8 +165,7 @@ size_t osolen(oso const *s);
// ^- Bytes in use by the string (not including the '\0' character.) // ^- Bytes in use by the string (not including the '\0' character.)
size_t osocap(oso const *s); size_t osocap(oso const *s);
// ^- Bytes allocated on heap (not including the '\0' terminator.) // ^- Bytes allocated on heap (not including the '\0' terminator.)
void osolencap(oso const *s, size_t *out_len, size_t *out_cap) void osolencap(oso const *s, size_t *out_len, size_t *out_cap) OSO_NONNULL(2, 3);
OSO_NONNULL(2, 3);
// ^- Get both the len and the cap in one call. // ^- Get both the len and the cap in one call.
size_t osoavail(oso const *s); size_t osoavail(oso const *s);
// ^- osocap(s) - osolen(s) // ^- osocap(s) - osolen(s)

147
src/sim.c

@ -8,8 +8,12 @@ static Glyph const glyph_table[36] = {
'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 12-23 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 12-23
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', // 24-35 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', // 24-35
}; };
enum { Glyphs_index_count = sizeof glyph_table }; enum
static inline Glyph glyph_of(Usz index) { {
Glyphs_index_count = sizeof glyph_table
};
static inline Glyph glyph_of(Usz index)
{
assert(index < Glyphs_index_count); assert(index < Glyphs_index_count);
return glyph_table[index]; return glyph_table[index];
} }
@ -22,8 +26,12 @@ static U8 const index_table[128] = {
0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 64-79 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 64-79
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 0, 0, 0, 0, // 80-95 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 0, 0, 0, 0, // 80-95
0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 96-111 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 96-111
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 0, 0, 0, 0}; // 112-127 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 0, 0, 0, 0
static ORCA_FORCEINLINE Usz index_of(Glyph c) { return index_table[c & 0x7f]; } }; // 112-127
static ORCA_FORCEINLINE Usz index_of(Glyph c)
{
return index_table[c & 0x7f];
}
// Reference implementation: // Reference implementation:
// static Usz index_of(Glyph c) { // static Usz index_of(Glyph c) {
@ -33,18 +41,26 @@ static ORCA_FORCEINLINE Usz index_of(Glyph c) { return index_table[c & 0x7f]; }
// return 0; // return 0;
// } // }
static ORCA_FORCEINLINE bool glyph_is_lowercase(Glyph g) { return g & 1 << 5; } static ORCA_FORCEINLINE bool glyph_is_lowercase(Glyph g)
static ORCA_FORCEINLINE Glyph glyph_lowered_unsafe(Glyph g) { {
return g & 1 << 5;
}
static ORCA_FORCEINLINE Glyph glyph_lowered_unsafe(Glyph g)
{
return (Glyph)(g | 1 << 5); return (Glyph)(g | 1 << 5);
} }
static inline Glyph glyph_with_case(Glyph g, Glyph caser) { static inline Glyph glyph_with_case(Glyph g, Glyph caser)
enum { Case_bit = 1 << 5, Alpha_bit = 1 << 6 }; {
return (Glyph)((g & ~Case_bit) | ((~g & Alpha_bit) >> 1) | enum
(caser & Case_bit)); {
Case_bit = 1 << 5,
Alpha_bit = 1 << 6
};
return (Glyph)((g & ~Case_bit) | ((~g & Alpha_bit) >> 1) | (caser & Case_bit));
} }
static ORCA_PURE bool oper_has_neighboring_bang(Glyph const *gbuf, Usz h, Usz w, static ORCA_PURE bool oper_has_neighboring_bang(Glyph const *gbuf, Usz h, Usz w, Usz y, Usz x)
Usz y, Usz x) { {
Glyph const *gp = gbuf + w * y + x; Glyph const *gp = gbuf + w * y + x;
if (x < w - 1 && gp[1] == '*') if (x < w - 1 && gp[1] == '*')
return true; return true;
@ -60,14 +76,15 @@ static ORCA_PURE bool oper_has_neighboring_bang(Glyph const *gbuf, Usz h, Usz w,
} }
// Returns UINT8_MAX if not a valid note. // Returns UINT8_MAX if not a valid note.
static U8 midi_note_number_of(Glyph g) { static U8 midi_note_number_of(Glyph g)
{
int sharp = (g & 1 << 5) >> 5; // sharp=1 if lowercase int sharp = (g & 1 << 5) >> 5; // sharp=1 if lowercase
g &= (Glyph) ~(1 << 5); // make uppercase g &= (Glyph) ~(1 << 5); // make uppercase
if (g < 'A' || g > 'Z') // A through Z only if (g < 'A' || g > 'Z') // A through Z only
return UINT8_MAX; return UINT8_MAX;
// We want C=0, D=1, E=2, etc. A and B are equivalent to H and I. // We want C=0, D=1, E=2, etc. A and B are equivalent to H and I.
int deg = g <= 'B' ? 'G' - 'B' + g - 'A' : g - 'C'; int deg = g <= 'B' ? 'G' - 'B' + g - 'A' : g - 'C';
return (U8)(deg / 7 * 12 + (I8[]){0, 2, 4, 5, 7, 9, 11}[deg % 7] + sharp); return (U8)(deg / 7 * 12 + (I8[]){ 0, 2, 4, 5, 7, 9, 11 }[deg % 7] + sharp);
} }
typedef struct { typedef struct {
@ -76,9 +93,17 @@ typedef struct {
Usz random_seed; Usz random_seed;
} Oper_extra_params; } Oper_extra_params;
static void oper_poke_and_stun(Glyph *restrict gbuffer, Mark *restrict mbuffer, static void oper_poke_and_stun(
Usz height, Usz width, Usz y, Usz x, Isz delta_y, Glyph *restrict gbuffer,
Isz delta_x, Glyph g) { Mark *restrict mbuffer,
Usz height,
Usz width,
Usz y,
Usz x,
Isz delta_y,
Isz delta_x,
Glyph g)
{
Isz y0 = (Isz)y + delta_y; Isz y0 = (Isz)y + delta_y;
Isz x0 = (Isz)x + delta_x; Isz x0 = (Isz)x + delta_x;
if (y0 < 0 || x0 < 0 || (Usz)y0 >= height || (Usz)x0 >= width) if (y0 < 0 || x0 < 0 || (Usz)y0 >= height || (Usz)x0 >= width)
@ -96,10 +121,17 @@ static void oper_poke_and_stun(Glyph *restrict gbuffer, Mark *restrict mbuffer,
#define BEGIN_OPERATOR(_oper_name) \ #define BEGIN_OPERATOR(_oper_name) \
OPER_FUNCTION_ATTRIBS oper_behavior_##_oper_name( \ OPER_FUNCTION_ATTRIBS oper_behavior_##_oper_name( \
Glyph *const restrict gbuffer, Mark *const restrict mbuffer, \ Glyph *const restrict gbuffer, \
Usz const height, Usz const width, Usz const y, Usz const x, \ Mark *const restrict mbuffer, \
Usz Tick_number, Oper_extra_params *const extra_params, \ Usz const height, \
Mark const cell_flags, Glyph const This_oper_char) { \ Usz const width, \
Usz const y, \
Usz const x, \
Usz Tick_number, \
Oper_extra_params *const extra_params, \
Mark const cell_flags, \
Glyph const This_oper_char) \
{ \
(void)gbuffer; \ (void)gbuffer; \
(void)mbuffer; \ (void)mbuffer; \
(void)height; \ (void)height; \
@ -116,17 +148,13 @@ static void oper_poke_and_stun(Glyph *restrict gbuffer, Mark *restrict mbuffer,
#define PEEK(_delta_y, _delta_x) \ #define PEEK(_delta_y, _delta_x) \
gbuffer_peek_relative(gbuffer, height, width, y, x, _delta_y, _delta_x) gbuffer_peek_relative(gbuffer, height, width, y, x, _delta_y, _delta_x)
#define POKE(_delta_y, _delta_x, _glyph) \ #define POKE(_delta_y, _delta_x, _glyph) \
gbuffer_poke_relative(gbuffer, height, width, y, x, _delta_y, _delta_x, \ gbuffer_poke_relative(gbuffer, height, width, y, x, _delta_y, _delta_x, _glyph)
_glyph)
#define STUN(_delta_y, _delta_x) \ #define STUN(_delta_y, _delta_x) \
mbuffer_poke_relative_flags_or(mbuffer, height, width, y, x, _delta_y, \ mbuffer_poke_relative_flags_or(mbuffer, height, width, y, x, _delta_y, _delta_x, Mark_flag_sleep)
_delta_x, Mark_flag_sleep)
#define POKE_STUNNED(_delta_y, _delta_x, _glyph) \ #define POKE_STUNNED(_delta_y, _delta_x, _glyph) \
oper_poke_and_stun(gbuffer, mbuffer, height, width, y, x, _delta_y, \ oper_poke_and_stun(gbuffer, mbuffer, height, width, y, x, _delta_y, _delta_x, _glyph)
_delta_x, _glyph)
#define LOCK(_delta_y, _delta_x) \ #define LOCK(_delta_y, _delta_x) \
mbuffer_poke_relative_flags_or(mbuffer, height, width, y, x, _delta_y, \ mbuffer_poke_relative_flags_or(mbuffer, height, width, y, x, _delta_y, _delta_x, Mark_flag_lock)
_delta_x, Mark_flag_lock)
#define IN Mark_flag_input #define IN Mark_flag_input
#define OUT Mark_flag_output #define OUT Mark_flag_output
@ -143,8 +171,7 @@ static void oper_poke_and_stun(Glyph *restrict gbuffer, Mark *restrict mbuffer,
return return
#define PORT(_delta_y, _delta_x, _flags) \ #define PORT(_delta_y, _delta_x, _flags) \
mbuffer_poke_relative_flags_or(mbuffer, height, width, y, x, _delta_y, \ mbuffer_poke_relative_flags_or(mbuffer, height, width, y, x, _delta_y, _delta_x, (_flags) ^ Mark_flag_lock)
_delta_x, (_flags) ^ Mark_flag_lock)
//////// Operators //////// Operators
#define UNIQUE_OPERATORS(_) \ #define UNIQUE_OPERATORS(_) \
@ -186,8 +213,7 @@ static void oper_poke_and_stun(Glyph *restrict gbuffer, Mark *restrict mbuffer,
_('Z', lerp) _('Z', lerp)
BEGIN_OPERATOR(movement) BEGIN_OPERATOR(movement)
if (glyph_is_lowercase(This_oper_char) && if (glyph_is_lowercase(This_oper_char) && !oper_has_neighboring_bang(gbuffer, height, width, y, x))
!oper_has_neighboring_bang(gbuffer, height, width, y, x))
return; return;
Isz delta_y, delta_x; Isz delta_y, delta_x;
switch (glyph_lowered_unsafe(This_oper_char)) { switch (glyph_lowered_unsafe(This_oper_char)) {
@ -243,8 +269,7 @@ BEGIN_OPERATOR(midicc)
if (channel > 15) if (channel > 15)
return; return;
PORT(0, 0, OUT); PORT(0, 0, OUT);
Oevent_midi_cc *oe = Oevent_midi_cc *oe = (Oevent_midi_cc *)oevent_list_alloc_item(extra_params->oevent_list);
(Oevent_midi_cc *)oevent_list_alloc_item(extra_params->oevent_list);
oe->oevent_type = Oevent_type_midi_cc; oe->oevent_type = Oevent_type_midi_cc;
oe->channel = (U8)channel; oe->channel = (U8)channel;
oe->control = (U8)index_of(control_g); oe->control = (U8)index_of(control_g);
@ -307,8 +332,7 @@ BEGIN_OPERATOR(midi)
vel_num = 127; vel_num = 127;
} }
PORT(0, 0, OUT); PORT(0, 0, OUT);
Oevent_midi_note *oe = Oevent_midi_note *oe = (Oevent_midi_note *)oevent_list_alloc_item(extra_params->oevent_list);
(Oevent_midi_note *)oevent_list_alloc_item(extra_params->oevent_list);
oe->oevent_type = (U8)Oevent_type_midi_note; oe->oevent_type = (U8)Oevent_type_midi_note;
oe->channel = (U8)channel_num; oe->channel = (U8)channel_num;
oe->octave = octave_num; oe->octave = octave_num;
@ -338,8 +362,7 @@ BEGIN_OPERATOR(udp)
n = i; n = i;
STOP_IF_NOT_BANGED; STOP_IF_NOT_BANGED;
PORT(0, 0, OUT); PORT(0, 0, OUT);
Oevent_udp_string *oe = Oevent_udp_string *oe = (Oevent_udp_string *)oevent_list_alloc_item(extra_params->oevent_list);
(Oevent_udp_string *)oevent_list_alloc_item(extra_params->oevent_list);
oe->oevent_type = (U8)Oevent_type_udp_string; oe->oevent_type = (U8)Oevent_type_udp_string;
oe->count = (U8)n; oe->count = (U8)n;
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
@ -364,8 +387,7 @@ BEGIN_OPERATOR(osc)
for (Usz i = 0; i < len; ++i) { for (Usz i = 0; i < len; ++i) {
buff[i] = (U8)index_of(PEEK(0, (Isz)i + 3)); buff[i] = (U8)index_of(PEEK(0, (Isz)i + 3));
} }
Oevent_osc_ints *oe = Oevent_osc_ints *oe = &oevent_list_alloc_item(extra_params->oevent_list)->osc_ints;
&oevent_list_alloc_item(extra_params->oevent_list)->osc_ints;
oe->oevent_type = (U8)Oevent_type_osc_ints; oe->oevent_type = (U8)Oevent_type_osc_ints;
oe->glyph = g; oe->glyph = g;
oe->count = (U8)len; oe->count = (U8)len;
@ -389,8 +411,7 @@ BEGIN_OPERATOR(midipb)
if (channel > 15) if (channel > 15)
return; return;
PORT(0, 0, OUT); PORT(0, 0, OUT);
Oevent_midi_pb *oe = Oevent_midi_pb *oe = (Oevent_midi_pb *)oevent_list_alloc_item(extra_params->oevent_list);
(Oevent_midi_pb *)oevent_list_alloc_item(extra_params->oevent_list);
oe->oevent_type = Oevent_type_midi_pb; oe->oevent_type = Oevent_type_midi_pb;
oe->channel = (U8)channel; oe->channel = (U8)channel;
oe->msb = (U8)(index_of(msb_g) * 127 / 35); // 0~35 -> 0~127 oe->msb = (U8)(index_of(msb_g) * 127 / 35); // 0~35 -> 0~127
@ -634,8 +655,7 @@ BEGIN_OPERATOR(random)
max = a; max = a;
} }
// Initial input params for the hash // Initial input params for the hash
Usz key = (extra_params->random_seed + y * width + x) ^ Usz key = (extra_params->random_seed + y * width + x) ^ (Tick_number << UINT32_C(16));
(Tick_number << UINT32_C(16));
// 32-bit shift_mult hash to evenly distribute bits // 32-bit shift_mult hash to evenly distribute bits
key = (key ^ UINT32_C(61)) ^ (key >> UINT32_C(16)); key = (key ^ UINT32_C(61)) ^ (key >> UINT32_C(16));
key = key + (key << UINT32_C(3)); key = key + (key << UINT32_C(3));
@ -745,8 +765,15 @@ END_OPERATOR
//////// Run simulation //////// Run simulation
void orca_run(Glyph *restrict gbuf, Mark *restrict mbuf, Usz height, Usz width, void orca_run(
Usz tick_number, Oevent_list *oevent_list, Usz random_seed) { Glyph *restrict gbuf,
Mark *restrict mbuf,
Usz height,
Usz width,
Usz tick_number,
Oevent_list *oevent_list,
Usz random_seed)
{
Glyph vars_slots[Glyphs_index_count]; Glyph vars_slots[Glyphs_index_count];
memset(vars_slots, '.', sizeof(vars_slots)); memset(vars_slots, '.', sizeof(vars_slots));
Oper_extra_params extras; Oper_extra_params extras;
@ -767,15 +794,33 @@ void orca_run(Glyph *restrict gbuf, Mark *restrict mbuf, Usz height, Usz width,
switch (glyph_char) { switch (glyph_char) {
#define UNIQUE_CASE(_oper_char, _oper_name) \ #define UNIQUE_CASE(_oper_char, _oper_name) \
case _oper_char: \ case _oper_char: \
oper_behavior_##_oper_name(gbuf, mbuf, height, width, iy, ix, tick_number, \ oper_behavior_##_oper_name( \
&extras, cell_flags, glyph_char); \ gbuf, \
mbuf, \
height, \
width, \
iy, \
ix, \
tick_number, \
&extras, \
cell_flags, \
glyph_char); \
break; break;
#define ALPHA_CASE(_upper_oper_char, _oper_name) \ #define ALPHA_CASE(_upper_oper_char, _oper_name) \
case _upper_oper_char: \ case _upper_oper_char: \
case (char)(_upper_oper_char | 1 << 5): \ case (char)(_upper_oper_char | 1 << 5): \
oper_behavior_##_oper_name(gbuf, mbuf, height, width, iy, ix, tick_number, \ oper_behavior_##_oper_name( \
&extras, cell_flags, glyph_char); \ gbuf, \
mbuf, \
height, \
width, \
iy, \
ix, \
tick_number, \
&extras, \
cell_flags, \
glyph_char); \
break; break;
UNIQUE_OPERATORS(UNIQUE_CASE) UNIQUE_OPERATORS(UNIQUE_CASE)
ALPHA_OPERATORS(ALPHA_CASE) ALPHA_OPERATORS(ALPHA_CASE)

9
src/sim.h

@ -2,6 +2,11 @@
#include "base.h" #include "base.h"
#include "vmio.h" #include "vmio.h"
void orca_run(Glyph *restrict gbuffer, Mark *restrict mbuffer, Usz height, void orca_run(
Usz width, Usz tick_number, Oevent_list *oevent_list, Glyph *restrict gbuffer,
Mark *restrict mbuffer,
Usz height,
Usz width,
Usz tick_number,
Oevent_list *oevent_list,
Usz random_seed); Usz random_seed);

95
src/sokol_time.h

@ -89,15 +89,15 @@
extern "C" { extern "C" {
#endif #endif
SOKOL_API_DECL void stm_setup(void); SOKOL_API_DECL void stm_setup(void);
SOKOL_API_DECL uint64_t stm_now(void); SOKOL_API_DECL uint64_t stm_now(void);
SOKOL_API_DECL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks); SOKOL_API_DECL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks);
SOKOL_API_DECL uint64_t stm_since(uint64_t start_ticks); SOKOL_API_DECL uint64_t stm_since(uint64_t start_ticks);
SOKOL_API_DECL uint64_t stm_laptime(uint64_t* last_time); SOKOL_API_DECL uint64_t stm_laptime(uint64_t *last_time);
SOKOL_API_DECL double stm_sec(uint64_t ticks); SOKOL_API_DECL double stm_sec(uint64_t ticks);
SOKOL_API_DECL double stm_ms(uint64_t ticks); SOKOL_API_DECL double stm_ms(uint64_t ticks);
SOKOL_API_DECL double stm_us(uint64_t ticks); SOKOL_API_DECL double stm_us(uint64_t ticks);
SOKOL_API_DECL double stm_ns(uint64_t ticks); SOKOL_API_DECL double stm_ns(uint64_t ticks);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
@ -106,51 +106,52 @@ SOKOL_API_DECL double stm_ns(uint64_t ticks);
/*-- IMPLEMENTATION ----------------------------------------------------------*/ /*-- IMPLEMENTATION ----------------------------------------------------------*/
#ifdef SOKOL_IMPL #ifdef SOKOL_IMPL
#ifndef SOKOL_API_IMPL #ifndef SOKOL_API_IMPL
#define SOKOL_API_IMPL #define SOKOL_API_IMPL
#endif #endif
#ifndef SOKOL_ASSERT #ifndef SOKOL_ASSERT
#include <assert.h> #include <assert.h>
#define SOKOL_ASSERT(c) assert(c) #define SOKOL_ASSERT(c) assert(c)
#endif #endif
#ifndef _SOKOL_PRIVATE #ifndef _SOKOL_PRIVATE
#if defined(__GNUC__) #if defined(__GNUC__)
#define _SOKOL_PRIVATE __attribute__((unused)) static #define _SOKOL_PRIVATE __attribute__((unused)) static
#else #else
#define _SOKOL_PRIVATE static #define _SOKOL_PRIVATE static
#endif #endif
#endif #endif
static int _stm_initialized; static int _stm_initialized;
#if defined(_WIN32) #if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
#include <windows.h> #include <windows.h>
static LARGE_INTEGER _stm_win_freq; static LARGE_INTEGER _stm_win_freq;
static LARGE_INTEGER _stm_win_start; static LARGE_INTEGER _stm_win_start;
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)
#include <mach/mach_time.h> #include <mach/mach_time.h>
static mach_timebase_info_data_t _stm_osx_timebase; static mach_timebase_info_data_t _stm_osx_timebase;
static uint64_t _stm_osx_start; static uint64_t _stm_osx_start;
#else /* anything else, this will need more care for non-Linux platforms */ #else /* anything else, this will need more care for non-Linux platforms */
#include <time.h> #include <time.h>
static uint64_t _stm_posix_start; static uint64_t _stm_posix_start;
#endif #endif
/* prevent 64-bit overflow when computing relative timestamp /* prevent 64-bit overflow when computing relative timestamp
see https://gist.github.com/jspohr/3dc4f00033d79ec5bdaf67bc46c813e3 see https://gist.github.com/jspohr/3dc4f00033d79ec5bdaf67bc46c813e3
*/ */
#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) #if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__))
_SOKOL_PRIVATE int64_t int64_muldiv(int64_t value, int64_t numer, int64_t denom) { _SOKOL_PRIVATE int64_t int64_muldiv(int64_t value, int64_t numer, int64_t denom)
{
int64_t q = value / denom; int64_t q = value / denom;
int64_t r = value % denom; int64_t r = value % denom;
return q * numer + r * numer / denom; return q * numer + r * numer / denom;
} }
#endif #endif
SOKOL_API_IMPL void stm_setup(void) { SOKOL_API_IMPL void stm_setup(void)
{
SOKOL_ASSERT(0 == _stm_initialized); SOKOL_ASSERT(0 == _stm_initialized);
_stm_initialized = 1; _stm_initialized = 1;
#if defined(_WIN32) #if defined(_WIN32)
@ -162,11 +163,12 @@ SOKOL_API_IMPL void stm_setup(void) {
#else #else
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
_stm_posix_start = (uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec; _stm_posix_start = (uint64_t)ts.tv_sec * 1000000000 + (uint64_t)ts.tv_nsec;
#endif #endif
} }
SOKOL_API_IMPL uint64_t stm_now(void) { SOKOL_API_IMPL uint64_t stm_now(void)
{
SOKOL_ASSERT(_stm_initialized); SOKOL_ASSERT(_stm_initialized);
uint64_t now; uint64_t now;
#if defined(_WIN32) #if defined(_WIN32)
@ -179,26 +181,28 @@ SOKOL_API_IMPL uint64_t stm_now(void) {
#else #else
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
now = ((uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec) - _stm_posix_start; now = ((uint64_t)ts.tv_sec * 1000000000 + (uint64_t)ts.tv_nsec) - _stm_posix_start;
#endif #endif
return now; return now;
} }
SOKOL_API_IMPL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks) { SOKOL_API_IMPL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks)
{
if (new_ticks > old_ticks) { if (new_ticks > old_ticks) {
return new_ticks - old_ticks; return new_ticks - old_ticks;
} } else {
else {
/* FIXME: this should be a value that converts to a non-null double */ /* FIXME: this should be a value that converts to a non-null double */
return 1; return 1;
} }
} }
SOKOL_API_IMPL uint64_t stm_since(uint64_t start_ticks) { SOKOL_API_IMPL uint64_t stm_since(uint64_t start_ticks)
{
return stm_diff(stm_now(), start_ticks); return stm_diff(stm_now(), start_ticks);
} }
SOKOL_API_IMPL uint64_t stm_laptime(uint64_t* last_time) { SOKOL_API_IMPL uint64_t stm_laptime(uint64_t *last_time)
{
SOKOL_ASSERT(last_time); SOKOL_ASSERT(last_time);
uint64_t dt = 0; uint64_t dt = 0;
uint64_t now = stm_now(); uint64_t now = stm_now();
@ -209,20 +213,23 @@ SOKOL_API_IMPL uint64_t stm_laptime(uint64_t* last_time) {
return dt; return dt;
} }
SOKOL_API_IMPL double stm_sec(uint64_t ticks) { SOKOL_API_IMPL double stm_sec(uint64_t ticks)
{
return (double)ticks / 1000000000.0; return (double)ticks / 1000000000.0;
} }
SOKOL_API_IMPL double stm_ms(uint64_t ticks) { SOKOL_API_IMPL double stm_ms(uint64_t ticks)
{
return (double)ticks / 1000000.0; return (double)ticks / 1000000.0;
} }
SOKOL_API_IMPL double stm_us(uint64_t ticks) { SOKOL_API_IMPL double stm_us(uint64_t ticks)
{
return (double)ticks / 1000.0; return (double)ticks / 1000.0;
} }
SOKOL_API_IMPL double stm_ns(uint64_t ticks) { SOKOL_API_IMPL double stm_ns(uint64_t ticks)
{
return (double)ticks; return (double)ticks;
} }
#endif /* SOKOL_IMPL */ #endif /* SOKOL_IMPL */

118
src/sysmisc.c

@ -8,7 +8,8 @@
static char const *const xdg_config_home_env = "XDG_CONFIG_HOME"; static char const *const xdg_config_home_env = "XDG_CONFIG_HOME";
static char const *const home_env = "HOME"; static char const *const home_env = "HOME";
void expand_home_tilde(oso **path) { void expand_home_tilde(oso **path)
{
oso *s = *path; oso *s = *path;
size_t n = osolen(s); size_t n = osolen(s);
if (n < 2) if (n < 2)
@ -30,9 +31,15 @@ done:
} }
ORCA_NOINLINE ORCA_NOINLINE
Cboard_error cboard_copy(Glyph const *gbuffer, Usz field_height, Cboard_error cboard_copy(
Usz field_width, Usz rect_y, Usz rect_x, Usz rect_h, Glyph const *gbuffer,
Usz rect_w) { Usz field_height,
Usz field_width,
Usz rect_y,
Usz rect_x,
Usz rect_h,
Usz rect_w)
{
(void)field_height; (void)field_height;
FILE *fp = FILE *fp =
#ifdef ORCA_OS_MAC #ifdef ORCA_OS_MAC
@ -53,8 +60,8 @@ Cboard_error cboard_copy(Glyph const *gbuffer, Usz field_height,
} }
ORCA_NOINLINE ORCA_NOINLINE
Cboard_error cboard_paste(Glyph *gbuffer, Usz height, Usz width, Usz y, Usz x, Cboard_error cboard_paste(Glyph *gbuffer, Usz height, Usz width, Usz y, Usz x, Usz *out_h, Usz *out_w)
Usz *out_h, Usz *out_w) { {
FILE *fp = FILE *fp =
#ifdef ORCA_OS_MAC #ifdef ORCA_OS_MAC
popen("pbpaste -pboard general -Prefer txt 2>/dev/null", "r"); popen("pbpaste -pboard general -Prefer txt 2>/dev/null", "r");
@ -94,9 +101,15 @@ Cboard_error cboard_paste(Glyph *gbuffer, Usz height, Usz width, Usz y, Usz x,
} }
ORCA_NOINLINE ORCA_NOINLINE
Conf_read_result conf_read_line(FILE *file, char *buf, Usz bufsize, Conf_read_result conf_read_line(
char **out_left, Usz *out_leftsize, FILE *file,
char **out_right, Usz *out_rightsize) { char *buf,
Usz bufsize,
char **out_left,
Usz *out_leftsize,
char **out_right,
Usz *out_rightsize)
{
// a0 and a1 are the start and end positions of the left side of an "foo=bar" // a0 and a1 are the start and end positions of the left side of an "foo=bar"
// pair. b0 and b1 are the positions right side. Leading and trailing spaces // pair. b0 and b1 are the positions right side. Leading and trailing spaces
// will be removed. // will be removed.
@ -208,16 +221,22 @@ ok:
return Conf_read_left_and_right; return Conf_read_left_and_right;
} }
bool conf_read_match(FILE **pfile, char const *const *names, Usz nameslen, bool conf_read_match(
char *buf, Usz bufsize, Usz *out_index, char **out_value) { FILE **pfile,
char const *const *names,
Usz nameslen,
char *buf,
Usz bufsize,
Usz *out_index,
char **out_value)
{
FILE *file = *pfile; FILE *file = *pfile;
if (!file) if (!file)
return false; return false;
char *left; char *left;
Usz leftsz, rightsz; Usz leftsz, rightsz;
next_line:; next_line:;
Conf_read_result res = Conf_read_result res = conf_read_line(file, buf, bufsize, &left, &leftsz, out_value, &rightsz);
conf_read_line(file, buf, bufsize, &left, &leftsz, out_value, &rightsz);
switch (res) { switch (res) {
case Conf_read_left_and_right: case Conf_read_left_and_right:
for (Usz i = 0; i < nameslen; i++) { for (Usz i = 0; i < nameslen; i++) {
@ -239,12 +258,14 @@ next_line:;
return false; return false;
} }
typedef enum { typedef enum
{
Conf_dir_ok = 0, Conf_dir_ok = 0,
Conf_dir_no_home, Conf_dir_no_home,
} Conf_dir_error; } Conf_dir_error;
static Conf_dir_error try_get_conf_dir(oso **out) { static Conf_dir_error try_get_conf_dir(oso **out)
{
char const *xdgcfgdir = getenv(xdg_config_home_env); char const *xdgcfgdir = getenv(xdg_config_home_env);
if (xdgcfgdir) { if (xdgcfgdir) {
Usz xdgcfgdirlen = strlen(xdgcfgdir); Usz xdgcfgdirlen = strlen(xdgcfgdir);
@ -264,8 +285,8 @@ static Conf_dir_error try_get_conf_dir(oso **out) {
return Conf_dir_no_home; return Conf_dir_no_home;
} }
static void conf_impl_catconfpath(oso **p, char const *conf_file_name, static void conf_impl_catconfpath(oso **p, char const *conf_file_name, size_t conflen)
size_t conflen) { {
oso *path = *p; oso *path = *p;
size_t n = osolen(path); size_t n = osolen(path);
osoensurecap(&path, n + 1 + conflen); osoensurecap(&path, n + 1 + conflen);
@ -279,7 +300,8 @@ done:
*p = path; *p = path;
} }
FILE *conf_file_open_for_reading(char const *conf_file_name) { FILE *conf_file_open_for_reading(char const *conf_file_name)
{
if (!conf_file_name) if (!conf_file_name)
return NULL; return NULL;
oso *path = NULL; oso *path = NULL;
@ -296,9 +318,9 @@ FILE *conf_file_open_for_reading(char const *conf_file_name) {
return file; return file;
} }
Conf_save_start_error conf_save_start(Conf_save *p, Conf_save_start_error conf_save_start(Conf_save *p, char const *conf_file_name)
char const *conf_file_name) { {
*p = (Conf_save){0}; *p = (Conf_save){ 0 };
oso *dir = NULL; oso *dir = NULL;
Conf_save_start_error err; Conf_save_start_error err;
if (!conf_file_name) { if (!conf_file_name) {
@ -369,17 +391,19 @@ cleanup:
return err; return err;
} }
void conf_save_cancel(Conf_save *p) { void conf_save_cancel(Conf_save *p)
{
osofree(p->canonpath); osofree(p->canonpath);
osofree(p->temppath); osofree(p->temppath);
if (p->origfile) if (p->origfile)
fclose(p->origfile); fclose(p->origfile);
if (p->tempfile) if (p->tempfile)
fclose(p->tempfile); fclose(p->tempfile);
*p = (Conf_save){0}; *p = (Conf_save){ 0 };
} }
Conf_save_commit_error conf_save_commit(Conf_save *p) { Conf_save_commit_error conf_save_commit(Conf_save *p)
{
Conf_save_commit_error err; Conf_save_commit_error err;
fclose(p->tempfile); fclose(p->tempfile);
p->tempfile = NULL; p->tempfile = NULL;
@ -401,7 +425,8 @@ cleanup:
return err; return err;
} }
char const *ezconf_w_errorstring(Ezconf_w_error error) { char const *ezconf_w_errorstring(Ezconf_w_error error)
{
switch (error) { switch (error) {
case Ezconf_w_ok: case Ezconf_w_ok:
return "No error"; return "No error";
@ -438,25 +463,34 @@ char const *ezconf_w_errorstring(Ezconf_w_error error) {
return "Unknown"; return "Unknown";
} }
void ezconf_r_start(Ezconf_r *ezcr, char const *conf_file_name) { void ezconf_r_start(Ezconf_r *ezcr, char const *conf_file_name)
{
ezcr->file = conf_file_open_for_reading(conf_file_name); ezcr->file = conf_file_open_for_reading(conf_file_name);
ezcr->index = 0; ezcr->index = 0;
ezcr->value = NULL; ezcr->value = NULL;
} }
bool ezconf_r_step(Ezconf_r *ezcr, char const *const *names, size_t nameslen) { bool ezconf_r_step(Ezconf_r *ezcr, char const *const *names, size_t nameslen)
return conf_read_match(&ezcr->file, names, nameslen, ezcr->buffer, {
sizeof ezcr->buffer, &ezcr->index, &ezcr->value); return conf_read_match(
&ezcr->file,
names,
nameslen,
ezcr->buffer,
sizeof ezcr->buffer,
&ezcr->index,
&ezcr->value);
} }
enum { enum
{
Confwflag_add_newline = 1 << 0, Confwflag_add_newline = 1 << 0,
Ezconf_opt_written = 1 << 0, Ezconf_opt_written = 1 << 0,
}; };
void ezconf_w_start(Ezconf_w *ezcw, Ezconf_opt *optsbuffer, size_t buffercap, void ezconf_w_start(Ezconf_w *ezcw, Ezconf_opt *optsbuffer, size_t buffercap, char const *conf_file_name)
char const *conf_file_name) { {
*ezcw = (Ezconf_w){.save = {0}}; // Weird to silence clang warning *ezcw = (Ezconf_w){ .save = { 0 } }; // Weird to silence clang warning
ezcw->opts = optsbuffer; ezcw->opts = optsbuffer;
ezcw->optscap = buffercap; ezcw->optscap = buffercap;
Ezconf_w_error error = Ezconf_w_unknown_error; Ezconf_w_error error = Ezconf_w_unknown_error;
@ -492,14 +526,16 @@ void ezconf_w_start(Ezconf_w *ezcw, Ezconf_opt *optsbuffer, size_t buffercap,
} }
ezcw->error = error; ezcw->error = error;
} }
void ezconf_w_addopt(Ezconf_w *ezcw, char const *key, intptr_t id) { void ezconf_w_addopt(Ezconf_w *ezcw, char const *key, intptr_t id)
{
size_t count = ezcw->optscount, cap = ezcw->optscap; size_t count = ezcw->optscount, cap = ezcw->optscap;
if (count == cap) if (count == cap)
return; return;
ezcw->opts[count] = (Ezconf_opt){.name = key, .id = id, .flags = 0}; ezcw->opts[count] = (Ezconf_opt){ .name = key, .id = id, .flags = 0 };
ezcw->optscount = count + 1; ezcw->optscount = count + 1;
} }
bool ezconf_w_step(Ezconf_w *ezcw) { bool ezconf_w_step(Ezconf_w *ezcw)
{
uint32_t stateflags = ezcw->stateflags; uint32_t stateflags = ezcw->stateflags;
FILE *origfile = ezcw->save.origfile, *tempfile = ezcw->save.tempfile; FILE *origfile = ezcw->save.origfile, *tempfile = ezcw->save.tempfile;
Ezconf_opt *opts = ezcw->opts, *chosen = NULL; Ezconf_opt *opts = ezcw->opts, *chosen = NULL;
@ -520,8 +556,14 @@ bool ezconf_w_step(Ezconf_w *ezcw) {
char linebuff[1024]; char linebuff[1024];
char *left, *right; char *left, *right;
size_t leftsz, rightsz; size_t leftsz, rightsz;
Conf_read_result res = conf_read_line(origfile, linebuff, sizeof linebuff, Conf_read_result res = conf_read_line(
&left, &leftsz, &right, &rightsz); origfile,
linebuff,
sizeof linebuff,
&left,
&leftsz,
&right,
&rightsz);
switch (res) { switch (res) {
case Conf_read_left_and_right: { case Conf_read_left_and_right: {
for (size_t i = 0; i < optscount; i++) { for (size_t i = 0; i < optscount; i++) {

53
src/sysmisc.h

@ -5,21 +5,27 @@ struct oso;
void expand_home_tilde(struct oso **path); void expand_home_tilde(struct oso **path);
typedef enum { typedef enum
{
Cboard_error_none = 0, Cboard_error_none = 0,
Cboard_error_unavailable, Cboard_error_unavailable,
Cboard_error_popen_failed, Cboard_error_popen_failed,
Cboard_error_process_exit_error, Cboard_error_process_exit_error,
} Cboard_error; } Cboard_error;
Cboard_error cboard_copy(Glyph const *gbuffer, Usz field_height, Cboard_error cboard_copy(
Usz field_width, Usz rect_y, Usz rect_x, Usz rect_h, Glyph const *gbuffer,
Usz field_height,
Usz field_width,
Usz rect_y,
Usz rect_x,
Usz rect_h,
Usz rect_w); Usz rect_w);
Cboard_error cboard_paste(Glyph *gbuffer, Usz height, Usz width, Usz y, Usz x, Cboard_error cboard_paste(Glyph *gbuffer, Usz height, Usz width, Usz y, Usz x, Usz *out_h, Usz *out_w);
Usz *out_h, Usz *out_w);
typedef enum { typedef enum
{
Conf_read_left_and_right = 0, // left and right will be set Conf_read_left_and_right = 0, // left and right will be set
Conf_read_irrelevant, // only left will be set Conf_read_irrelevant, // only left will be set
Conf_read_buffer_too_small, // neither will be set Conf_read_buffer_too_small, // neither will be set
@ -27,12 +33,23 @@ typedef enum {
Conf_read_io_error, // " Conf_read_io_error, // "
} Conf_read_result; } Conf_read_result;
Conf_read_result conf_read_line(FILE *file, char *buf, Usz bufsize, Conf_read_result conf_read_line(
char **out_left, Usz *out_leftlen, FILE *file,
char **out_right, Usz *out_rightlen); char *buf,
Usz bufsize,
bool conf_read_match(FILE **pfile, char const *const *names, Usz nameslen, char **out_left,
char *buf, Usz bufsize, Usz *out_index, char **out_value); Usz *out_leftlen,
char **out_right,
Usz *out_rightlen);
bool conf_read_match(
FILE **pfile,
char const *const *names,
Usz nameslen,
char *buf,
Usz bufsize,
Usz *out_index,
char **out_value);
FILE *conf_file_open_for_reading(char const *conf_file_name); FILE *conf_file_open_for_reading(char const *conf_file_name);
@ -41,7 +58,8 @@ typedef struct {
struct oso *canonpath, *temppath; struct oso *canonpath, *temppath;
} Conf_save; } Conf_save;
typedef enum { typedef enum
{
Conf_save_start_ok = 0, Conf_save_start_ok = 0,
Conf_save_start_bad_conf_name, Conf_save_start_bad_conf_name,
Conf_save_start_alloc_failed, Conf_save_start_alloc_failed,
@ -53,7 +71,8 @@ typedef enum {
Conf_save_start_temp_file_open_failed, Conf_save_start_temp_file_open_failed,
} Conf_save_start_error; } Conf_save_start_error;
typedef enum { typedef enum
{
Conf_save_commit_ok = 0, Conf_save_commit_ok = 0,
Conf_save_commit_temp_fsync_failed, Conf_save_commit_temp_fsync_failed,
Conf_save_commit_temp_close_failed, Conf_save_commit_temp_close_failed,
@ -94,7 +113,8 @@ typedef struct {
void ezconf_r_start(Ezconf_r *ezcr, char const *conf_file_name); void ezconf_r_start(Ezconf_r *ezcr, char const *conf_file_name);
bool ezconf_r_step(Ezconf_r *ezcr, char const *const *names, Usz nameslen); bool ezconf_r_step(Ezconf_r *ezcr, char const *const *names, Usz nameslen);
typedef enum { typedef enum
{
Ezconf_w_ok = 0, Ezconf_w_ok = 0,
Ezconf_w_bad_conf_name, Ezconf_w_bad_conf_name,
Ezconf_w_oom, Ezconf_w_oom,
@ -130,7 +150,6 @@ typedef struct {
uint32_t stateflags; uint32_t stateflags;
} Ezconf_w; } Ezconf_w;
void ezconf_w_start(Ezconf_w *ezcw, Ezconf_opt *optsbuffer, size_t buffercap, void ezconf_w_start(Ezconf_w *ezcw, Ezconf_opt *optsbuffer, size_t buffercap, char const *conf_file_name);
char const *conf_file_name);
void ezconf_w_addopt(Ezconf_w *ezcw, char const *key, intptr_t id); void ezconf_w_addopt(Ezconf_w *ezcw, char const *key, intptr_t id);
bool ezconf_w_step(Ezconf_w *ezcw); bool ezconf_w_step(Ezconf_w *ezcw);

207
src/term_util.c

@ -3,15 +3,18 @@
#include <ctype.h> #include <ctype.h>
#include <form.h> #include <form.h>
void term_util_init_colors() { void term_util_init_colors()
{
if (has_colors()) { if (has_colors()) {
// Enable color // Enable color
start_color(); start_color();
use_default_colors(); use_default_colors();
for (int ifg = 0; ifg < Colors_count; ++ifg) { for (int ifg = 0; ifg < Colors_count; ++ifg) {
for (int ibg = 0; ibg < Colors_count; ++ibg) { for (int ibg = 0; ibg < Colors_count; ++ibg) {
int res = init_pair((short int)(1 + ifg * Colors_count + ibg), int res = init_pair(
(short int)(ifg - 1), (short int)(ibg - 1)); (short int)(1 + ifg * Colors_count + ibg),
(short int)(ifg - 1),
(short int)(ibg - 1));
(void)res; (void)res;
// Might fail on Linux virtual console/terminal for a couple of colors. // Might fail on Linux virtual console/terminal for a couple of colors.
// Just ignore. // Just ignore.
@ -29,8 +32,7 @@ void term_util_init_colors() {
} }
#define ORCA_CONTAINER_OF(ptr, type, member) \ #define ORCA_CONTAINER_OF(ptr, type, member) \
((type *)((char *)(1 ? (ptr) : &((type *)0)->member) - \ ((type *)((char *)(1 ? (ptr) : &((type *)0)->member) - offsetof(type, member)))
offsetof(type, member)))
struct Qmsg { struct Qmsg {
Qblock qblock; Qblock qblock;
@ -65,8 +67,12 @@ ORCA_NOINLINE static void qmenu_reprint(Qmenu *qm);
Qnav_stack qnav_stack; Qnav_stack qnav_stack;
void qnav_init() { qnav_stack = (Qnav_stack){0}; } void qnav_init()
void qnav_deinit() { {
qnav_stack = (Qnav_stack){ 0 };
}
void qnav_deinit()
{
while (qnav_stack.top) while (qnav_stack.top)
qnav_stack_pop(); qnav_stack_pop();
} }
@ -77,7 +83,8 @@ void qnav_deinit() {
// you've finished doing the rest of the setup on the Qblock. The y and x // you've finished doing the rest of the setup on the Qblock. The y and x
// fields can be junk, though, since this function writes to them without // fields can be junk, though, since this function writes to them without
// reading them. // reading them.
static ORCA_NOINLINE void qnav_reposition_block(Qblock *qb) { static ORCA_NOINLINE void qnav_reposition_block(Qblock *qb)
{
int top = 0, left = 0; int top = 0, left = 0;
Qblock *prev = qb->down; Qblock *prev = qb->down;
if (!prev) if (!prev)
@ -114,7 +121,8 @@ done:
qb->y = top; qb->y = top;
qb->x = left; qb->x = left;
} }
static ORCA_NOINLINE void qnav_stack_push(Qblock *qb, int height, int width) { static ORCA_NOINLINE void qnav_stack_push(Qblock *qb, int height, int width)
{
#ifndef NDEBUG #ifndef NDEBUG
for (Qblock *i = qnav_stack.top; i; i = i->down) { for (Qblock *i = qnav_stack.top; i; i = i->down) {
assert(i != qb); assert(i != qb);
@ -133,14 +141,19 @@ static ORCA_NOINLINE void qnav_stack_push(Qblock *qb, int height, int width) {
qnav_stack.occlusion_dirty = true; qnav_stack.occlusion_dirty = true;
} }
Qblock *qnav_top_block() { return qnav_stack.top; } Qblock *qnav_top_block()
{
return qnav_stack.top;
}
void qblock_init(Qblock *qb, Qblock_type_tag tag) { void qblock_init(Qblock *qb, Qblock_type_tag tag)
*qb = (Qblock){0}; {
*qb = (Qblock){ 0 };
qb->tag = tag; qb->tag = tag;
} }
void qnav_free_block(Qblock *qb) { void qnav_free_block(Qblock *qb)
{
switch (qb->tag) { switch (qb->tag) {
case Qblock_type_qmsg: { case Qblock_type_qmsg: {
Qmsg *qm = qmsg_of(qb); Qmsg *qm = qmsg_of(qb);
@ -156,7 +169,8 @@ void qnav_free_block(Qblock *qb) {
} }
} }
void qnav_stack_pop(void) { void qnav_stack_pop(void)
{
assert(qnav_stack.top); assert(qnav_stack.top);
if (!qnav_stack.top) if (!qnav_stack.top)
return; return;
@ -178,7 +192,8 @@ void qnav_stack_pop(void) {
delwin(outer_window); delwin(outer_window);
} }
bool qnav_draw(void) { bool qnav_draw(void)
{
bool drew_any = false; bool drew_any = false;
if (!qnav_stack.bottom) if (!qnav_stack.bottom)
goto done; goto done;
@ -227,7 +242,8 @@ done:
return drew_any; return drew_any;
} }
void qnav_adjust_term_size(void) { void qnav_adjust_term_size(void)
{
if (!qnav_stack.bottom) if (!qnav_stack.bottom)
return; return;
for (Qblock *qb = qnav_stack.bottom; qb; qb = qb->up) for (Qblock *qb = qnav_stack.bottom; qb; qb = qb->up)
@ -235,13 +251,22 @@ void qnav_adjust_term_size(void) {
qnav_stack.occlusion_dirty = true; qnav_stack.occlusion_dirty = true;
} }
void qblock_print_border(Qblock *qb, unsigned int attr) { void qblock_print_border(Qblock *qb, unsigned int attr)
wborder(qb->outer_window, ACS_VLINE | attr, ACS_VLINE | attr, {
ACS_HLINE | attr, ACS_HLINE | attr, ACS_ULCORNER | attr, wborder(
ACS_URCORNER | attr, ACS_LLCORNER | attr, ACS_LRCORNER | attr); qb->outer_window,
ACS_VLINE | attr,
ACS_VLINE | attr,
ACS_HLINE | attr,
ACS_HLINE | attr,
ACS_ULCORNER | attr,
ACS_URCORNER | attr,
ACS_LLCORNER | attr,
ACS_LRCORNER | attr);
} }
void qblock_print_title(Qblock *qb, char const *title, int attr) { void qblock_print_title(Qblock *qb, char const *title, int attr)
{
wmove(qb->outer_window, 0, 1); wmove(qb->outer_window, 0, 1);
attr_t attrs = A_NORMAL; attr_t attrs = A_NORMAL;
short pair = 0; short pair = 0;
@ -253,9 +278,13 @@ void qblock_print_title(Qblock *qb, char const *title, int attr) {
wattr_set(qb->outer_window, attrs, pair, NULL); wattr_set(qb->outer_window, attrs, pair, NULL);
} }
void qblock_set_title(Qblock *qb, char const *title) { qb->title = title; } void qblock_set_title(Qblock *qb, char const *title)
{
qb->title = title;
}
void qblock_print_frame(Qblock *qb, bool active) { void qblock_print_frame(Qblock *qb, bool active)
{
qblock_print_border(qb, active ? A_NORMAL : A_DIM); qblock_print_border(qb, active ? A_NORMAL : A_DIM);
if (qb->title) { if (qb->title) {
qblock_print_title(qb, qb->title, active ? A_NORMAL : A_DIM); qblock_print_title(qb, qb->title, active ? A_NORMAL : A_DIM);
@ -268,19 +297,25 @@ void qblock_print_frame(Qblock *qb, bool active) {
} }
} }
WINDOW *qmsg_window(Qmsg *qm) { return qm->qblock.content_window; } WINDOW *qmsg_window(Qmsg *qm)
{
return qm->qblock.content_window;
}
void qmsg_set_title(Qmsg *qm, char const *title) { void qmsg_set_title(Qmsg *qm, char const *title)
{
qblock_set_title(&qm->qblock, title); qblock_set_title(&qm->qblock, title);
} }
void qmsg_set_dismiss_mode(Qmsg *qm, Qmsg_dismiss_mode mode) { void qmsg_set_dismiss_mode(Qmsg *qm, Qmsg_dismiss_mode mode)
{
if (qm->dismiss_mode == mode) if (qm->dismiss_mode == mode)
return; return;
qm->dismiss_mode = mode; qm->dismiss_mode = mode;
} }
Qmsg *qmsg_push(int height, int width) { Qmsg *qmsg_push(int height, int width)
{
Qmsg *qm = malloc(sizeof(Qmsg)); Qmsg *qm = malloc(sizeof(Qmsg));
qblock_init(&qm->qblock, Qblock_type_qmsg); qblock_init(&qm->qblock, Qblock_type_qmsg);
qm->dismiss_mode = Qmsg_dismiss_mode_explicitly; qm->dismiss_mode = Qmsg_dismiss_mode_explicitly;
@ -288,7 +323,8 @@ Qmsg *qmsg_push(int height, int width) {
return qm; return qm;
} }
Qmsg *qmsg_printf_push(char const *title, char const *fmt, ...) { Qmsg *qmsg_printf_push(char const *title, char const *fmt, ...)
{
int titlewidth = title ? (int)strlen(title) : 0; int titlewidth = title ? (int)strlen(title) : 0;
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
@ -339,8 +375,9 @@ Qmsg *qmsg_printf_push(char const *title, char const *fmt, ...) {
return msg; return msg;
} }
bool qmsg_drive(Qmsg *qm, int key, Qmsg_action *out_action) { bool qmsg_drive(Qmsg *qm, int key, Qmsg_action *out_action)
*out_action = (Qmsg_action){0}; {
*out_action = (Qmsg_action){ 0 };
Qmsg_dismiss_mode dm = qm->dismiss_mode; Qmsg_dismiss_mode dm = qm->dismiss_mode;
switch (dm) { switch (dm) {
case Qmsg_dismiss_mode_explicitly: case Qmsg_dismiss_mode_explicitly:
@ -364,9 +401,13 @@ bool qmsg_drive(Qmsg *qm, int key, Qmsg_action *out_action) {
return false; return false;
} }
Qmsg *qmsg_of(Qblock *qb) { return ORCA_CONTAINER_OF(qb, Qmsg, qblock); } Qmsg *qmsg_of(Qblock *qb)
{
return ORCA_CONTAINER_OF(qb, Qmsg, qblock);
}
Qmenu *qmenu_create(int id) { Qmenu *qmenu_create(int id)
{
Qmenu *qm = (Qmenu *)malloc(sizeof(Qmenu)); Qmenu *qm = (Qmenu *)malloc(sizeof(Qmenu));
qblock_init(&qm->qblock, Qblock_type_qmenu); qblock_init(&qm->qblock, Qblock_type_qmenu);
qm->items = NULL; qm->items = NULL;
@ -378,9 +419,16 @@ Qmenu *qmenu_create(int id) {
qm->is_frontmost = 0; qm->is_frontmost = 0;
return qm; return qm;
} }
void qmenu_destroy(Qmenu *qm) { qmenu_free(qm); } void qmenu_destroy(Qmenu *qm)
int qmenu_id(Qmenu const *qm) { return qm->id; } {
static ORCA_NOINLINE Qmenu_item *qmenu_allocitems(Qmenu *qm, Usz count) { qmenu_free(qm);
}
int qmenu_id(Qmenu const *qm)
{
return qm->id;
}
static ORCA_NOINLINE Qmenu_item *qmenu_allocitems(Qmenu *qm, Usz count)
{
Usz old_count = qm->items_count; Usz old_count = qm->items_count;
if (old_count > SIZE_MAX - count) // overflow if (old_count > SIZE_MAX - count) // overflow
exit(1); exit(1);
@ -402,7 +450,8 @@ static ORCA_NOINLINE Qmenu_item *qmenu_allocitems(Qmenu *qm, Usz count) {
qm->items_count = new_count; qm->items_count = new_count;
return items + old_count; return items + old_count;
} }
ORCA_NOINLINE static void qmenu_reprint(Qmenu *qm) { ORCA_NOINLINE static void qmenu_reprint(Qmenu *qm)
{
WINDOW *win = qm->qblock.content_window; WINDOW *win = qm->qblock.content_window;
Qmenu_item *items = qm->items; Qmenu_item *items = qm->items;
bool isfront = qm->is_frontmost; bool isfront = qm->is_frontmost;
@ -416,10 +465,12 @@ ORCA_NOINLINE static void qmenu_reprint(Qmenu *qm) {
waddstr(win, items[i].text); waddstr(win, items[i].text);
} }
} }
void qmenu_set_title(Qmenu *qm, char const *title) { void qmenu_set_title(Qmenu *qm, char const *title)
{
qblock_set_title(&qm->qblock, title); qblock_set_title(&qm->qblock, title);
} }
void qmenu_add_choice(Qmenu *qm, int id, char const *text) { void qmenu_add_choice(Qmenu *qm, int id, char const *text)
{
assert(id != 0); assert(id != 0);
Qmenu_item *item = qmenu_allocitems(qm, 1); Qmenu_item *item = qmenu_allocitems(qm, 1);
item->text = text; item->text = text;
@ -429,7 +480,8 @@ void qmenu_add_choice(Qmenu *qm, int id, char const *text) {
if (!qm->current_item) if (!qm->current_item)
qm->current_item = id; qm->current_item = id;
} }
void qmenu_add_printf(Qmenu *qm, int id, char const *fmt, ...) { void qmenu_add_printf(Qmenu *qm, int id, char const *fmt, ...)
{
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
int textsize = vsnprintf(NULL, 0, fmt, ap); int textsize = vsnprintf(NULL, 0, fmt, ap);
@ -450,21 +502,27 @@ void qmenu_add_printf(Qmenu *qm, int id, char const *fmt, ...) {
if (!qm->current_item) if (!qm->current_item)
qm->current_item = id; qm->current_item = id;
} }
void qmenu_add_spacer(Qmenu *qm) { void qmenu_add_spacer(Qmenu *qm)
{
Qmenu_item *item = qmenu_allocitems(qm, 1); Qmenu_item *item = qmenu_allocitems(qm, 1);
item->text = " "; item->text = " ";
item->id = 0; item->id = 0;
item->owns_string = false; item->owns_string = false;
item->is_spacer = true; item->is_spacer = true;
} }
void qmenu_set_current_item(Qmenu *qm, int id) { void qmenu_set_current_item(Qmenu *qm, int id)
{
if (qm->current_item == id) if (qm->current_item == id)
return; return;
qm->current_item = id; qm->current_item = id;
qm->needs_reprint = 1; qm->needs_reprint = 1;
} }
int qmenu_current_item(Qmenu *qm) { return qm->current_item; } int qmenu_current_item(Qmenu *qm)
void qmenu_push_to_nav(Qmenu *qm) { {
return qm->current_item;
}
void qmenu_push_to_nav(Qmenu *qm)
{
// Probably a programming error if there are no items. Make the menu visible // Probably a programming error if there are no items. Make the menu visible
// so the programmer knows something went wrong. // so the programmer knows something went wrong.
if (qm->items_count == 0) if (qm->items_count == 0)
@ -489,7 +547,8 @@ void qmenu_push_to_nav(Qmenu *qm) {
qnav_stack_push(&qm->qblock, menu_min_h, menu_min_w); qnav_stack_push(&qm->qblock, menu_min_h, menu_min_w);
} }
static void qmenu_free(Qmenu *qm) { static void qmenu_free(Qmenu *qm)
{
Qmenu_item *items = qm->items; Qmenu_item *items = qm->items;
for (Usz i = 0, n = qm->items_count; i < n; ++i) { for (Usz i = 0, n = qm->items_count; i < n; ++i) {
if (items[i].owns_string) if (items[i].owns_string)
@ -499,7 +558,8 @@ static void qmenu_free(Qmenu *qm) {
free(qm); free(qm);
} }
ORCA_NOINLINE static void qmenu_drive_upordown(Qmenu *qm, bool downwards) { ORCA_NOINLINE static void qmenu_drive_upordown(Qmenu *qm, bool downwards)
{
Qmenu_item *items = qm->items; Qmenu_item *items = qm->items;
Usz n = qm->items_count; Usz n = qm->items_count;
if (n <= 1) if (n <= 1)
@ -529,7 +589,8 @@ found:;
} }
} }
bool qmenu_drive(Qmenu *qm, int key, Qmenu_action *out_action) { bool qmenu_drive(Qmenu *qm, int key, Qmenu_action *out_action)
{
switch (key) { switch (key) {
case 27: { case 27: {
out_action->any.type = Qmenu_action_type_canceled; out_action->any.type = Qmenu_action_type_canceled;
@ -551,9 +612,13 @@ bool qmenu_drive(Qmenu *qm, int key, Qmenu_action *out_action) {
return false; return false;
} }
Qmenu *qmenu_of(Qblock *qb) { return ORCA_CONTAINER_OF(qb, Qmenu, qblock); } Qmenu *qmenu_of(Qblock *qb)
{
return ORCA_CONTAINER_OF(qb, Qmenu, qblock);
}
bool qmenu_top_is_menu(int id) { bool qmenu_top_is_menu(int id)
{
Qblock *qb = qnav_top_block(); Qblock *qb = qnav_top_block();
if (!qb) if (!qb)
return false; return false;
@ -563,7 +628,8 @@ bool qmenu_top_is_menu(int id) {
return qm->id == id; return qm->id == id;
} }
Qform *qform_create(int id) { Qform *qform_create(int id)
{
Qform *qf = (Qform *)malloc(sizeof(Qform)); Qform *qf = (Qform *)malloc(sizeof(Qform));
qblock_init(&qf->qblock, Qblock_type_qform); qblock_init(&qf->qblock, Qblock_type_qform);
qf->ncurses_form = NULL; qf->ncurses_form = NULL;
@ -572,7 +638,8 @@ Qform *qform_create(int id) {
qf->id = id; qf->id = id;
return qf; return qf;
} }
static void qform_free(Qform *qf) { static void qform_free(Qform *qf)
{
curs_set(0); curs_set(0);
unpost_form(qf->ncurses_form); unpost_form(qf->ncurses_form);
free_form(qf->ncurses_form); free_form(qf->ncurses_form);
@ -581,12 +648,20 @@ static void qform_free(Qform *qf) {
} }
free(qf); free(qf);
} }
int qform_id(Qform const *qf) { return qf->id; } int qform_id(Qform const *qf)
Qform *qform_of(Qblock *qb) { return ORCA_CONTAINER_OF(qb, Qform, qblock); } {
void qform_set_title(Qform *qf, char const *title) { return qf->id;
}
Qform *qform_of(Qblock *qb)
{
return ORCA_CONTAINER_OF(qb, Qform, qblock);
}
void qform_set_title(Qform *qf, char const *title)
{
qblock_set_title(&qf->qblock, title); qblock_set_title(&qf->qblock, title);
} }
void qform_add_line_input(Qform *qf, int id, char const *initial) { void qform_add_line_input(Qform *qf, int id, char const *initial)
{
FIELD *f = new_field(1, 30, 0, 0, 0, 0); FIELD *f = new_field(1, 30, 0, 0, 0, 0);
if (initial) if (initial)
set_field_buffer(f, 0, initial); set_field_buffer(f, 0, initial);
@ -596,7 +671,8 @@ void qform_add_line_input(Qform *qf, int id, char const *initial) {
++qf->fields_count; ++qf->fields_count;
qf->ncurses_fields[qf->fields_count] = NULL; qf->ncurses_fields[qf->fields_count] = NULL;
} }
void qform_push_to_nav(Qform *qf) { void qform_push_to_nav(Qform *qf)
{
qf->ncurses_form = new_form(qf->ncurses_fields); qf->ncurses_form = new_form(qf->ncurses_fields);
int form_min_h, form_min_w; int form_min_h, form_min_w;
scale_form(qf->ncurses_form, &form_min_h, &form_min_w); scale_form(qf->ncurses_form, &form_min_h, &form_min_w);
@ -608,13 +684,15 @@ void qform_push_to_nav(Qform *qf) {
curs_set(1); curs_set(1);
form_driver(qf->ncurses_form, REQ_END_LINE); form_driver(qf->ncurses_form, REQ_END_LINE);
} }
void qform_single_line_input(int id, char const *title, char const *initial) { void qform_single_line_input(int id, char const *title, char const *initial)
{
Qform *qf = qform_create(id); Qform *qf = qform_create(id);
qform_set_title(qf, title); qform_set_title(qf, title);
qform_add_line_input(qf, 1, initial); qform_add_line_input(qf, 1, initial);
qform_push_to_nav(qf); qform_push_to_nav(qf);
} }
bool qform_drive(Qform *qf, int key, Qform_action *out_action) { bool qform_drive(Qform *qf, int key, Qform_action *out_action)
{
switch (key) { switch (key) {
case 27: case 27:
out_action->any.type = Qform_action_type_canceled; out_action->any.type = Qform_action_type_canceled;
@ -653,7 +731,8 @@ bool qform_drive(Qform *qf, int key, Qform_action *out_action) {
form_driver(qf->ncurses_form, key); form_driver(qf->ncurses_form, key);
return false; return false;
} }
static Usz size_without_trailing_spaces(char const *str) { static Usz size_without_trailing_spaces(char const *str)
{
Usz size = strlen(str); Usz size = strlen(str);
for (;;) { for (;;) {
if (size == 0) if (size == 0)
@ -664,7 +743,8 @@ static Usz size_without_trailing_spaces(char const *str) {
} }
return size; return size;
} }
static FIELD *qform_find_field(Qform const *qf, int id) { static FIELD *qform_find_field(Qform const *qf, int id)
{
Usz count = qf->fields_count; Usz count = qf->fields_count;
for (Usz i = 0; i < count; ++i) { for (Usz i = 0; i < count; ++i) {
FIELD *f = qf->ncurses_fields[i]; FIELD *f = qf->ncurses_fields[i];
@ -673,7 +753,8 @@ static FIELD *qform_find_field(Qform const *qf, int id) {
} }
return NULL; return NULL;
} }
bool qform_get_text_line(Qform const *qf, int id, oso **out) { bool qform_get_text_line(Qform const *qf, int id, oso **out)
{
FIELD *f = qform_find_field(qf, id); FIELD *f = qform_find_field(qf, id);
if (!f) if (!f)
return false; return false;
@ -685,10 +766,12 @@ bool qform_get_text_line(Qform const *qf, int id, oso **out) {
osoputlen(out, buf, trimmed); osoputlen(out, buf, trimmed);
return true; return true;
} }
bool qform_get_single_text_line(Qform const *qf, struct oso **out) { bool qform_get_single_text_line(Qform const *qf, struct oso **out)
{
return qform_get_text_line(qf, 1, out); return qform_get_text_line(qf, 1, out);
} }
oso *qform_get_nonempty_single_line_input(Qform *qf) { oso *qform_get_nonempty_single_line_input(Qform *qf)
{
oso *s = NULL; oso *s = NULL;
if (qform_get_text_line(qf, 1, &s) && osolen(s) > 0) if (qform_get_text_line(qf, 1, &s) && osolen(s) > 0)
return s; return s;

44
src/term_util.h

@ -3,19 +3,20 @@
#include <ncurses.h> #include <ncurses.h>
#if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute) #if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute)
#if __has_attribute(format) #if __has_attribute(format)
#define ORCA_TERM_UTIL_PRINTF(...) __attribute__((format(printf, __VA_ARGS__))) #define ORCA_TERM_UTIL_PRINTF(...) __attribute__((format(printf, __VA_ARGS__)))
#endif #endif
#endif #endif
#ifndef ORCA_TERM_UTIL_PRINTF #ifndef ORCA_TERM_UTIL_PRINTF
#define ORCA_TERM_UTIL_PRINTF(...) #define ORCA_TERM_UTIL_PRINTF(...)
#endif #endif
#define CTRL_PLUS(c) ((c)&037) #define CTRL_PLUS(c) ((c)&037)
struct oso; struct oso;
typedef enum { typedef enum
{
C_natural, C_natural,
C_black, C_black,
C_red, C_red,
@ -27,15 +28,18 @@ typedef enum {
C_white, C_white,
} Color_name; } Color_name;
enum { enum
{
Colors_count = C_white + 1, Colors_count = C_white + 1,
}; };
enum { enum
{
Cdef_normal = COLOR_PAIR(1), Cdef_normal = COLOR_PAIR(1),
}; };
typedef enum { typedef enum
{
A_normal = A_NORMAL, A_normal = A_NORMAL,
A_bold = A_BOLD, A_bold = A_BOLD,
A_dim = A_DIM, A_dim = A_DIM,
@ -43,14 +47,15 @@ typedef enum {
A_reverse = A_REVERSE, A_reverse = A_REVERSE,
} Term_attr; } Term_attr;
static ORCA_FORCEINLINE ORCA_OK_IF_UNUSED attr_t fg_bg(Color_name fg, static ORCA_FORCEINLINE ORCA_OK_IF_UNUSED attr_t fg_bg(Color_name fg, Color_name bg)
Color_name bg) { {
return COLOR_PAIR(1 + fg * Colors_count + bg); return COLOR_PAIR(1 + fg * Colors_count + bg);
} }
void term_util_init_colors(void); void term_util_init_colors(void);
typedef enum { typedef enum
{
Qblock_type_qmsg, Qblock_type_qmsg,
Qblock_type_qmenu, Qblock_type_qmenu,
Qblock_type_qform, Qblock_type_qform,
@ -73,7 +78,8 @@ typedef struct Qmsg Qmsg;
typedef struct Qmenu Qmenu; typedef struct Qmenu Qmenu;
typedef enum { typedef enum
{
Qmenu_action_type_canceled, Qmenu_action_type_canceled,
Qmenu_action_type_picked, Qmenu_action_type_picked,
} Qmenu_action_type; } Qmenu_action_type;
@ -94,7 +100,8 @@ typedef union {
typedef struct Qform Qform; typedef struct Qform Qform;
typedef enum { typedef enum
{
Qform_action_type_canceled, Qform_action_type_canceled,
Qform_action_type_submitted, Qform_action_type_submitted,
} Qform_action_type; } Qform_action_type;
@ -105,7 +112,8 @@ typedef union {
Qform_action_any any; Qform_action_any any;
} Qform_action; } Qform_action;
typedef enum { typedef enum
{
Qmsg_dismiss_mode_explicitly, // Space, return, escape dismisses. Default. Qmsg_dismiss_mode_explicitly, // Space, return, escape dismisses. Default.
Qmsg_dismiss_mode_easily, // Any key dismisses. Qmsg_dismiss_mode_easily, // Any key dismisses.
Qmsg_dismiss_mode_passthrough, // Easily, and pass through key event. Qmsg_dismiss_mode_passthrough, // Easily, and pass through key event.
@ -126,8 +134,7 @@ void qblock_print_frame(Qblock *qb, bool active);
void qblock_set_title(Qblock *qb, char const *title); void qblock_set_title(Qblock *qb, char const *title);
Qmsg *qmsg_push(int height, int width); Qmsg *qmsg_push(int height, int width);
Qmsg *qmsg_printf_push(char const *title, char const *fmt, ...) Qmsg *qmsg_printf_push(char const *title, char const *fmt, ...) ORCA_TERM_UTIL_PRINTF(2, 3);
ORCA_TERM_UTIL_PRINTF(2, 3);
WINDOW *qmsg_window(Qmsg *qm); WINDOW *qmsg_window(Qmsg *qm);
void qmsg_set_title(Qmsg *qm, char const *title); void qmsg_set_title(Qmsg *qm, char const *title);
void qmsg_set_dismiss_mode(Qmsg *qm, Qmsg_dismiss_mode mode); void qmsg_set_dismiss_mode(Qmsg *qm, Qmsg_dismiss_mode mode);
@ -142,8 +149,7 @@ void qmenu_destroy(Qmenu *qm);
int qmenu_id(Qmenu const *qm); int qmenu_id(Qmenu const *qm);
void qmenu_set_title(Qmenu *qm, char const *title); void qmenu_set_title(Qmenu *qm, char const *title);
void qmenu_add_choice(Qmenu *qm, int id, char const *text); void qmenu_add_choice(Qmenu *qm, int id, char const *text);
void qmenu_add_printf(Qmenu *qm, int id, char const *fmt, ...) void qmenu_add_printf(Qmenu *qm, int id, char const *fmt, ...) ORCA_TERM_UTIL_PRINTF(3, 4);
ORCA_TERM_UTIL_PRINTF(3, 4);
void qmenu_add_spacer(Qmenu *qm); void qmenu_add_spacer(Qmenu *qm);
void qmenu_set_current_item(Qmenu *qm, int id); void qmenu_set_current_item(Qmenu *qm, int id);
void qmenu_push_to_nav(Qmenu *qm); void qmenu_push_to_nav(Qmenu *qm);
@ -158,7 +164,7 @@ Qform *qform_of(Qblock *qb);
void qform_set_title(Qform *qf, char const *title); void qform_set_title(Qform *qf, char const *title);
void qform_add_line_input(Qform *qf, int id, char const *initial); void qform_add_line_input(Qform *qf, int id, char const *initial);
void qform_push_to_nav(Qform *qf); void qform_push_to_nav(Qform *qf);
void qform_single_line_input(int id, char const *title, char const* initial); void qform_single_line_input(int id, char const *title, char const *initial);
bool qform_drive(Qform *qf, int key, Qform_action *out_action); bool qform_drive(Qform *qf, int key, Qform_action *out_action);
bool qform_get_text_line(Qform const *qf, int id, struct oso **out); bool qform_get_text_line(Qform const *qf, int id, struct oso **out);
bool qform_get_single_text_line(Qform const *qf, struct oso **out); bool qform_get_single_text_line(Qform const *qf, struct oso **out);

1401
src/tui_main.c

File diff suppressed because it is too large

19
src/vmio.c

@ -1,13 +1,21 @@
#include "vmio.h" #include "vmio.h"
void oevent_list_init(Oevent_list *olist) { void oevent_list_init(Oevent_list *olist)
{
olist->buffer = NULL; olist->buffer = NULL;
olist->count = 0; olist->count = 0;
olist->capacity = 0; olist->capacity = 0;
} }
void oevent_list_deinit(Oevent_list *olist) { free(olist->buffer); } void oevent_list_deinit(Oevent_list *olist)
void oevent_list_clear(Oevent_list *olist) { olist->count = 0; } {
void oevent_list_copy(Oevent_list const *src, Oevent_list *dest) { free(olist->buffer);
}
void oevent_list_clear(Oevent_list *olist)
{
olist->count = 0;
}
void oevent_list_copy(Oevent_list const *src, Oevent_list *dest)
{
Usz src_count = src->count; Usz src_count = src->count;
if (dest->capacity < src_count) { if (dest->capacity < src_count) {
Usz new_cap = orca_round_up_power2(src_count); Usz new_cap = orca_round_up_power2(src_count);
@ -17,7 +25,8 @@ void oevent_list_copy(Oevent_list const *src, Oevent_list *dest) {
memcpy(dest->buffer, src->buffer, src_count * sizeof(Oevent)); memcpy(dest->buffer, src->buffer, src_count * sizeof(Oevent));
dest->count = src_count; dest->count = src_count;
} }
Oevent *oevent_list_alloc_item(Oevent_list *olist) { Oevent *oevent_list_alloc_item(Oevent_list *olist)
{
Usz count = olist->count; Usz count = olist->count;
if (olist->capacity == count) { if (olist->capacity == count) {
// Note: no overflow check, but you're probably out of memory if this // Note: no overflow check, but you're probably out of memory if this

13
src/vmio.h

@ -1,7 +1,8 @@
#pragma once #pragma once
#include "base.h" #include "base.h"
typedef enum { typedef enum
{
Oevent_type_midi_note, Oevent_type_midi_note,
Oevent_type_midi_cc, Oevent_type_midi_cc,
Oevent_type_midi_pb, Oevent_type_midi_pb,
@ -28,7 +29,10 @@ typedef struct {
U8 channel, lsb, msb; U8 channel, lsb, msb;
} Oevent_midi_pb; } Oevent_midi_pb;
enum { Oevent_osc_int_count = 35 }; enum
{
Oevent_osc_int_count = 35
};
typedef struct { typedef struct {
U8 oevent_type; U8 oevent_type;
@ -37,7 +41,10 @@ typedef struct {
U8 numbers[Oevent_osc_int_count]; U8 numbers[Oevent_osc_int_count];
} Oevent_osc_ints; } Oevent_osc_ints;
enum { Oevent_udp_string_count = 16 }; enum
{
Oevent_udp_string_count = 16
};
typedef struct { typedef struct {
U8 oevent_type; U8 oevent_type;

Loading…
Cancel
Save