Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
440 changes: 440 additions & 0 deletions Bin/CalC.c

Large diffs are not rendered by default.

14 changes: 3 additions & 11 deletions Conventions/CODING-CONVENTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,8 @@ of the codebase to see them in action.
shouldn't be — adjusting state has invariants the mutators enforce.
Intentional-corruption tests that need to bypass an invariant (to
verify that a validator catches it) write the field directly, with
an inline comment opening with the canonical phrase
`// intentional bypass:` followed by *why* no public accessor /
mutator covers the case. The phrase is grep-able; a stray field
write without it is a review finding. See
`Tests/Std/Allocator.Heap.c`, `Tests/Std/BitVec.Convert.c`,
`Tests/Std/Graph.Init.c`, and the other `Tests/Std/*` Deadend
fixtures for the established shape.
an inline comment explaining why no public accessor or mutator
covers the case.
- **Container key types ship `*_hash` and `*_compare`.** Any type
meant to be a `Map` key (or `Vec`/`List` element with comparison
semantics) must expose two snake_case helpers in the
Expand Down Expand Up @@ -675,10 +670,7 @@ up-cast.
exercise the validators by violating an invariant — bypassing
capacity bookkeeping, scrambling a magic value, overrunning a buffer.
These tests write fields directly because that's the whole point of
the test; open each such site with the canonical
`// intentional bypass:` comment (same phrase used by the
non-Deadend tests in *Accessor macros are read-only* above) so it
stays grep-able and doesn't get swept on the next pass.
the test.
- **Fixture-local owned storage** (e.g. `Vec.Complex.c`'s `char *name`
/ `int *values` inside a `ComplexItem` that exercises
`VecInitWithDeepCopy` callbacks) is fine as raw pointers because the
Expand Down
747 changes: 747 additions & 0 deletions Include/Misra/ParserCombinator.h

Large diffs are not rendered by default.

