{"id":30853567,"url":"https://github.com/sanko/infix","last_synced_at":"2026-02-15T00:17:52.179Z","repository":{"id":305384975,"uuid":"1022715336","full_name":"sanko/Infix","owner":"sanko","description":"JIT-based FFI","archived":false,"fork":false,"pushed_at":"2025-09-04T04:37:27.000Z","size":1078,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-04T04:39:54.448Z","etag":null,"topics":["aarch64","c17","experiment","ffi","foreign-function-interface","interoperability","jit","native","trampoline","x86-64"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"artistic-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sanko.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE-A2","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"sanko"}},"created_at":"2025-07-19T17:06:23.000Z","updated_at":"2025-09-04T04:37:31.000Z","dependencies_parsed_at":"2025-07-19T21:48:24.382Z","dependency_job_id":"151e343c-3da6-46f7-99a4-4b29d1f838c3","html_url":"https://github.com/sanko/Infix","commit_stats":null,"previous_names":["sanko/infix"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sanko/Infix","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sanko%2FInfix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sanko%2FInfix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sanko%2FInfix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sanko%2FInfix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sanko","download_url":"https://codeload.github.com/sanko/Infix/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sanko%2FInfix/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274021054,"owners_count":25208729,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-07T02:00:09.463Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aarch64","c17","experiment","ffi","foreign-function-interface","interoperability","jit","native","trampoline","x86-64"],"created_at":"2025-09-07T09:36:08.848Z","updated_at":"2026-02-07T05:06:27.276Z","avatar_url":"https://github.com/sanko.png","language":"C","funding_links":["https://github.com/sponsors/sanko"],"categories":[],"sub_categories":[],"readme":"# infix: A Lightweight FFI Code Generation Library for C\n\n**infix** is a minimal, dependency-free, Just-in-Time (JIT) powered Foreign Function Interface (FFI) library for modern C. It allows you to dynamically create function calls and callbacks at runtime by generating machine code on the fly.\n\nThe entire project is written from scratch in C17 and serves as a practical example of how low-level code generation, ABI-specific logic, and memory management work together.\n\n### Features\n\n*   **Convenient String-Based API**: Define complex C function signatures, including packed structs and function pointers, using a simple, human-readable string.\n*   **Forward Calls:** Dynamically generate and call any C function pointer, even for functions with complex signatures and variadic arguments.\n*   **Reverse Calls (Callbacks):** Generate native, callable C function pointers that wrap a custom handler function. The callback mechanism is **thread-safe**, re-entrant, and supports variadic function signatures.\n*   **Cross-Platform \u0026 Cross-Compiler ABI Support:** Correctly handles calling conventions across multiple platforms and compilers:\n    *   **x86-64:** System V (Linux, macOS, BSD) and Windows x64 (MSVC, GCC, and Clang).\n    *   **ARM64 (AArch64):** AAPCS64 (Linux, macOS, Windows, BSD), including correct handling of Apple-specific variadic rules.\n*   **Rich Type System:** Supports a comprehensive set of C types, including primitives, pointers, structs, unions, and fixed-size arrays.\n*   **Performance Optimized:** The one-time cost of trampoline generation is significantly accelerated by an internal arena allocator, which replaces thousands of small `malloc` calls with simple pointer bumps.\n*   **Secure by Design:** Adheres to strict security principles, validated through extensive testing:\n    *   **W^X (Write XOR Execute):** Enforces that memory is never writable and executable at the same time.\n    *   **Overflow Hardened:** The type system is protected against integer overflows from malformed or malicious user input.\n    *   **Use-After-Free Protection:** Freed trampolines are converted into guard pages, ensuring calls to dangling pointers result in a safe, immediate crash.\n    *   **Read-Only Contexts:** Callback context data is made read-only after creation to protect against runtime memory corruption attacks.\n*   **Simple Integration**: Add `infix.h` to your includes and compile with your project to get started.\n\n## API Quick Reference\n\ninfix provides two API layers: a convenient high-level Signature API and a powerful low-level Core API.\n\n#### 1. The Signature API\n\nThis API uses simple strings to define function signatures, making it easy to use and read.\n\n```c\n#include \u003cinfix.h\u003e\n\n// Generate a forward trampoline for `int add(int, int)`\nffi_trampoline_t* t;\nffi_create_forward_trampoline_from_signature(\u0026t, \"ii =\u003e i\");\n\n// Generate a reverse trampoline (callback) for `void handler(char*)`\nffi_reverse_trampoline_t* rt;\nffi_create_reverse_trampoline_from_signature(\u0026rt, \"c* =\u003e v\", my_handler, NULL);\n```\n\n#### 2. The Core API (Recommended for Advanced Control)\n\nThis API gives you fine-grained control by requiring you to build type descriptions manually. It's more verbose but powerful for programmatically constructing types.\n\n```c\n#include \u003cinfix.h\u003e\n\n// Describe the signature `int(int, int)` manually\nffi_type* ret_type = ffi_type_create_primitive(FFI_PRIMITIVE_TYPE_SINT32);\nffi_type* arg_types[] = { ffi_type_create_primitive(FFI_PRIMITIVE_TYPE_SINT32),\n                          ffi_type_create_primitive(FFI_PRIMITIVE_TYPE_SINT32) };\n\n// Generate the trampoline\nffi_trampoline_t* t;\ngenerate_forward_trampoline(\u0026t, ret_type, arg_types, 2, 2);\n```\n\n## Getting Started Example\n\nThis example uses the **Signature API** to call the standard C `printf` function.\n\n```c\n#include \u003cinfix.h\u003e\n#include \u003cstdio.h\u003e\n\nint main(void) {\n    // 1. Describe the function signature as a string.\n    // Signature: int printf(const char* format, ...);\n    // We will call it with an int and a double.\n    // 'c*' = const char*, '.' = variadic separator, 'i' = int, 'd' = double\n    const char* signature = \"c*.id =\u003e i\";\n\n    // 2. Generate the trampoline from the signature.\n    ffi_trampoline_t* trampoline = NULL;\n    ffi_status status = ffi_create_forward_trampoline_from_signature(\u0026trampoline, signature);\n    if (status != FFI_SUCCESS) return 1;\n\n    // 3. Prepare the arguments.\n    const char* format_str = \"Hello! The number is %d and the double is %.2f\\n\";\n    int my_int = 42;\n    double my_double = 3.14;\n    void* args[] = { \u0026format_str, \u0026my_int, \u0026my_double };\n\n    // 4. Get the callable function pointer and invoke it.\n    ffi_cif_func cif_func = (ffi_cif_func)ffi_trampoline_get_code(trampoline);\n    int printf_ret = 0;\n    cif_func((void*)printf, \u0026printf_ret, args);\n\n    printf(\"printf returned: %d\\n\", printf_ret);\n\n    // 5. Clean up.\n    ffi_trampoline_free(trampoline);\n    return 0;\n}\n```\n\n## Signature Language Reference\n\nThe signature string is a powerful mini-language for describing C types. The format is `arg1_type arg2_type ... =\u003e return_type`.\n\n### Primitives\n\n| Code | C Type                 |\n| :--- | :--------------------- |\n| `v`  | `void`                 |\n| `b`  | `bool`                 |\n| `a`  | `signed char`          |\n| `c`  | `char`                 |\n| `h`  | `unsigned char`        |\n| `s`  | `short`                |\n| `t`  | `unsigned short`       |\n| `i`  | `int`                  |\n| `j`  | `unsigned int`         |\n| `l`  | `long`                 |\n| `m`  | `unsigned long`        |\n| `x`  | `long long`            |\n| `y`  | `unsigned long long`   |\n| `n`  | `__int128_t`           |\n| `o`  | `__uint128_t`          |\n| `f`  | `float`                |\n| `d`  | `double`               |\n| `e`  | `long double`          |\n\n### Composites\n\n| Syntax                                     | C Equivalent                                     |\n| ------------------------------------------ | ------------------------------------------------ |\n| `T*`                                       | `T*` (e.g., `i*` is `int*`)                     |\n| `T**`                                      | `T**` (e.g., `c**` is `char**`)                 |\n| `T[N]`                                     | `T[N]` (e.g., `f[16]` is `float[16]`)           |\n| `{member1;member2}`                        | `struct { T1 member1; T2 member2; }`             |\n| `\u003cmember1;member2\u003e`                        | `union { T1 member1; T2 member2; }`              |\n| `p(size,align){type1:off1;...}`             | A packed struct with explicit layout             |\n| `(args...=\u003eret)`                           | A function pointer, e.g., `(i=\u003ev)` for `void (*)(int)` |\n\n### Delimiters\n\n| Delimiter | Purpose                                                     |\n| :-------- | :---------------------------------------------------------- |\n| `=\u003e`      | **Required.** Separates arguments from the return type.     |\n| `.`       | **Optional.** Separates fixed arguments from variadic ones. |\n| `;`       | **Required.** Separates members inside `{...}` and `\u003c...\u003e` lists. |\n| `:`       | **Required.** Separates type from offset in packed structs. |\n\n### Examples\n\n| Signature String                 | Corresponding C Function Signature                               |\n| -------------------------------- | ------------------------------------------------------------------ |\n| `ii =\u003e i`                        | `int function(int, int);`                                        |\n| `c* =\u003e v`                        | `void function(char*);` (Also used for `void*`)                  |\n| `(i=\u003ev) =\u003e v`                    | `void function(void (*callback)(int));`                          |\n| `{i;f}c* =\u003e v`                   | `void function(struct { int a; float b; }, char*);`               |\n| `c*.if =\u003e i`                     | `int function(const char*, int, float, ...);`                     |\n| `p(9,1){c:0;y:1} =\u003e i`           | `int function(PackedStruct);` (where `PackedStruct` is `char a; uint64_t b;` packed to 1-byte alignment) |\n\n\n### Project Structure\n\n```.\n├── include/              # Public API header (infix.h) and compatibility headers\n├── src/                  # All implementation files\n│   ├── arch/             # Architecture-specific implementations (x64, aarch64)\n│   └── core/             # Core implementation files (executor.c, types.c, etc.)\n├── t/                    # Test files\n├── fuzz/                 # Fuzzing harness\n├── docs/                 # Detailed documentation\n│   ├── cookbook.md       # Practical recipes and examples\n│   └── internals.md      # Deep dive into the architecture\n└── README.md             # This file\n```\n\n### API Concepts\n\nThe infix API is built around a few core concepts. Understanding them is key to using the library effectively.\n\n#### 1. The Type System (`ffi_type`)\n\nBefore you can call a function or create a callback, you must describe its signature to the library. This is done using `ffi_type` pointers.\n\n*   **Static Types:** For basic C types, you use singleton instances provided by the library. You **never** need to free these.\n    *   `ffi_type_create_primitive(FFI_PRIMITIVE_TYPE_SINT32)` for `int`.\n    *   `ffi_type_create_pointer()` for any pointer type (`char*`, `void*`, `MyStruct*`).\n    *   `ffi_type_create_void()` for functions that return `void`.\n*   **Dynamic Types:** For complex types like structs, unions, and arrays, you must build them dynamically. These **must** be freed with `ffi_type_destroy` when you are done with them.\n    *   `ffi_type_create_struct()`: Takes an array of `ffi_struct_member` that describes the layout of the struct.\n    *   `ffi_type_create_array()`: Describes a fixed-size array of another `ffi_type`.\n\n#### 2. Forward Calls (`generate_forward_trampoline`)\n\nA \"forward call\" is when your code calls a C function. To do this, you generate a **trampoline**. A trampoline is a small, JIT-compiled function stub that bridges the gap between the library's generic calling convention and the target function's specific, native ABI.\n\nThe process is:\n1.  Describe the function's return type and argument types using an array of `ffi_type*`.\n2.  Call `generate_forward_trampoline()` with this signature.\n3.  This returns a `ffi_trampoline_t*` handle. Get the executable code pointer from it by calling `ffi_trampoline_get_code()`.\n4.  Cast this pointer to `ffi_cif_func`.\n5.  Call the `ffi_cif_func`, passing it the target function's address, a pointer to a buffer for the return value, and an array of pointers to the arguments.\n6.  Free the trampoline with `ffi_trampoline_free()`.\n\n#### 3. Reverse Calls / Callbacks (`generate_reverse_trampoline`)\n\nA \"reverse call\" is when you create a native C function pointer that, when called by external code, executes a C function handler that you provide. This is used to implement callbacks.\n\nThe process is:\n1.  Describe the desired signature of your callback using `ffi_type*`.\n2.  Call `generate_reverse_trampoline()`, passing it the signature, a pointer to your C handler function, and an optional `void* user_data` pointer to maintain state.\n3.  This returns a `ffi_reverse_trampoline_t*` handle.\n4.  The native function pointer is located in `rt-\u003eexec_code.rx_ptr`. Cast this pointer to the appropriate function pointer type.\n5.  You can now pass this function pointer to any C API that expects a callback.\n6.  The `ffi_reverse_trampoline_t*` handle **must** remain alive for as long as the native function pointer is in use. Free it with `ffi_reverse_trampoline_free()` when the callback is no longer needed.\n\n#### 4. Error Handling (`ffi_status`)\n\nNearly all API functions that can fail return an `ffi_status` enum. Always check the return value of these functions.\n\n```c\nffi_trampoline_t* trampoline = NULL;\nffi_status status = generate_forward_trampoline(\u0026trampoline, ...);\nif (status != FFI_SUCCESS) {\n    // Handle the error\n}\n```\n\n#### 5. Memory Management\n\n*   **If you `create` it, you `destroy` it.** Any `ffi_type` from `ffi_type_create_struct`, `_union`, or `_array` must be freed with `ffi_type_destroy()`. Destruction is recursive.\n*   **The caller owns input on failure.** If `ffi_type_create_struct` fails, you are still responsible for freeing the `members` array you passed in.\n*   **Do not free static types.** Return values from `ffi_type_create_primitive()`, `_pointer()`, and `_void()` must not be destroyed.\n*   **Trampolines must be freed.** Always call `ffi_trampoline_free()` and `ffi_reverse_trampoline_free()`.\n\n### How It Works\n\n`infix` generates raw machine code at runtime and writes it into a W^X executable memory block.\n\n1.  **ABI Specification:** An `ffi_abi_spec` v-table provides function pointers to an implementation for the target ABI.\n2.  **Trampoline Generation:** The library consults the ABI spec to create a `ffi_call_frame_layout` blueprint that maps each argument to its destination (register or stack).\n3.  **JIT Execution:** The core engine uses this blueprint to emit machine code into a memory buffer, which is then made executable using platform-specific APIs.\n\nFor a deeper dive into the architecture, see [docs/internals.md](./docs/internals.md).\n\n### Example 1: Forward Call (Calling a C function)\n\nThis example shows how to dynamically call the function `int add(int a, int b)`.\n\n```c\n#include \"infix.h\"\n#include \u003cstdio.h\u003e\n\n// The C function we want to call\nint add(int a, int b) {\n    return a + b;\n}\n\nint main(void) {\n    // 1. Describe the function signature as a string.\n    // Signature: int printf(const char* format, ...);\n    // We will call it with an int and a double.\n    // 'c*' = const char*, '.' = variadic separator, 'i' = int, 'd' = double\n    const char* signature = \"c*.id =\u003e i\";\n\n    // 2. Generate the trampoline from the signature.\n    ffi_trampoline_t* trampoline = NULL;\n    ffi_status status = ffi_create_forward_trampoline_from_signature(\u0026trampoline, signature);\n\n    if (status != FFI_SUCCESS) {\n        fprintf(stderr, \"Failed to generate trampoline from signature.\\n\");\n        return 1;\n    }\n\n    // 3. Prepare the arguments.\n    const char* format_str = \"Hello from a signature! The number is %d and the double is %.2f\\\\n\";\n    int my_int = 42;\n    double my_double = 3.14;\n    void* args[] = { \u0026format_str, \u0026my_int, \u0026my_double };\n\n    // 4. Get the callable function pointer and invoke it.\n    ffi_cif_func cif_func = (ffi_cif_func)ffi_trampoline_get_code(trampoline);\n    int printf_ret = 0;\n    cif_func((void*)printf, \u0026printf_ret, args);\n\n    printf(\"printf returned: %d\\\\n\", printf_ret);\n\n    // 5. Clean up.\n    ffi_trampoline_free(trampoline);\n    return 0;\n}\n```\n\n### Example 2: Calling a Variadic Function\n\nCalling a function like `snprintf` requires specifying how many arguments are part of the fixed signature before the `...`. For `snprintf(buf, size, format, ...)`, there are 3 fixed arguments.\n\n```c\n#include \"infix.h\"\n#include \u003cstdio.h\u003e\n#include \u003cstring.h\u003e\n\nvoid test_variadic_call() {\n    // Target signature: int snprintf(char*, size_t, const char*, ...);\n    ffi_type* ret_type = ffi_type_create_primitive(FFI_PRIMITIVE_TYPE_SINT32);\n    ffi_type* arg_types[] = {\n        ffi_type_create_pointer(),                             // Fixed: char* buffer\n        ffi_type_create_primitive(FFI_PRIMITIVE_TYPE_UINT64),  // Fixed: size_t size\n        ffi_type_create_pointer(),                             // Fixed: const char* format\n        ffi_type_create_pointer(),                             // Variadic: const char* \"hello\"\n        ffi_type_create_primitive(FFI_PRIMITIVE_TYPE_SINT32),  // Variadic: int 123\n        ffi_type_create_primitive(FFI_PRIMITIVE_TYPE_DOUBLE)   // Variadic: double 3.14\n    };\n\n    // Generate the trampoline: Total arguments = 6. Fixed arguments = 3.\n    ffi_trampoline_t* trampoline = NULL;\n    ffi_status status = generate_forward_trampoline(\u0026trampoline, ret_type, arg_types, 6, 3);\n    if (status != FFI_SUCCESS) {\n        fprintf(stderr, \"Failed to generate variadic trampoline: %d\\n\", status);\n        return;\n    }\n    ffi_cif_func cif_func = (ffi_cif_func)ffi_trampoline_get_code(trampoline);\n\n    char buffer;\n    size_t buf_size = sizeof(buffer);\n    const char* format = \"Variadic call: %s %d %.2f\";\n    const char* str_arg = \"hello\";\n    int int_arg = 123;\n    double dbl_arg = 3.14;\n    void* args[] = { \u0026buffer, \u0026buf_size, \u0026format, \u0026str_arg, \u0026int_arg, \u0026dbl_arg };\n    int chars_written = 0;\n\n    cif_func((void*)snprintf, \u0026chars_written, args);\n    printf(\"'%s' (%d chars)\\n\", buffer, chars_written); // Prints \"'Variadic call: hello 123 3.14' (31 chars)\"\n\n    ffi_trampoline_free(trampoline);\n}\n```\n\n### Example 3: Reverse Call (Creating a Callback)\n\nThis example creates a C function pointer that, when called, will execute our `my_int_callback_handler`.\n\n```c\n#include \"infix.h\"\n#include \u003cstdio.h\u003e\n\n// Our custom handler that will be called by the trampoline\nint my_int_callback_handler(int a, int b) {\n    return a * b;\n}\n\nvoid test_reverse_call() {\n    // 1. Describe the signature of the callback\n    ffi_type *ret_type = ffi_type_create_primitive(FFI_PRIMITIVE_TYPE_SINT32);\n    ffi_type *arg_types[] = {\n        ffi_type_create_primitive(FFI_PRIMITIVE_TYPE_SINT32),\n        ffi_type_create_primitive(FFI_PRIMITIVE_TYPE_SINT32)\n    };\n\n    // 2. Generate the reverse trampoline, linking it to our handler.\n    ffi_reverse_trampoline_t *rt = NULL;\n    ffi_status status = generate_reverse_trampoline(\n        \u0026rt, ret_type, arg_types, 2, 2, (void *)my_int_callback_handler, NULL\n    );\n    if (status != FFI_SUCCESS) {\n        fprintf(stderr, \"Failed to generate reverse trampoline: %d\\n\", status);\n        return;\n    }\n\n    // 3. Get a native, callable function pointer from the trampoline\n    typedef int (*my_func_ptr)(int, int);\n    my_func_ptr func_ptr = (my_func_ptr)rt-\u003eexec_code.rx_ptr;\n\n    // 4. Call the generated pointer as if it were a normal C function\n    int result = func_ptr(7, 6);\n    printf(\"Result of callback(7, 6): %d\\n\", result); // Prints 42\n\n    // 5. Clean up\n    ffi_reverse_trampoline_free(rt);\n}\n```\n\n### Building the Project\n\n**Prerequisites:**\n*   A C17-compatible compiler like GCC, Clang, or MSVC.\n*   `perl` (recommended, cross-platform).\n\n#### Using Perl\n\nThe included Perl script can build the library, run tests, and manage other tasks.\n\n```bash\n# Seek help\nperl build.pl help\n\n# Build the static library (libinfix.a or infix.lib)\nperl build.pl build\n\n# To specify a compiler (msvc, gcc, clang):\nperl build.pl --compiler=clang build\n\n# Run all standard tests\nperl build.pl test\n\n# Run the memory stress test under Valgrind (on Linux)\nperl build.pl memtest\n\n# Run the fault injection memory test under Valgrind (on Linux)\nperl build.pl memtest:fault\n\n# Run the threading test with ThreadSanitizer (on a compatible toolchain)\nperl build.pl test 800_threading\n\n# Build and run the fuzzer (requires Clang)\nperl build.pl fuzz\n./fuzz_types_harness -max_total_time=300 corpus/\n```\n\n### Integrating infix Into Your Project\n\nTo use infix in your own application:\n\n1.  Run `perl build.pl build` to produce the static library (`libinfix.a` or `infix.lib`).\n2.  Copy the static library and the `include/` directory into your project's source tree.\n3.  Include the main header in your code: `#include \"infix.h\"`\n4.  When compiling your application, tell the compiler where to find the header files and how to link the library.\n\n**Example GCC/Clang link command:**\n```bash\ngcc src/main.c -Ipath/to/infix/include -Lpath/to/infix/lib -linfix -o my_app\n```\n\n### Learn More\n\n*   **[Cookbook](./docs/cookbook.md):** Practical, copy-pasteable recipes for common FFI tasks.\n*   **[Internals](./docs/internals.md):** A deep dive into the library's architecture for maintainers and contributors.\n*   **[Porting Guide](./docs/porting.md):** A brief document with basic instructions to add new architectures.\n\n## License \u0026 Legal\n\n`infix` is provided under a dual-license model to maximize its usability for all developers.\n\n### Code License\n\nAll source code, including header files (`.h`) and implementation files (`.c`),\nis dual-licensed under the **Artistic License 2.0** or the **MIT License**. You\nmay choose to use the code under the terms of either license.\n\nSee the [LICENSE-A2](LICENSE-A2) and/or [LICENSE-MIT](LICENSE-MIT) file for the\nfull text of both licenses.\n\n### Documentation License\n\nAll standalone documentation, including this `README.md`, the `cookbook.md`, and\nall other markdown files in the `/docs` directory, is licensed under the\n**Creative Commons Attribution 4.0 International License (CC BY 4.0)**. This\nlicense encourages you to share and adapt the documentation for any purpose, as\nlong as you give appropriate credit.\n\nSee the [LICENSE-CC](LICENSE-CC) for details.\n\n### Clarification on Embedded Documentation\n\nBy default, all content within the source code files (`.h`, `.c`) is licensed as\na whole under the project's code license (Artistic 2.0 / MIT).\n\nHowever, an additional permission is granted: any explanatory text, including\nDoxygen-style documentation blocks, comments, and code examples contained within\nthe source code, may be separately used, modified, and distributed under the terms\nof the **Creative Commons Attribution 4.0 International License (CC BY 4.0)**\n*when such text is extracted from and presented separately from the functional\nsource code.*\n\nThis allows for the free use of the project's inline documentation for purposes\nsuch as generating an API reference website, creating tutorials, or adapting the\ndocumentation in other ways while ensuring that the code itself remains under the\nA2/MIT license when used as a whole (e.g., when a developer includes `infix.h` in\ntheir project).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsanko%2Finfix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsanko%2Finfix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsanko%2Finfix/lists"}