Coding Style
AXL Coding Style
AXL follows GLib naming conventions. All new code uses this style — no exceptions, no EDK2-style PascalCase functions.
Naming
Element |
Convention |
Example |
GLib equivalent |
|---|---|---|---|
Functions |
|
|
|
Types |
|
|
|
Macros/constants |
|
|
|
Enum values |
|
|
|
Struct members |
|
|
|
Local variables |
|
|
|
Parameters |
|
|
|
Static/file scope |
|
|
Types — Standard C Only in Public API
Public headers (axl/*.h) use standard C types exclusively:
Use |
Not |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
— |
Include <stddef.h> for size_t, <stdbool.h> for bool,
<stdint.h> for fixed-width types. These are freestanding headers
provided by GCC even with -ffreestanding.
No <Uefi.h> in public headers. Public headers (axl/*.h) must
not include <Uefi.h>. Use freestanding headers only (<stddef.h>,
<stdint.h>, <stdbool.h>, <stdarg.h>).
_impl declarations use UEFI types but are isolated in
axl-mem-impl.h (included at the bottom of axl-mem.h).
Consumers never call _impl functions directly — they use macros.
Implementation files (.c) may use UEFI types internally.
UCS-2 interop: Functions that bridge to UEFI’s UCS-2 strings
(e.g. axl_utf8_to_ucs2) use unsigned short * in their
signatures — equivalent to UEFI’s CHAR16 without the dependency.
Strings — UTF-8 Everywhere
All strings in the AXL public API are char * (UTF-8). No CHAR16,
no wchar_t, no wide strings. This matches GLib’s convention.
All axl_str* functions (without _w suffix) operate on UTF-8
strings. Since UTF-8 is a superset of ASCII, these functions work
correctly for comparison, searching, copying, and splitting.
Case-insensitive operations (axl_strcasecmp, axl_strcasestr)
fold ASCII letters only — they do not handle full Unicode case
mapping (same as GLib’s g_ascii_strcasecmp).
UCS-2 (unsigned short *) functions have a _w suffix and are
for UEFI internal use. Consumer code should use UTF-8 and convert
at boundaries with axl_utf8_to_ucs2 / axl_ucs2_to_utf8.
UEFI uses UCS-2 (CHAR16 *) for file paths and console output.
AXL converts internally when calling UEFI APIs. The conversion
functions are exposed for code that needs direct UEFI protocol
interop (e.g., drivers using <uefi/axl-uefi.h>).
File Naming
Element |
Convention |
Example |
|---|---|---|
Source files |
|
|
Public headers |
|
|
Internal headers |
|
|
Umbrella header |
|
|
Test files |
|
|
Directories |
lowercase |
|
Source files and headers use lowercase hyphenated names.
Internal headers live next to their implementation (e.g.,
src/backend/axl-backend.h), not in include/.
Formatting
Rule |
Convention |
Example |
|---|---|---|
Indent |
4 spaces, no tabs |
|
Line length |
80-120 characters |
|
Braces (control flow) |
K&R, opening on same line |
|
Braces (functions) |
Opening brace on its own line |
see example below |
Braces (single stmt) |
Always use braces |
|
Return type |
Separate line from function name |
|
Pointer style |
Star with variable |
|
Parens |
No space before parens (calls, declarations, macros) |
|
Comments |
|
|
Header guards |
|
|
NULL checks |
Explicit: |
Not |
Bool checks |
Implicit: |
Not |
Result checks |
Explicit: |
Not |
Strings |
|
Not |
Empty lines |
Allowed, no trailing whitespace |
Return Value Conventions
Two patterns, used consistently:
Pattern |
Return type |
Success |
Failure |
Example |
|---|---|---|---|---|
Operations |
|
|
|
|
Predicates |
|
|
|
|
Operations (set, parse, open, write, etc.) return int. Check with
!= AXL_OK, never with ! or truthiness:
if (axl_file_get_contents(path, &buf, &len) != AXL_OK) {
// error
}
Predicates (is_X, has_X, dir_read iterator) return bool. Check
with truthiness:
while (axl_dir_read(dir, &entry)) {
// process entry
}
Functions returning pointers follow the pointer convention: NULL on
error, non-NULL on success.
Critical int-returning functions are marked AXL_WARN_UNUSED in the
header to catch unchecked returns at compile time.
Event Loop Callback Convention
Callback return values control the source, not the loop:
return AXL_SOURCE_CONTINUE; // keep this source active
return AXL_SOURCE_REMOVE; // remove this source (loop continues)
To quit the loop, call axl_loop_quit(loop) explicitly — typically
passed via the callback’s data parameter:
static bool
on_timer(void *data)
{
AxlLoop *loop = (AxlLoop *)data;
if (done) {
axl_loop_quit(loop);
return AXL_SOURCE_REMOVE;
}
return AXL_SOURCE_CONTINUE;
}
axl_loop_add_timer(loop, 1000, on_timer, loop);
This matches GLib’s G_SOURCE_CONTINUE / G_SOURCE_REMOVE convention.
Example
int
axl_do_something(AxlHashTable *table, const char *key)
{
if (key == NULL) {
return -1;
}
char *val = axl_hash_table_lookup(table, key);
if (val == NULL) {
axl_eprintf("key not found: %s\n", key);
return -1;
}
/* Process value */
axl_printf("found: %s = %s\n", key, val);
return 0;
}
Printf and Variadic Functions
AXL has its own lightweight printf engine (axl_vformat) that uses
standard C va_arg. It does NOT use EDK2’s PrintLib, so variadic
functions need no special calling convention annotation.
Format specifiers follow standard C printf — %s for char *,
%d for int, %lu for unsigned long, %zu for size_t, etc.
Use __attribute__((format(printf, N, M))) for compile-time checking:
void
axl_string_append_printf(AxlString *b, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
char *
axl_asprintf(const char *fmt, ...)
__attribute__((format(printf, 1, 2)));
Documentation (Doxygen)
Inline parameter docs using Doxygen trailing comments (///<).
Parameters are column-aligned in the signature with docs beside them.
The block comment above has the function description and return value.
/**
* @brief Create a new hash table with string keys.
*
* @return new AxlHashTable, or NULL on allocation failure.
* Free with axl_hash_table_free().
*/
AxlHashTable *
axl_hash_table_new(void);
/**
* @brief Insert or replace a key-value pair.
*/
void
axl_hash_table_insert(
AxlHashTable *h, ///< hash table
const char *key, ///< string key (copied internally)
void *val ///< value pointer (not copied, not freed on removal)
);
/**
* @brief Look up a key.
*
* @return value pointer, or NULL if not found.
*/
void *
axl_hash_table_lookup(
AxlHashTable *h, ///< hash table
const char *key ///< key to look up
);
For simple functions with 0-1 parameters, keep the signature on one line:
/**
* @brief Free a hash table. Keys freed; values NOT freed.
*/
void
axl_hash_table_free(AxlHashTable *h); ///< hash table (NULL-safe)
Dogfooding
AXL’s own internals use the AXL API:
Allocate with
axl_malloc/axl_calloc/axl_freeReport errors with
axl_printerrBuild strings with
axl_stringUse
axl_strlcpy/axl_strlcatfor bounded copies
Exception: code that runs before axl_io_init() (e.g. very early
allocator errors) may use EDK2 primitives as a fallback.