### Install libamxc Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/README.md Install the compiled library using the make install target. ```bash cd ~/amx_project/libraries/libamxc sudo -E make install ``` -------------------------------- ### Start coverage report server Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/README.md Start a Python HTTP server to view coverage reports in a browser. ```bash cd ~/amx_project/ python3 -m http.server 8080 & ``` -------------------------------- ### Install Debian package Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/README.md Install a generated .deb package using dpkg. ```bash sudo dpkg -i ~/amx_project/libraries/libamxc/libamxc-.deb ``` -------------------------------- ### Launch Development Container Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/README.md Start the container with necessary permissions, user mapping, and volume mounts for project development. ```bash docker run -ti -d --name oss-dbg --restart always --cap-add=SYS_PTRACE --sysctl net.ipv6.conf.all.disable_ipv6=1 -e "USER=$USER" -e "UID=$(id -u)" -e "GID=$(id -g)" -v ~/amx_project/:/home/$USER/amx_project/ registry.gitlab.com/soft.at.home/docker/oss-dbg:latest ``` -------------------------------- ### Package libamxc Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/README.md Create installable packages from the source. ```bash cd ~/amx_project/libraries/libamxc make package ``` -------------------------------- ### Example debug output Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Sample text output generated by the amxc_var_dump function. ```txt [ { user_id: 1, name: "John Doe", access_rights: 0x775 }, { user_id: 2, name: "Jane Doe", access_rights: 0x664 }, { user_id: 3, name: "Super", access_rights: 0x777 } ] ``` -------------------------------- ### Example JSON data structure Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md A sample JSON representation of a users data set used for variant operations. ```json [ { "user_id": 1, "name": "John Doe", "access_rights": 0x775 }, { "user_id": 2, "name": "Jane Doe", "access_rights": 0x664 }, { "user_id": 3, "name": "Super", "access_rights": 0x777 } ] ``` -------------------------------- ### Worker function for linked list Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Example usage of the linked list user management functions. ```C amxc_llist_t *my_worker_function(void) { amxc_llist_t *my_users = NULL; amxc_llist_new(&my_users); add_user(my_users, 1, "John Doe", 0x755); add_user(my_users, 2, "Jane Doe", 0x644); add_user(my_users, 3, "Super", 0x777); return my_users; } ``` -------------------------------- ### Worker function for variant list Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Example usage of the variant-based user management functions. ```C amxc_var_t *my_worker_function(void) { amxc_var_t *my_users = NULL; amxc_var_new(&my_users); amxc_var_set_type(my_users, AMXC_VAR_ID_LIST); add_user(my_users, 1, "John Doe", 0x755); add_user(my_users, 2, "Jane Doe", 0x644); add_user(my_users, 3, "Super", 0x777); return my_users; } ``` -------------------------------- ### Iterating Composite Lists Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Provides an example of how to iterate over a composite variant that contains a list of variants using the `amxc_var_for_each` macro. It highlights that this iteration method is specific to list variants. ```APIDOC ## Iterating A Composite List A composite variant containing a list of variants can be iterated using macro `amxc_var_for_each` ### Example ```C amxc_var_for_each(user, (&users)) { amxc_var_t *var_name = amxc_var_get_path(user, "name", AMXC_VAR_FLAG_DEFAULT); const char *str_name = amxc_var_constcast(cstring_t, var_name); } ``` > NOTE > > Iterating only works on composite list variants and not on composite key-value pair variants. ``` -------------------------------- ### Accessing Individual Primitives with amxc_var_get_path Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Demonstrates how to retrieve individual primitive values from a composite variant using a path. It explains the function signature, the use of flags for copying or referencing, and provides an example of accessing a nested value. ```APIDOC ## Accessing Individual Primitives Getting the individual values out of a composite variant can be done by accessing the individual variant by it's `path`. The function to retrieve a primitive variant out of the composite variant is: ```C amxc_var_t *amxc_var_get_path(const amxc_var_t * const var, const char * const path, const int flags); ``` This function will give the pointer to the variant as in the composite variant or a newly allocated variant, which you need to free with `amxc_var_delete`. The `flags` argument is used to indicate what you want the variant as is or a copy. The flags can be: - `AMXC_VAR_FLAG_DEFAULT` (no copy, use the variant as is) - `AMXC_VAR_FLAG_COPY` (allocate a new variant, and copy the data) > NOTE > > When using the default behavior `AMXC_VAR_FLAG_DEFAULT` the pointer to the variant in the composite variant is returned. When changing the value of that returned value, the value in the composite variant is changed. ### Example Let's take the `users` data set and assume a complex variant is created with this data (JSON notation) ```json [ { "user_id": 1, "name": "John Doe", "access_rights": 0x775 }, { "user_id": 2, "name": "Jane Doe", "access_rights": 0x664 }, { "user_id": 3, "name": "Super", "access_rights": 0x777 } ] ``` Getting the name of the second user in the composite variant can be achieved by: ```C amxc_var_t *var_name = amxc_var_get_path(&users, "1.name", AMXC_VAR_FLAG_DEFAULT); const char *str_name = amxc_var_constcast(cstring_t, var_name); ``` A list can be accessed using an index, the first element in a list will have index 0. Key-value pairs can be accessed by key. ``` -------------------------------- ### Inspecting Variant Content with amxc_var_dump Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Explains the `amxc_var_dump` function, which is used to print the content of a variant in a JSON-like structure for debugging complex variants. It shows the function signature and an example of its output. ```APIDOC ## Inspecting The Content With very complex composite variants it can be difficult to understand what is stored in the variant. A debug function is available that will print the content of the variant in a JSON like structure. ```C int amxc_var_dump(const amxc_var_t * const var, int fd); ``` The file descriptor can be `STDOUT_FILENO`, `STDERR_FILENO` or any other file descriptor with write permissions. ### Example output (using the `users` example) ```txt [ { user_id: 1, name: "John Doe", access_rights: 0x775 }, { user_id: 2, name: "Jane Doe", access_rights: 0x664 }, { user_id: 3, name: "Super", access_rights: 0x777 } ] ``` ``` -------------------------------- ### Retrieve a primitive variant by path Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Use this function to get a pointer to a variant within a composite structure. Specify flags to determine if the returned pointer refers to the original data or a newly allocated copy. ```C amxc_var_t *amxc_var_get_path(const amxc_var_t * const var, const char * const path, const int flags); ``` -------------------------------- ### Get Variant Type Identifier Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Retrieves the integer type identifier of the data contained within a variant using `amxc_var_type_of`. ```C uint32_t amxc_var_type_of(const amxc_var_t * const var); ``` -------------------------------- ### Get Variant Type Name Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Fetches the string name of the data type currently held by a variant using `amxc_var_type_name_of`. The returned pointer is constant and should not be freed. ```C const char *amxc_var_type_name_of(const amxc_var_t * const var); ``` -------------------------------- ### Initialize and Use Ring Buffer in C Source: https://context7.com/prpl-foundation/components/llms.txt Demonstrates initializing a ring buffer, writing data, performing partial and full reads, and cleaning up resources. The buffer automatically handles circular wrapping for data storage. ```c #include #include #include int main(void) { amxc_rbuffer_t rb; amxc_rbuffer_init(&rb, 64); // 64-byte initial capacity // Write data const char* msg1 = "Hello, "; const char* msg2 = "Ring Buffer!"; amxc_rbuffer_write(&rb, msg1, strlen(msg1)); amxc_rbuffer_write(&rb, msg2, strlen(msg2)); printf("Data size: %zu bytes\n", amxc_rbuffer_size(&rb)); printf("Capacity: %zu bytes\n", amxc_rbuffer_capacity(&rb)); // Output: Data size: 19 bytes // Output: Capacity: 64 bytes // Read partial data char buf[32]; ssize_t read = amxc_rbuffer_read(&rb, buf, 7); buf[read] = '\0'; printf("Read %zd bytes: '%s'\n", read, buf); // Output: Read 7 bytes: 'Hello, ' // Read remaining data read = amxc_rbuffer_read(&rb, buf, sizeof(buf)); buf[read] = '\0'; printf("Read %zd bytes: '%s'\n", read, buf); // Output: Read 12 bytes: 'Ring Buffer!' // Buffer is now empty printf("Is empty: %s\n", amxc_rbuffer_is_empty(&rb) ? "yes" : "no"); // Output: Is empty: yes // Write more data (wraps around in circular fashion) for (int i = 0; i < 5; i++) { char data[20]; snprintf(data, sizeof(data), "Message %d\n", i); amxc_rbuffer_write(&rb, data, strlen(data)); } // Read all while (!amxc_rbuffer_is_empty(&rb)) { char c; amxc_rbuffer_read(&rb, &c, 1); putchar(c); } amxc_rbuffer_clean(&rb); return 0; } ``` -------------------------------- ### Fetch Docker Container Image Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/README.md Download the pre-configured development environment image from the registry. ```bash docker pull registry.gitlab.com/soft.at.home/docker/oss-dbg:latest ``` -------------------------------- ### Build and Link libamxc Applications Source: https://context7.com/prpl-foundation/components/llms.txt Provides commands for building the library and compiling applications against it. ```bash # Build the library cd libamxc make # Install (optional) sudo make install # Compile your application gcc -Wall -Wextra -Werror myapp.c -lamxc -o myapp # Or with explicit paths gcc -I/path/to/libamxc/include -L/path/to/libamxc/output myapp.c -lamxc -o myapp ``` -------------------------------- ### Implement Queues and Stacks with libamxc Source: https://context7.com/prpl-foundation/components/llms.txt Demonstrates the usage of array-based queues and stacks for FIFO and LIFO operations respectively. ```c #include #include int main(void) { // Array-based queue (FIFO) amxc_array_t queue; amxc_array_init(&queue, 10); // Enqueue items int values[] = {10, 20, 30, 40}; for (int i = 0; i < 4; i++) { amxc_aqueue_add(&queue, &values[i]); } // Dequeue items (FIFO order) while (!amxc_array_is_empty(&queue)) { int* val = (int*)amxc_aqueue_remove(&queue); printf("Dequeued: %d\n", *val); } // Output: 10, 20, 30, 40 amxc_array_clean(&queue, NULL); // Array-based stack (LIFO) amxc_array_t stack; amxc_array_init(&stack, 10); // Push items for (int i = 0; i < 4; i++) { amxc_astack_push(&stack, &values[i]); } // Pop items (LIFO order) while (!amxc_array_is_empty(&stack)) { int* val = (int*)amxc_astack_pop(&stack); printf("Popped: %d\n", *val); } // Output: 40, 30, 20, 10 amxc_array_clean(&stack, NULL); return 0; } ``` -------------------------------- ### Manage Hash Table Data in C Source: https://context7.com/prpl-foundation/components/llms.txt Demonstrates initializing a hash table, inserting entries, performing lookups, and iterating through elements. Requires manual cleanup using a callback function to free embedded data. ```c #include #include #include typedef struct config_entry { int value; amxc_htable_it_t hit; // Embedded hash table iterator } config_entry_t; static void delete_entry(const char* key, amxc_htable_it_t* it) { config_entry_t* entry = amxc_htable_it_get_data(it, config_entry_t, hit); printf("Deleting key: %s\n", key); free(entry); } int main(void) { amxc_htable_t config; amxc_htable_init(&config, 10); // Reserve 10 buckets // Insert entries const char* keys[] = {"timeout", "retries", "port", "debug"}; int values[] = {30, 3, 8080, 1}; for (int i = 0; i < 4; i++) { config_entry_t* entry = calloc(1, sizeof(config_entry_t)); entry->value = values[i]; amxc_htable_insert(&config, keys[i], &entry->hit); } printf("Table size: %zu\n", amxc_htable_size(&config)); // Output: Table size: 4 // Lookup by key amxc_htable_it_t* it = amxc_htable_get(&config, "port"); if (it != NULL) { config_entry_t* entry = amxc_htable_it_get_data(it, config_entry_t, hit); printf("port = %d\n", entry->value); } // Output: port = 8080 // Check if key exists if (amxc_htable_contains(&config, "timeout")) { printf("Has timeout config\n"); } // Iterate all entries amxc_htable_for_each(iter, (&config)) { const char* key = amxc_htable_it_get_key(iter); config_entry_t* e = amxc_htable_it_get_data(iter, config_entry_t, hit); printf("%s => %d\n", key, e->value); } // Get sorted keys amxc_array_t* sorted = amxc_htable_get_sorted_keys(&config); if (sorted) { for (size_t i = 0; i < amxc_array_size(sorted); i++) { printf("Sorted key %zu: %s\n", i, (char*)amxc_array_get_data_at(sorted, i)); } amxc_array_delete(&sorted, NULL); } amxc_htable_clean(&config, delete_entry); return 0; } ``` -------------------------------- ### Create Shared Project Directory Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/README.md Prepare a local directory to be mounted into the Docker container for development. ```bash mkdir -p ~/amx_project/libraries/ ``` -------------------------------- ### Manage Variant Hash Tables in C Source: https://context7.com/prpl-foundation/components/llms.txt Demonstrates creating, populating, and accessing key-value pairs in hash tables, including path-based access for nested data. ```c #include #include #include int main(void) { amxc_var_t config; amxc_var_init(&config); amxc_var_set_type(&config, AMXC_VAR_ID_HTABLE); // Add key-value pairs amxc_var_add_key(cstring_t, &config, "hostname", "localhost"); amxc_var_add_key(uint32_t, &config, "port", 8080); amxc_var_add_key(bool, &config, "ssl_enabled", false); // Add nested hash table amxc_var_t* db = amxc_var_add_key(amxc_htable_t, &config, "database", NULL); amxc_var_add_key(cstring_t, db, "host", "db.example.com"); amxc_var_add_key(uint32_t, db, "port", 5432); amxc_var_add_key(cstring_t, db, "name", "myapp"); // Access by key const char* host = GET_CHAR(&config, "hostname"); uint32_t port = GET_UINT32(&config, "port"); printf("Server: %s:%u\n", host, port); // Output: Server: localhost:8080 // Access nested values by path const char* db_host = GETP_CHAR(&config, "database.host"); uint32_t db_port = GETP_UINT32(&config, "database.port"); printf("Database: %s:%u\n", db_host, db_port); // Output: Database: db.example.com:5432 // Using amxc_var_get_path for complex paths amxc_var_t* db_name = amxc_var_get_path(&config, "database.name", AMXC_VAR_FLAG_DEFAULT); if (db_name) { printf("DB Name: %s\n", amxc_var_constcast(cstring_t, db_name)); } // Iterate key-value pairs const amxc_htable_t* ht = amxc_var_constcast(amxc_htable_t, &config); amxc_htable_iterate(it, ht) { const char* key = amxc_htable_it_get_key(it); amxc_var_t* val = amxc_var_from_htable_it(it); printf("Key: %s, Type: %s\n", key, amxc_var_type_name_of(val)); } // Dump for debugging amxc_var_dump(&config, STDOUT_FILENO); amxc_var_clean(&config); return 0; } ``` -------------------------------- ### Run tests Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/README.md Execute the test suite for libamxc. ```bash cd ~/amx_project/libraries/libamxc/tests make ``` ```bash cd ~/amx_project/libraries/libamxc/tests make run coverage ``` -------------------------------- ### Create a variant list Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Initialize a variant as a list and add string elements. ```C amxc_var_t my_var; amxc_var_init(&my_var); amxc_var_set_type(&my_var, AMXC_VAR_ID_LIST); amxc_var_add(cstring_t, &my_var, "Hello"); amxc_var_add(cstring_t, &my_var, "World"); ``` -------------------------------- ### Build libamxc Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/README.md Compile the library source code. ```bash cd ~/amx_project/libraries/libamxc make ``` -------------------------------- ### Generate API documentation Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/README.md Generate HTML documentation using Doxygen. ```bash cd ~/amx_project/libraries/libamxc make doc ``` -------------------------------- ### Create a variant hash table Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Initialize a variant as a hash table and add key-value pairs. ```C amxc_var_t my_var; amxc_var_init(&my_var); amxc_var_set_type(&my_var, AMXC_VAR_ID_HTABLE); amxc_var_add_key(cstring_t, &my_var, "key1", "Hello"); amxc_var_add_key(cstring_t, &my_var, "key2", "World"); ``` -------------------------------- ### Manage Variant Lists in C Source: https://context7.com/prpl-foundation/components/llms.txt Demonstrates initializing, populating, accessing, and iterating over variant lists, including nested structures. ```c #include #include #include int main(void) { amxc_var_t list; amxc_var_init(&list); amxc_var_set_type(&list, AMXC_VAR_ID_LIST); // Add different types to the list amxc_var_add(cstring_t, &list, "first"); amxc_var_add(int32_t, &list, 42); amxc_var_add(bool, &list, true); amxc_var_add(double, &list, 3.14); // Access by index amxc_var_t* elem = amxc_var_get_index(&list, 1, AMXC_VAR_FLAG_DEFAULT); printf("Index 1: %d\n", amxc_var_constcast(int32_t, elem)); // Output: Index 1: 42 // Iterate over list amxc_var_for_each(var, (&list)) { printf("Type: %s\n", amxc_var_type_name_of(var)); } // Convenience macros const char* str = GETI_CHAR(&list, 0); // Get string at index 0 int32_t val = GETI_INT32(&list, 1); // Get int32 at index 1 printf("str=%s, val=%d\n", str, val); // Nested lists amxc_var_t* nested = amxc_var_add(amxc_llist_t, &list, NULL); amxc_var_add(cstring_t, nested, "nested1"); amxc_var_add(cstring_t, nested, "nested2"); // Dump content for debugging amxc_var_dump(&list, STDOUT_FILENO); /* Output: [ "first", 42, true, 3.14, [ "nested1", "nested2" ] ] */ amxc_var_clean(&list); return 0; } ``` -------------------------------- ### Build Complex Data Structures with Amxc Variant API Source: https://context7.com/prpl-foundation/components/llms.txt Demonstrates how to build nested data structures combining lists and hash tables, similar to JSON objects, using the Amxc Variant API. Includes creating user records and lists of users. ```c #include #include #include // Build a user record amxc_var_t* create_user(uint32_t id, const char* name, uint32_t access) { amxc_var_t* user = NULL; amxc_var_new(&user); amxc_var_set_type(user, AMXC_VAR_ID_HTABLE); amxc_var_add_key(uint32_t, user, "user_id", id); amxc_var_add_key(cstring_t, user, "name", name); amxc_var_add_key(uint32_t, user, "access_rights", access); return user; } int main(void) { // Create a list of users amxc_var_t users; amxc_var_init(&users); amxc_var_set_type(&users, AMXC_VAR_ID_LIST); // Add users using helper function amxc_var_t* u1 = create_user(1, "John Doe", 0x755); amxc_var_t* u2 = create_user(2, "Jane Doe", 0x644); amxc_var_t* u3 = create_user(3, "Admin", 0x777); amxc_var_set_index(&users, -1, u1, AMXC_VAR_FLAG_DEFAULT); amxc_var_set_index(&users, -1, u2, AMXC_VAR_FLAG_DEFAULT); amxc_var_set_index(&users, -1, u3, AMXC_VAR_FLAG_DEFAULT); // Access nested data: users[1].name amxc_var_t* name = amxc_var_get_path(&users, "1.name", AMXC_VAR_FLAG_DEFAULT); printf("Second user: %s\n", amxc_var_constcast(cstring_t, name)); // Output: Second user: Jane Doe // Iterate and print all users amxc_var_for_each(user, (&users)) { printf("User %u: %s (0x%X)\n", GETP_UINT32(user, "user_id"), GETP_CHAR(user, "name"), GETP_UINT32(user, "access_rights")); } // JSON-like output amxc_var_dump(&users, STDOUT_FILENO); /* Output: [ { user_id: 1, name: "John Doe", access_rights: 1877 }, { user_id: 2, name: "Jane Doe", access_rights: 1604 }, { user_id: 3, name: "Admin", access_rights: 1911 } ] */ amxc_var_clean(&users); return 0; } ``` -------------------------------- ### Manage a Doubly Linked List with Custom Structures Source: https://context7.com/prpl-foundation/components/llms.txt Demonstrates adding, iterating, accessing, and cleaning up a doubly linked list storing custom 'person_t' structures. Ensure a callback is provided to 'amxc_llist_clean' for freeing allocated memory. ```c #include #include #include typedef struct person { char first_name[64]; char last_name[64]; uint32_t age; amxc_llist_it_t it; // Embedded iterator } person_t; // Callback to free person structures static void delete_person(amxc_llist_it_t* it) { person_t* person = amxc_container_of(it, person_t, it); free(person); } int main(void) { amxc_llist_t contacts; amxc_llist_init(&contacts); // Add 5 people to the list for (uint32_t i = 0; i < 5; i++) { person_t* person = (person_t*)calloc(1, sizeof(person_t)); snprintf(person->first_name, 64, "John%d", i); snprintf(person->last_name, 64, "Doe%d", i); person->age = 20 + i; amxc_llist_append(&contacts, &person->it); } printf("List size: %zu\n", amxc_llist_size(&contacts)); // Output: List size: 5 // Iterate over the list (safe to delete current item) amxc_llist_for_each(it, (&contacts)) { person_t* p = amxc_container_of(it, person_t, it); printf("%s %s, age %d\n", p->first_name, p->last_name, p->age); } // Get item at specific index amxc_llist_it_t* second = amxc_llist_get_at(&contacts, 1); person_t* p2 = amxc_container_of(second, person_t, it); printf("Second person: %s\n", p2->first_name); // Output: Second person: John1 // Clean up - calls delete_person for each item amxc_llist_clean(&contacts, delete_person); return 0; } ``` -------------------------------- ### Manipulate Dynamic Strings in C Source: https://context7.com/prpl-foundation/components/llms.txt Shows how to use dynamic strings for printf-style formatting, searching, replacing, trimming, and case conversion. Note that amxc_string_take_buffer transfers ownership, requiring manual memory management. ```c #include #include int main(void) { amxc_string_t str; amxc_string_init(&str, 0); // Set content using printf formatting amxc_string_setf(&str, "Hello, %s!", "World"); printf("String: %s\n", amxc_string_get(&str, 0)); // Output: String: Hello, World! // Append formatted content amxc_string_appendf(&str, " Count: %d", 42); printf("After append: %s\n", amxc_string_get(&str, 0)); // Output: After append: Hello, World! Count: 42 // Prepend content amxc_string_prependf(&str, "[INFO] "); printf("After prepend: %s\n", amxc_string_get(&str, 0)); // Output: After prepend: [INFO] Hello, World! Count: 42 // String metrics printf("Text length: %zu\n", amxc_string_text_length(&str)); printf("Buffer size: %zu\n", amxc_string_buffer_length(&str)); // Search for substring int pos = amxc_string_search(&str, "World", 0); printf("'World' found at position: %d\n", pos); // Replace all occurrences amxc_string_t str2; amxc_string_init(&str2, 0); amxc_string_setf(&str2, "foo bar foo baz foo"); int count = amxc_string_replace(&str2, "foo", "QUX", UINT32_MAX); printf("Replaced %d times: %s\n", count, amxc_string_get(&str2, 0)); // Output: Replaced 3 times: QUX bar QUX baz QUX // Trim whitespace amxc_string_t str3; amxc_string_init(&str3, 0); amxc_string_set(&str3, " trimmed "); amxc_string_trim(&str3, NULL); // NULL uses isspace printf("Trimmed: '%s'\n", amxc_string_get(&str3, 0)); // Output: Trimmed: 'trimmed' // Case conversion amxc_string_to_upper(&str3); printf("Upper: %s\n", amxc_string_get(&str3, 0)); // Output: Upper: TRIMMED // Take buffer (transfers ownership) char* buf = amxc_string_take_buffer(&str); printf("Taken: %s\n", buf); free(buf); // Must free manually amxc_string_clean(&str); amxc_string_clean(&str2); amxc_string_clean(&str3); return 0; } ``` -------------------------------- ### Clone libamxc repository Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/README.md Clone the library source code into the local project directory. ```bash cd ~/amx_project/libraries/ git clone git@gitlab.com:prpl-foundation/components/ambiorix/libraries/libamxc.git ``` -------------------------------- ### Define a system user structure Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Define a C structure for user data to be used in a linked list. ```C typedef struct _system_user { uint32_t user_id; char *name; uint32_t access_rights; amxc_llist_t lit; } system_user_t; ``` -------------------------------- ### Manage a Dynamic Array with String Data Source: https://context7.com/prpl-foundation/components/llms.txt Shows how to initialize, set data, append, iterate, and clean up a dynamic array storing string pointers. A callback is required for 'amxc_array_clean' to free the string data. ```c #include #include #include #include // Callback to free array items static void delete_item(amxc_array_it_t* it) { free(it->data); } int main(void) { amxc_array_t arr; amxc_array_init(&arr, 10); // Initial capacity of 10 // Store strings in array char* names[] = {"Alice", "Bob", "Charlie", "Diana"}; for (int i = 0; i < 4; i++) { char* copy = strdup(names[i]); amxc_array_set_data_at(&arr, i, copy); } printf("Array size (used): %zu\n", amxc_array_size(&arr)); printf("Array capacity: %zu\n", amxc_array_capacity(&arr)); // Output: Array size (used): 4 // Output: Array capacity: 10 // Access by index char* second = (char*)amxc_array_get_data_at(&arr, 1); printf("Index 1: %s\n", second); // Output: Index 1: Bob // Append data (grows if needed) amxc_array_append_data(&arr, strdup("Eve")); // Iterate over used buckets only amxc_array_it_t* it = amxc_array_get_first(&arr); while (it != NULL) { printf("Name: %s\n", (char*)it->data); it = amxc_array_it_get_next(it); } // Take data from array (removes from array, returns pointer) char* taken = (char*)amxc_array_take_first_data(&arr); printf("Taken: %s\n", taken); free(taken); // Clean up amxc_array_clean(&arr, delete_item); return 0; } ``` -------------------------------- ### Manage Variant Types in C Source: https://context7.com/prpl-foundation/components/llms.txt Shows how to use stack and heap-allocated variants to store different data types, perform type conversions, and safely retrieve values. Note that amxc_var_constcast returns a default value if the requested type does not match the stored type. ```c #include #include int main(void) { // Stack-allocated variant amxc_var_t var; amxc_var_init(&var); // Set string value amxc_var_set(cstring_t, &var, "Hello World"); printf("Type: %s\n", amxc_var_type_name_of(&var)); printf("Value: %s\n", amxc_var_constcast(cstring_t, &var)); // Output: Type: cstring_t // Output: Value: Hello World // Set integer value (clears previous) amxc_var_set(uint32_t, &var, 42); printf("Type: %s\n", amxc_var_type_name_of(&var)); printf("Value: %u\n", amxc_var_constcast(uint32_t, &var)); // Output: Type: uint32_t // Output: Value: 42 // Type conversion with amxc_var_dyncast amxc_var_set(cstring_t, &var, "12345"); int32_t num = amxc_var_dyncast(int32_t, &var); // Converts string to int printf("Converted: %d\n", num); // Output: Converted: 12345 // constcast returns default if type doesn't match amxc_var_set(bool, &var, true); uint32_t wrong = amxc_var_constcast(uint32_t, &var); // Returns 0 bool correct = amxc_var_constcast(bool, &var); // Returns true printf("Wrong type: %u, Correct: %s\n", wrong, correct ? "true" : "false"); // Output: Wrong type: 0, Correct: true // Heap-allocated variant amxc_var_t* pvar = NULL; amxc_var_new(&pvar); amxc_var_set(double, pvar, 3.14159); printf("Pi: %f\n", amxc_var_constcast(double, pvar)); amxc_var_delete(&pvar); // pvar is set to NULL amxc_var_clean(&var); return 0; } ``` -------------------------------- ### Allocate and Delete a Variant on the Heap Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Shows how to allocate memory for a variant on the heap using `amxc_var_new`. The `amxc_var_delete` function frees the allocated memory and resets the pointer to NULL. ```C amxc_var_t *pMyVariant = NULL; amxc_var_new(&pMyVariant); amxc_var_delete(&pMyVariant); ``` -------------------------------- ### Add user to linked list Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Function to append a user instance to a linked list. ```C void add_user(amxc_llist_t *users, uint32_t user_id, const char *name, uint32_t access_rights) { int name_length = strlen(name); system_user_t *user = calloc(1, sizeof(system_user_t)); user->user_id = user_id; user->name = calloc(1, name_length + 1); strcpy(user->name, name); user->access_rights = access_rights; amxc_llist_append(users, &user->lit); } ``` -------------------------------- ### Initialize and Clean Up a Variant on the Stack Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Demonstrates how to define a local variant on the stack and then clean it up. The `amxc_var_clean` function resets the variant to the null type and frees any allocated memory. ```C amxc_var_t MyVariant; amxc_var_init(&MyVariant); amxc_var_clean(&MyVariant); ``` -------------------------------- ### Check container IP address Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/README.md Retrieve the container IP address to access the coverage report URL. ```bash USER@:~/amx_project/libraries/libamxc$ ip a ``` -------------------------------- ### Accessing List and Hash Table Variants Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Explains how to access the underlying linked list or hash table from a variant that holds these types using `amxc_var_constcast`. It also mentions how to retrieve variant pointers from list and hash table iterators. ```APIDOC ## Accessing The List When a variant contains a `list` type, the pointer to the linked list in the variant can be fetch using the macro `amxc_var_constcast`. ```C const amxc_llist_t *var_list = amxc_var_constcast(amxc_llist_t, &my_var); ``` Use the `amxc_llist_t` API to access or iterate over the list. Each item in the list will be a variant. Use function `amxc_var_from_llist_it` to get the variant pointer. ## Accessing The Hash Table When a variant contains a `htable` type, the pointer to the hash table in the variant can be fetch using the macro `amxc_var_constcast`. ```C const amxc_htable_t *var_table = amxc_var_constcast(amxc_htable_t, &my_var); ``` Use the `amxc_htable_t` API to access or iterate over the hash table. Each item in the table will be a variant. Use function `amxc_var_from_htable_it` to get the variant pointer. ``` -------------------------------- ### Iterate over a composite list Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Use the amxc_var_for_each macro to traverse a list of variants. ```C amxc_var_for_each(user, (&users)) { amxc_var_t *var_name = amxc_var_get_path(user, "name", AMXC_VAR_FLAG_DEFAULT); const char *str_name = amxc_var_constcast(cstring_t, var_name); } ``` -------------------------------- ### Variant Lifecycle Management Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Functions for initializing, cleaning, and deleting variant structures on the stack or heap. ```APIDOC ## C Functions: Variant Lifecycle ### Description Functions to manage the memory and initialization state of amxc_var_t variants. ### Methods - amxc_var_init(amxc_var_t *var) - amxc_var_new(amxc_var_t **var) - amxc_var_clean(amxc_var_t *var) - amxc_var_delete(amxc_var_t **var) ### Parameters - **var** (amxc_var_t*) - Required - Pointer to the variant structure. ``` -------------------------------- ### Amxc Variant API Type Conversion and Operations Source: https://context7.com/prpl-foundation/components/llms.txt Illustrates type conversion, in-place casting, and operations like list concatenation, string concatenation, integer addition, and variant comparison using the Amxc Variant API. ```c #include #include #include int main(void) { // Type conversion amxc_var_t src, dest; amxc_var_init(&src); amxc_var_init(&dest); amxc_var_set(cstring_t, &src, "42"); amxc_var_convert(&dest, &src, AMXC_VAR_ID_INT32); printf("Converted: %d\n", amxc_var_constcast(int32_t, &dest)); // Output: Converted: 42 // In-place cast amxc_var_set(int32_t, &src, 12345); amxc_var_cast(&src, AMXC_VAR_ID_CSTRING); printf("Cast to string: %s\n", amxc_var_constcast(cstring_t, &src)); // Output: Cast to string: 12345 // List concatenation with amxc_var_add_value amxc_var_t list1, list2; amxc_var_init(&list1); amxc_var_init(&list2); amxc_var_set_type(&list1, AMXC_VAR_ID_LIST); amxc_var_set_type(&list2, AMXC_VAR_ID_LIST); amxc_var_add(int32_t, &list1, 1); amxc_var_add(int32_t, &list1, 2); amxc_var_add(int32_t, &list2, 3); amxc_var_add(int32_t, &list2, 4); amxc_var_add_value(&list1, &list2); // list1 = [1, 2, 3, 4] amxc_var_dump(&list1, STDOUT_FILENO); // String concatenation amxc_var_t str1, str2; amxc_var_init(&str1); amxc_var_init(&str2); amxc_var_set(cstring_t, &str1, "Hello "); amxc_var_set(cstring_t, &str2, "World"); amxc_var_add_value(&str1, &str2); // "Hello World" printf("Concatenated: %s\n", amxc_var_constcast(cstring_t, &str1)); // Integer addition amxc_var_t num1, num2; amxc_var_init(&num1); amxc_var_init(&num2); amxc_var_set(int32_t, &num1, 10); amxc_var_set(int32_t, &num2, 32); amxc_var_add_value(&num1, &num2); // num1 = 42 printf("Sum: %d\n", amxc_var_constcast(int32_t, &num1)); // Output: Sum: 42 // Compare variants amxc_var_t a, b; amxc_var_init(&a); amxc_var_init(&b); amxc_var_set(int32_t, &a, 10); amxc_var_set(int32_t, &b, 20); int result; amxc_var_compare(&a, &b, &result); printf("Compare: %d (a %s b)\n", result, result < 0 ? "<" : (result > 0 ? ">" : "==")); // Output: Compare: -1 (a < b) // Cleanup amxc_var_clean(&src); amxc_var_clean(&dest); amxc_var_clean(&list1); amxc_var_clean(&list2); amxc_var_clean(&str1); amxc_var_clean(&str2); amxc_var_clean(&num1); amxc_var_clean(&num2); amxc_var_clean(&a); amxc_var_clean(&b); return 0; } ``` -------------------------------- ### Setting Variant Values Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Macro for setting primitive values into a variant structure. ```APIDOC ## Macro: amxc_var_set ### Description Sets a primitive value into a variant. The macro automatically selects the appropriate setter function based on the provided type name. ### Usage amxc_var_set(type_name, &var, value); ### Parameters - **type_name** (identifier) - Required - The name of the type (e.g., cstring_t, int32_t). - **var** (amxc_var_t*) - Required - Pointer to the variant. - **value** (any) - Required - The value to assign. ``` -------------------------------- ### Add user to variant list Source: https://gitlab.com/prpl-foundation/components/ambiorix/libraries/libamxc/-/blob/main/doc/variant.md Function to add a user as a hash table variant within a list variant. ```C void add_user(amxc_var_t *users, uint32_t user_id, const char *name, uint32_t access_rights) { amxc_var_t *user = amxc_var_add(amxc_htable_t, users, NULL); amxc_var_add_key(uint32_t, user, "user_id", user_id); amxc_var_add_key(cstring_t, user, "name", name); amxc_var_add_key(uint32_t, user, "access_rights", access_rights); } ```