17 changes: 13 additions & 4 deletions Include/Misra/Parsers/Elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,18 @@ typedef struct Elf {
///
/// Open and parse an ELF file from disk.
///
/// out[out] : Populated on success.
/// path[in] : Filesystem path. Prefer `Str *`; `Zstr` (NUL-terminated) accepted.
/// alloc[in] : Allocator for the read-in byte buffer and the section /
/// symbol vectors. Must outlive the `Elf`.
/// Call shapes via `OVERLOAD` + `_Generic` on `path`:
/// `ElfOpen(out, path)` -- `path` is `Str *` or `Zstr`.
/// `ElfOpen(out, path, alloc)` -- same, explicit allocator.
/// `ElfOpen(out, path, path_len, alloc)`-- `path` is a fixed-length view
/// (`Zstr`, `size`); copied into a
/// stack buffer for the syscall.
///
/// out[out] : Populated on success.
/// path[in] : Filesystem path. Prefer `Str *`; `Zstr` (NUL-terminated) accepted.
/// path_len[in] : Length of `path` for the fixed-length form.
/// alloc[in] : Allocator for the read-in byte buffer and the section /
/// symbol vectors. Must outlive the `Elf`.
///
/// SUCCESS : Returns true; `out` owns the read-in buffer and will free
/// it on `ElfDeinit`.
Expand All @@ -270,6 +278,7 @@ typedef struct Elf {
Zstr: elf_open((out), (Zstr)(path), ALLOCATOR_OF(alloc)), \
char *: elf_open((out), (Zstr)(path), ALLOCATOR_OF(alloc)) \
)
#define ElfOpen_4(out, path, len, alloc) elf_open_n((out), (Zstr)(path), (len), ALLOCATOR_OF(alloc))

///
/// Parse an ELF object from an in-memory byte range -- **L-value /
Expand Down
13 changes: 7 additions & 6 deletions Include/Misra/Parsers/Elf/Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@
extern "C" {
#endif

typedef struct Elf Elf;
typedef struct ElfSection ElfSection;
typedef struct Elf Elf;
typedef struct ElfSection ElfSection;

bool elf_open(Elf *out, Zstr path, Allocator *alloc);
bool elf_open_from_memory_copy(Elf *out, const u8 *data, size data_size, Allocator *alloc);
const ElfSection *elf_find_section_zstr(const Elf *self, Zstr name);
const ElfSection *elf_find_section_str(const Elf *self, const Str *name);
bool elf_open(Elf *out, Zstr path, Allocator *alloc);
bool elf_open_n(Elf *out, Zstr path, size len, Allocator *alloc);
bool elf_open_from_memory_copy(Elf *out, const u8 *data, size data_size, Allocator *alloc);
const ElfSection *elf_find_section_zstr(const Elf *self, Zstr name);
const ElfSection *elf_find_section_str(const Elf *self, const Str *name);

#ifdef __cplusplus
}
Expand Down
37 changes: 31 additions & 6 deletions Include/Misra/Parsers/Http.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,16 @@ void HttpHeaderDeinit(HttpHeader *header);
/// TAGS: Http, Deinit, Header, Init
///
///
/// Find a header by key (case-sensitive zero-terminated comparison).
/// Find a header by key (case-sensitive comparison).
///
/// Two call shapes via `OVERLOAD` + `_Generic` on `key`:
/// `HttpHeadersFind(headers, key)` -- `key` is `Str *` / `Zstr`.
/// `HttpHeadersFind(headers, key, key_len)` -- `key` is a counted view
/// (`Zstr`, `size`).
///
/// headers[in] : Caller's `Vec(HttpHeader)` to search.
/// key[in] : Key to look up.
/// key_len[in] : Length of `key` for the 3-arg counted form.
///
/// SUCCESS : Returns a pointer to the matching header inside the
/// vector. The pointer is valid until `*headers` is mutated
Expand All @@ -95,11 +101,14 @@ void HttpHeaderDeinit(HttpHeader *header);
///
HttpHeader *http_headers_find_zstr(HttpHeaders *headers, Zstr key);
HttpHeader *http_headers_find_str(HttpHeaders *headers, const Str *key);
#define HttpHeadersFind(headers, key) \
HttpHeader *http_headers_find_cstr(HttpHeaders *headers, Zstr key, size key_len);
#define HttpHeadersFind(...) OVERLOAD(HttpHeadersFind, __VA_ARGS__)
#define HttpHeadersFind_2(headers, key) \
_Generic((key), Str *: http_headers_find_str, Zstr: http_headers_find_zstr, char *: http_headers_find_zstr)( \
(headers), \
(key) \
)
#define HttpHeadersFind_3(headers, key, key_len) http_headers_find_cstr((headers), (Zstr)(key), (key_len))

typedef enum HttpResponseCode {
HTTP_RESPONSE_CODE_INVALID = 0,
Expand Down Expand Up @@ -254,19 +263,26 @@ typedef struct HttpRequest {
/// be initialized with `HttpRequestInit(...)` so the parser has an
/// allocator to write into.
///
/// Two call shapes via `OVERLOAD` + `_Generic` on `in`:
/// `HttpRequestParse(req, in)` -- `in` is `Str *` / `Zstr`.
/// `HttpRequestParse(req, in, in_len)` -- `in` is a counted view
/// (`Zstr`, `size`).
///
/// SUCCESS : Returns a pointer past the parsed request line + headers
/// (start of the body).
/// (start of the body), pointing into the caller's `in`.
/// FAILURE : Returns `in` unchanged when the input is malformed.
///
/// TAGS: Http, Parse, Request
///
#define HttpRequestParse(req, in) \
#define HttpRequestParse(...) OVERLOAD(HttpRequestParse, __VA_ARGS__)
#define HttpRequestParse_2(req, in) \
_Generic( \
(in), \
Str *: http_request_parse_str((req), (const Str *)(in)), \
Zstr: http_request_parse_zstr((req), (Zstr)(in)), \
char *: http_request_parse_zstr((req), (Zstr)(in)) \
)
#define HttpRequestParse_3(req, in, in_len) http_request_parse_cstr((req), (Zstr)(in), (in_len))

///
/// Release storage owned by `req` and zero the struct. Safe to call on
Expand Down Expand Up @@ -312,7 +328,7 @@ typedef struct HttpResponse {
((HttpResponse) {.allocator = ALLOCATOR_OF(alloc_ptr), \
.content_type = HTTP_CONTENT_TYPE_INVALID, \
.status_code = HTTP_RESPONSE_CODE_INVALID, \
.headers = VecInitWithDeepCopy_3(NULL, http_header_deinit, alloc_ptr), \
.headers = VecInitWithDeepCopy_3(NULL, http_header_deinit, alloc_ptr), \
.body = StrInit_1(alloc_ptr)})

///
Expand Down Expand Up @@ -347,18 +363,27 @@ HttpResponse *HttpRespondWithHtml(HttpResponse *response, HttpResponseCode statu
/// through `response->allocator`. Only available when the `file`
/// feature is enabled.
///
/// Two call shapes via `OVERLOAD` + `_Generic` on `filepath`:
/// `HttpRespondWithFile(response, status, content_type, filepath)`
/// -- `filepath` is `Str *` / `Zstr`.
/// `HttpRespondWithFile(response, status, content_type, filepath, filepath_len)`
/// -- `filepath` is a counted view (`Zstr`, `size`).
///
/// SUCCESS : Returns `response` with body filled.
/// FAILURE : Returns NULL on I/O or allocation failure.
///
/// TAGS: Http, Respond, File
///
# define HttpRespondWithFile(response, status, content_type, filepath) \
# define HttpRespondWithFile(...) OVERLOAD(HttpRespondWithFile, __VA_ARGS__)
# define HttpRespondWithFile_4(response, status, content_type, filepath) \
_Generic( \
(filepath), \
Str *: http_respond_with_file_str((response), (status), (content_type), (const Str *)(filepath)), \
Zstr: http_respond_with_file_zstr((response), (status), (content_type), (Zstr)(filepath)), \
char *: http_respond_with_file_zstr((response), (status), (content_type), (Zstr)(filepath)) \
)
# define HttpRespondWithFile_5(response, status, content_type, filepath, filepath_len) \
http_respond_with_file_cstr((response), (status), (content_type), (Zstr)(filepath), (filepath_len))
#endif

///
Expand Down
50 changes: 29 additions & 21 deletions Include/Misra/Parsers/Http/Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,38 @@
extern "C" {
#endif

typedef struct HttpRequest HttpRequest;
typedef struct HttpResponse HttpResponse;
typedef enum HttpResponseCode HttpResponseCode;
typedef enum HttpContentType HttpContentType;
typedef struct HttpRequest HttpRequest;
typedef struct HttpResponse HttpResponse;
typedef enum HttpResponseCode HttpResponseCode;
typedef enum HttpContentType HttpContentType;

void http_header_deinit(void *header, const Allocator *alloc);
bool http_header_init_copy(void *dst, const void *src, const Allocator *alloc);
Zstr http_request_parse_zstr(HttpRequest *req, Zstr in);
Zstr http_request_parse_str(HttpRequest *req, const Str *in);
void http_header_deinit(void *header, const Allocator *alloc);
bool http_header_init_copy(void *dst, const void *src, const Allocator *alloc);
Zstr http_request_parse_zstr(HttpRequest *req, Zstr in);
Zstr http_request_parse_str(HttpRequest *req, const Str *in);
Zstr http_request_parse_cstr(HttpRequest *req, Zstr in, size in_len);
#if FEATURE_FILE
HttpResponse *http_respond_with_file_zstr(
HttpResponse *response,
HttpResponseCode status,
HttpContentType content_type,
Zstr filepath
);
HttpResponse *http_respond_with_file_str(
HttpResponse *response,
HttpResponseCode status,
HttpContentType content_type,
const Str *filepath
);
HttpResponse *http_respond_with_file_zstr(
HttpResponse *response,
HttpResponseCode status,
HttpContentType content_type,
Zstr filepath
);
HttpResponse *http_respond_with_file_str(
HttpResponse *response,
HttpResponseCode status,
HttpContentType content_type,
const Str *filepath
);
HttpResponse *http_respond_with_file_cstr(
HttpResponse *response,
HttpResponseCode status,
HttpContentType content_type,
Zstr filepath,
size filepath_len
);
#endif
Str http_response_serialize(const HttpResponse *response, Allocator *alloc);
Str http_response_serialize(const HttpResponse *response, Allocator *alloc);

#ifdef __cplusplus
}
Expand Down
24 changes: 18 additions & 6 deletions Include/Misra/Parsers/KvConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,10 @@ StrIter KvConfigParse(StrIter si, KvConfig *cfg);
///
/// TAGS: KvConfig, Get, API
///
#define KvConfigGet(cfg, key) \
#define KvConfigGet(...) OVERLOAD(KvConfigGet, __VA_ARGS__)
#define KvConfigGet_2(cfg, key) \
_Generic((key), Str *: kvconfig_get_str, Zstr: kvconfig_get_zstr, char *: kvconfig_get_zstr)((cfg), (key))
#define KvConfigGet_3(cfg, key, key_len) kvconfig_get_cstr((cfg), (Zstr)(key), (key_len))

///
/// Get stored value for `key` by internal reference.
Expand All @@ -230,11 +232,13 @@ StrIter KvConfigParse(StrIter si, KvConfig *cfg);
///
/// TAGS: KvConfig, Get, Pointer
///
#define KvConfigGetPtr(cfg, key) \
#define KvConfigGetPtr(...) OVERLOAD(KvConfigGetPtr, __VA_ARGS__)
#define KvConfigGetPtr_2(cfg, key) \
_Generic((key), Str *: kvconfig_get_ptr_str, Zstr: kvconfig_get_ptr_zstr, char *: kvconfig_get_ptr_zstr)( \
(cfg), \
(key) \
)
#define KvConfigGetPtr_3(cfg, key, key_len) kvconfig_get_ptr_cstr((cfg), (Zstr)(key), (key_len))

///
/// Check whether a key exists in config.
Expand All @@ -247,11 +251,13 @@ StrIter KvConfigParse(StrIter si, KvConfig *cfg);
///
/// TAGS: KvConfig, Contains, API
///
#define KvConfigContains(cfg, key) \
#define KvConfigContains(...) OVERLOAD(KvConfigContains, __VA_ARGS__)
#define KvConfigContains_2(cfg, key) \
_Generic((key), Str *: kvconfig_contains_str, Zstr: kvconfig_contains_zstr, char *: kvconfig_contains_zstr)( \
(cfg), \
(key) \
)
#define KvConfigContains_3(cfg, key, key_len) kvconfig_contains_cstr((cfg), (Zstr)(key), (key_len))

///
/// Parse and fetch a boolean config value.
Expand All @@ -267,12 +273,14 @@ StrIter KvConfigParse(StrIter si, KvConfig *cfg);
///
/// TAGS: KvConfig, Get, Bool
///
#define KvConfigGetBool(cfg, key, value) \
#define KvConfigGetBool(...) OVERLOAD(KvConfigGetBool, __VA_ARGS__)
#define KvConfigGetBool_3(cfg, key, value) \
_Generic((key), Str *: kvconfig_get_bool_str, Zstr: kvconfig_get_bool_zstr, char *: kvconfig_get_bool_zstr)( \
(cfg), \
(key), \
(value) \
)
#define KvConfigGetBool_4(cfg, key, key_len, value) kvconfig_get_bool_cstr((cfg), (Zstr)(key), (key_len), (value))

///
/// Parse and fetch a signed 64-bit integer config value.
Expand All @@ -286,12 +294,14 @@ StrIter KvConfigParse(StrIter si, KvConfig *cfg);
///
/// TAGS: KvConfig, Get, I64
///
#define KvConfigGetI64(cfg, key, value) \
#define KvConfigGetI64(...) OVERLOAD(KvConfigGetI64, __VA_ARGS__)
#define KvConfigGetI64_3(cfg, key, value) \
_Generic((key), Str *: kvconfig_get_i64_str, Zstr: kvconfig_get_i64_zstr, char *: kvconfig_get_i64_zstr)( \
(cfg), \
(key), \
(value) \
)
#define KvConfigGetI64_4(cfg, key, key_len, value) kvconfig_get_i64_cstr((cfg), (Zstr)(key), (key_len), (value))

///
/// Parse and fetch a double-precision floating config value.
Expand All @@ -305,12 +315,14 @@ StrIter KvConfigParse(StrIter si, KvConfig *cfg);
///
/// TAGS: KvConfig, Get, F64
///
#define KvConfigGetF64(cfg, key, value) \
#define KvConfigGetF64(...) OVERLOAD(KvConfigGetF64, __VA_ARGS__)
#define KvConfigGetF64_3(cfg, key, value) \
_Generic((key), Str *: kvconfig_get_f64_str, Zstr: kvconfig_get_f64_zstr, char *: kvconfig_get_f64_zstr)( \
(cfg), \
(key), \
(value) \
)
#define KvConfigGetF64_4(cfg, key, key_len, value) kvconfig_get_f64_cstr((cfg), (Zstr)(key), (key_len), (value))

// Snake_case backends live in <Misra/Parsers/KvConfig/Private.h>, pulled
// in from the top of this file so the _Generic dispatch arms above can
Expand Down
Loading
Loading