# Conventions and Preferences ## Language - **C11** throughout (`-std=c11`) - **`_GNU_SOURCE`** defined via `-D_GNU_SOURCE` in all Makefiles — enables the full GNU/Linux feature set (POSIX 2008, BSD, GNU and Linux-specific extensions); do not define this in source files - **LTO enabled** via `-flto` in all Makefiles — the compiler handles inlining across translation units at link time; do not use `static` on functions solely to enable inlining - Target platform: Linux (V4L2, epoll, etc. are Linux-specific) --- ## Naming | Kind | Convention | Example | |---|---|---| | Structs | `Title_Snek_Case` | `struct App_Error`, `struct Frame_Header` | | Enums (type) | `Title_Snek_Case` | `enum Error_Code` | | Enum values | `CAPITAL_SNEK_CASE` | `ERR_NONE`, `ERR_SYSCALL` | | Functions | `lower_snek_case` | `v4l2_ctrl_open()`, `app_error_print()` | | Local variables | `lower_snek_case` | `frame_count`, `device_fd` | | Constants (`#define`, `const`) | `CAPITAL_SNEK_CASE` | `MAX_FRAME_SIZE` | | Module-level singletons | `lower_snek_case` | (treated as functions) | Identifiers are prefixed with their module name where disambiguation is needed (e.g. `v4l2_ctrl_`, `media_ctrl_`, `transport_`). --- ## Types ### No typedefs for structs Always use the `struct` keyword at the call site. This makes composite types unambiguous without inspecting declarations. ```c /* correct */ struct App_Error err = app_error_ok(); void process(struct Frame_Header *header); /* wrong */ typedef struct { ... } App_Error; ``` ### typedefs are acceptable for - Enums: `typedef enum Error_Code { ... } Error_Code;` — allows using the name without `enum` keyword - Scalar aliases where the underlying type is genuinely irrelevant to the caller (e.g. `typedef uint32_t Frame_Id;`) --- ## Formatting - **Indentation**: tabs (display width 4) - **Braces**: always use block braces, including single-statement bodies ```c /* correct */ if (err.code != ERR_NONE) { return err; } /* wrong */ if (err.code != ERR_NONE) return err; ``` - **Quotes**: double quotes for string literals (C standard) --- ## Error Handling Errors are returned as `struct App_Error` values. Functions that can fail return `struct App_Error` directly, or take an out-parameter for the result alongside it. ### Structure ```c /* modules/common/error.h */ typedef enum Error_Code { ERR_NONE = 0, ERR_SYSCALL = 1, /* errno is meaningful */ ERR_INVALID = 2, } Error_Code; struct Syscall_Error_Detail { int err_no; }; struct Invalid_Error_Detail { /* fields added as concrete cases arise */ }; struct App_Error { Error_Code code; const char *file; /* __FILE__ — future: replaced by generated location code */ int line; /* __LINE__ — future: replaced by generated location code */ union { struct Syscall_Error_Detail syscall; struct Invalid_Error_Detail invalid; } detail; }; ``` ### Macros ```c #define APP_OK \ ((struct App_Error){ .code = ERR_NONE }) #define APP_IS_OK(e) \ ((e).code == ERR_NONE) #define APP_ERROR(error_code, detail_field, ...) \ ((struct App_Error){ \ .code = (error_code), \ .file = __FILE__, \ .line = __LINE__, \ .detail = { .detail_field = { __VA_ARGS__ } } \ }) #define APP_SYSCALL_ERROR() \ APP_ERROR(ERR_SYSCALL, syscall, .err_no = errno) ``` ### Presentation Each error kind is handled in `app_error_print()`, which writes a human-readable description to stderr. A JSON writer (`app_error_write_json()`) will be added later and will use the same structured fields. ### Future upgrade When the custom preprocessor is available, `__FILE__` and `__LINE__` will be replaced by a generated numeric location code that uniquely identifies the error site in the project. JSON consumers will see the same struct shape either way. --- ## Directory Structure ``` video-setup/ src/ - all C source files modules/ - translation units; each has a .c and a Makefile common/ - shared types (error, base definitions); no external dependencies / node/ - video node entry point and integration (later) include/ - public headers (.h files) dev/ - development aids; not part of the final deliverable cli/ - exploratory CLI drivers, one per module experiments/ - freeform experiments tests/ - automated tests (later) Makefile - top-level build ``` Source files live in `src/`. Public headers live in `include/`. CLI drivers and experiments live in `dev/`. Nothing in `dev/` is a dependency of anything in `src/`. --- ## Module Structure Each module has its source under `src/modules//` and its public header under `include/`: ``` src/modules// .c - implementation Makefile - builds a static object include/ .h - public API; minimal includes, no implementation details ``` The corresponding CLI driver lives at `dev/cli/_cli.c`. --- ## Build - **GNU make** with tabs for recipe indentation - Each module builds to a static object (`.o`) - CLI drivers link the module object(s) they need - No CDN or vendored sources; dependencies are system libraries (libc, Linux kernel headers)