diff --git a/include/StringBuilder.h b/include/StringBuilder.h new file mode 100644 index 0000000..26cb176 --- /dev/null +++ b/include/StringBuilder.h @@ -0,0 +1,72 @@ +#include "memory.h" +#include "text.h" + +struct string_builder { + struct string *outBuffer; + struct string *stringBuffer; + u64 length; +}; + +static inline void +StringBuilderAppendString(struct string_builder *stringBuilder, struct string *string) +{ + struct string *outBuffer = stringBuilder->outBuffer; + memcpy(outBuffer->value + stringBuilder->length, string->value, string->length); + stringBuilder->length += string->length; + debug_assert(stringBuilder->length <= outBuffer->length); +} + +static inline void +StringBuilderAppendU64(struct string_builder *stringBuilder, u64 value) +{ + struct string *outBuffer = stringBuilder->outBuffer; + struct string *stringBuffer = stringBuilder->stringBuffer; + + struct string string = FormatU64(stringBuffer, value); + memcpy(outBuffer->value + stringBuilder->length, string.value, string.length); + stringBuilder->length += string.length; + debug_assert(stringBuilder->length <= outBuffer->length); +} + +static inline void +StringBuilderAppendHex(struct string_builder *stringBuilder, u64 value) +{ + struct string *outBuffer = stringBuilder->outBuffer; + struct string *stringBuffer = stringBuilder->stringBuffer; + + struct string string = FormatHex(stringBuffer, value); + memcpy(outBuffer->value + stringBuilder->length, string.value, string.length); + stringBuilder->length += string.length; + debug_assert(stringBuilder->length <= outBuffer->length); +} + +static inline void +StringBuilderAppendF32(struct string_builder *stringBuilder, f32 value, u64 fractionCount) +{ + struct string *outBuffer = stringBuilder->outBuffer; + struct string *stringBuffer = stringBuilder->stringBuffer; + + struct string string = FormatF32(stringBuffer, value, fractionCount); + memcpy(outBuffer->value + stringBuilder->length, string.value, string.length); + stringBuilder->length += string.length; + debug_assert(stringBuilder->length <= outBuffer->length); +} + +/* + * Returns string that is ready for transmit. + * Also resets length of builder. + * + * @code + * StringBuilderAppend..(stringBuilder, x); + * struct string string = StringBuilderFlush(stringBuilder); + * write(x, string.value, string.length); + * @endcode + */ +static inline struct string +StringBuilderFlush(struct string_builder *stringBuilder) +{ + struct string *outBuffer = stringBuilder->outBuffer; + struct string result = (struct string){.value = outBuffer->value, .length = stringBuilder->length}; + stringBuilder->length = 0; + return result; +} diff --git a/meson.build b/meson.build index 167e0b8..f50bf21 100644 --- a/meson.build +++ b/meson.build @@ -14,6 +14,7 @@ add_project_arguments( '-funroll-loops', '-fomit-frame-pointer', + '-Wno-unused-result', '-Wno-unused-function', '-DCOMPILER_GCC=' + (cc.get_id() == 'gcc').to_int().to_string(), diff --git a/src/main.c b/src/main.c index 7aabe19..736f8e4 100644 --- a/src/main.c +++ b/src/main.c @@ -11,6 +11,7 @@ #include #include +#include "StringBuilder.h" #include "assert.h" #include "memory.h" #include "text.h" @@ -382,30 +383,22 @@ main(int argc, char *argv[]) struct string stdoutBuffer = MemPushString(&memory, 256); struct string stringBuffer = MemPushString(&memory, 32); + struct string_builder stringBuilder = (struct string_builder){ + .outBuffer = &stdoutBuffer, + .stringBuffer = &stringBuffer, + }; #if GAMEPAD_IDLE_INHIBIT_DEBUG { - struct string string; - u64 length = 0; - -#define PRINTLN_U64(prefix, number) \ - string = STRING_FROM_ZERO_TERMINATED(prefix); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length; \ - string = FormatU64(&stringBuffer, number); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length; \ - string = STRING_FROM_ZERO_TERMINATED("\n"); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length - - PRINTLN_U64("total memory usage (in bytes): ", memory.used); - PRINTLN_U64("total memory wasted (in bytes): ", memory.total - memory.used); -#undef PRINTLN_U64 - - // print buffered string to output - debug_assert(length <= stdoutBuffer.length); - write(STDOUT_FILENO, stdoutBuffer.value, length); + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("total memory usage (in bytes): ")); + StringBuilderAppendU64(&stringBuilder, memory.used); + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("\n")); + + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("total memory wasted (in bytes): ")); + StringBuilderAppendU64(&stringBuilder, memory.total - memory.used); + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("\n")); + struct string string = StringBuilderFlush(&stringBuilder); + write(STDOUT_FILENO, string.value, string.length); } #endif @@ -490,23 +483,12 @@ main(int argc, char *argv[]) stagedOp.fd = openat(inputDirFd, (char *)stagedOp.path.value, O_RDONLY | O_NONBLOCK); if (stagedOp.fd == -1) { // warning("cannot open some event file\n"); - struct string string; - u64 length = 0; - - string = STRING_FROM_ZERO_TERMINATED("Cannot open device. event: "); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - string = stagedOp.path; - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - string = STRING_FROM_ZERO_TERMINATED("\n"); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("Cannot open device. event: ")); + StringBuilderAppendString(&stringBuilder, &stagedOp.path); + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("\n")); - debug_assert(length <= stdoutBuffer.length); - write(STDOUT_FILENO, stdoutBuffer.value, length); + struct string string = StringBuilderFlush(&stringBuilder); + write(STDOUT_FILENO, string.value, string.length); continue; } @@ -554,39 +536,18 @@ main(int argc, char *argv[]) stagedOp.triggerMinimum = triggerAbsInfo.minimum; { - struct string string; - u64 length = 0; - - string = STRING_FROM_ZERO_TERMINATED("Gamepad connected @ bus "); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - string = FormatHex(&stringBuffer, id.bustype); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - string = STRING_FROM_ZERO_TERMINATED(" vendor "); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("Gamepad connected @ bus ")); + StringBuilderAppendHex(&stringBuilder, id.bustype); - string = FormatHex(&stringBuffer, id.vendor); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED(" vendor ")); + StringBuilderAppendHex(&stringBuilder, id.vendor); - string = STRING_FROM_ZERO_TERMINATED(" product "); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED(" product ")); + StringBuilderAppendHex(&stringBuilder, id.product); - string = FormatHex(&stringBuffer, id.product); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - string = STRING_FROM_ZERO_TERMINATED("\n"); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - debug_assert(length <= stdoutBuffer.length); - write(STDOUT_FILENO, stdoutBuffer.value, length); + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("\n")); + struct string string = StringBuilderFlush(&stringBuilder); + write(STDOUT_FILENO, string.value, string.length); } stagedOp.gamepad = GamepadGetNotConnected(gamepads, maxGamepadCount); @@ -636,25 +597,15 @@ main(int argc, char *argv[]) #if GAMEPAD_IDLE_INHIBIT_DEBUG // printf("errno: %d %s\n", -error, strerror(-error)); - u64 length = 0; - struct string string; // see: /usr/include/asm-generic/errno-base.h // /usr/include/asm-generic/errno.h - string = STRING_FROM_ZERO_TERMINATED("errno: "); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - string = FormatU64(&stdoutBuffer, error); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("errno: ")); + StringBuilderAppendU64(&stringBuilder, error); + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("\n")); - string = STRING_FROM_ZERO_TERMINATED("\n"); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - debug_assert(length <= stdoutBuffer.length); - write(STDOUT_FILENO, stdoutBuffer.value, length); + struct string string = StringBuilderFlush(&stringBuilder); + write(STDOUT_FILENO, string.value, string.length); #endif error_code = GAMEPAD_ERROR_IO_URING_WAIT; @@ -845,39 +796,18 @@ main(int argc, char *argv[]) stagedOp.triggerMinimum = triggerAbsInfo.minimum; { - struct string string; - u64 length = 0; - - string = STRING_FROM_ZERO_TERMINATED("Gamepad connected @ bus "); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - string = FormatHex(&stringBuffer, id.bustype); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("Gamepad connected @ bus ")); + StringBuilderAppendHex(&stringBuilder, id.bustype); - string = STRING_FROM_ZERO_TERMINATED(" vendor "); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED(" vendor ")); + StringBuilderAppendHex(&stringBuilder, id.vendor); - string = FormatHex(&stringBuffer, id.vendor); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED(" product ")); + StringBuilderAppendHex(&stringBuilder, id.product); - string = STRING_FROM_ZERO_TERMINATED(" product "); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - string = FormatHex(&stringBuffer, id.product); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - string = STRING_FROM_ZERO_TERMINATED("\n"); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - debug_assert(length <= stdoutBuffer.length); - write(STDOUT_FILENO, stdoutBuffer.value, length); + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("\n")); + struct string string = StringBuilderFlush(&stringBuilder); + write(STDOUT_FILENO, string.value, string.length); } stagedOp.gamepad = GamepadGetNotConnected(gamepads, maxGamepadCount); @@ -1108,81 +1038,50 @@ main(int argc, char *argv[]) } } - struct string string; - u64 length = 0; - - string = STRING_FROM_ZERO_TERMINATED("Gamepad #"); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - string = FormatHex(&stringBuffer, (u64)&gamepad); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - -#define PRINT_BUTTON(prefix, button) \ - string = STRING_FROM_ZERO_TERMINATED(" " prefix ": "); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length; \ - string = FormatU64(&stringBuffer, gamepad->button); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length - -#define PRINT_ANALOG(prefix, stick, stickX, stickY) \ - string = STRING_FROM_ZERO_TERMINATED(" " prefix ": "); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length; \ - string = FormatU64(&stringBuffer, gamepad->stick); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length; \ - string = STRING_FROM_ZERO_TERMINATED(" "); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length; \ - string = FormatF32(&stringBuffer, gamepad->stickX, 2); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length; \ - string = STRING_FROM_ZERO_TERMINATED(","); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length; \ - string = FormatF32(&stringBuffer, gamepad->stickY, 2); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length - -#define PRINT_TRIGGER(prefix, trigger) \ - string = STRING_FROM_ZERO_TERMINATED(" " prefix ": "); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length; \ - string = FormatF32(&stringBuffer, gamepad->trigger, 2); \ - memcpy(stdoutBuffer.value + length, string.value, string.length); \ - length += string.length - - PRINT_BUTTON("a", a); - PRINT_BUTTON("b", b); - PRINT_BUTTON("x", x); - PRINT_BUTTON("y", y); - - PRINT_ANALOG("ls", ls, lsX, lsY); - PRINT_ANALOG("rs", rs, rsX, rsY); - - PRINT_BUTTON("lb", lb); - PRINT_TRIGGER("lt", lt); - - PRINT_BUTTON("rb", rb); - PRINT_TRIGGER("rt", rt); - - PRINT_BUTTON("home", home); - PRINT_BUTTON("back", back); - PRINT_BUTTON("start", start); - - string = STRING_FROM_ZERO_TERMINATED("\n"); - memcpy(stdoutBuffer.value + length, string.value, string.length); - length += string.length; - - debug_assert(length <= stdoutBuffer.length); - write(STDOUT_FILENO, stdoutBuffer.value, length); - -#undef PRINT_BUTTON -#undef PRINT_ANALOG -#undef PRINT_TRIGGER + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("Gamepad #")); + StringBuilderAppendHex(&stringBuilder, (u64)&gamepad); + +#define STRING_BUILDER_APPEND_BUTTON(prefix, button) \ + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED(" " prefix " ")); \ + StringBuilderAppendU64(&stringBuilder, gamepad->button) + +#define STRING_BUILDER_APPEND_ANALOG(prefix, stick, stickX, stickY) \ + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED(" " prefix " ")); \ + StringBuilderAppendU64(&stringBuilder, gamepad->stick); \ + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED(" ")); \ + StringBuilderAppendF32(&stringBuilder, gamepad->stickX, 2); \ + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED(",")); \ + StringBuilderAppendF32(&stringBuilder, gamepad->stickY, 2) + +#define STRING_BUILDER_APPEND_TRIGGER(prefix, trigger) \ + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED(" " prefix " ")); \ + StringBuilderAppendF32(&stringBuilder, gamepad->trigger, 2) + + STRING_BUILDER_APPEND_BUTTON("a", a); + STRING_BUILDER_APPEND_BUTTON("b", b); + STRING_BUILDER_APPEND_BUTTON("x", x); + STRING_BUILDER_APPEND_BUTTON("y", y); + + STRING_BUILDER_APPEND_ANALOG("ls", ls, lsX, lsY); + STRING_BUILDER_APPEND_ANALOG("rs", rs, rsX, rsY); + + STRING_BUILDER_APPEND_BUTTON("lb", lb); + STRING_BUILDER_APPEND_TRIGGER("lt", lt); + + STRING_BUILDER_APPEND_BUTTON("rb", rb); + STRING_BUILDER_APPEND_TRIGGER("rt", rt); + + STRING_BUILDER_APPEND_BUTTON("home", home); + STRING_BUILDER_APPEND_BUTTON("back", back); + STRING_BUILDER_APPEND_BUTTON("start", start); + +#undef STRING_BUILDER_APPEND_ANALOG +#undef STRING_BUILDER_APPEND_TRIGGER +#undef STRING_BUILDER_APPEND_BUTTON + + StringBuilderAppendString(&stringBuilder, &STRING_FROM_ZERO_TERMINATED("\n")); + struct string string = StringBuilderFlush(&stringBuilder); + write(STDOUT_FILENO, string.value, string.length); } // DEBUG: get file path from file descriptor