{"id":15048931,"url":"https://github.com/barrust/c-utils","last_synced_at":"2025-04-09T12:08:07.723Z","repository":{"id":41081577,"uuid":"223326680","full_name":"barrust/c-utils","owner":"barrust","description":"C utility libraries","archived":false,"fork":false,"pushed_at":"2024-12-21T22:09:53.000Z","size":273,"stargazers_count":72,"open_issues_count":1,"forks_count":13,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-02T11:01:40.453Z","etag":null,"topics":["bitarray","c-language","c-programming","c-string","doublylinkedlist","fileutils","graph","minunit","permutations","stack","string-manipulation","stringlib","timing","unit-testing-framework","utilities"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/barrust.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-22T04:59:06.000Z","updated_at":"2025-03-27T15:10:05.000Z","dependencies_parsed_at":"2025-01-16T01:10:29.213Z","dependency_job_id":"b4058cfe-482c-43f8-9128-fe6d116591c0","html_url":"https://github.com/barrust/c-utils","commit_stats":{"total_commits":78,"total_committers":1,"mean_commits":78.0,"dds":0.0,"last_synced_commit":"7a68ea75a7ee9c3208dd0b0a44e10e993c3c79c9"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/barrust%2Fc-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/barrust%2Fc-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/barrust%2Fc-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/barrust%2Fc-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/barrust","download_url":"https://codeload.github.com/barrust/c-utils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248036067,"owners_count":21037092,"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","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":["bitarray","c-language","c-programming","c-string","doublylinkedlist","fileutils","graph","minunit","permutations","stack","string-manipulation","stringlib","timing","unit-testing-framework","utilities"],"created_at":"2024-09-24T21:17:13.968Z","updated_at":"2025-04-09T12:08:07.706Z","avatar_url":"https://github.com/barrust.png","language":"C","readme":"# c-utils\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![GitHub release](https://img.shields.io/github/release/barrust/c-utils.svg)](https://github.com/barrust/c-utils/releases)\n[![C/C++ CI](https://github.com/barrust/c-utils/workflows/C/C++%20CI/badge.svg?branch=master)](https://github.com/barrust/c-utils/actions)\n[![codecov](https://codecov.io/gh/barrust/c-utils/branch/master/graph/badge.svg)](https://codecov.io/gh/barrust/c-utils)\n\n\nThis project provides a collection of utility libraries to help reduce the need to write similar code for each project on an ad-hoc basis. The need is based on what I have needed in most projects but are ended up written, as needed, and usually differently each time and without unit tests. The goal is to provide a single place to store each of these libraries and to provide unit tests.\n\nIf there are other commonly used code or data-structures that should be added, please add a feature request!\n\n##### Table of Contents:\n* [stringlib](#stringlib) - C-string utilities\n* [fileutils](#fileutils) - File system utilities\n* [bitarray](#bitarray)\n* [linked list](#linkedlist)\n* [doubly linked list](#doublylinkedlist)\n* [stack](#stack)\n* [queue](#queue)\n* [graph](#graph)\n* [permutations](#permutations)\n* [timing-c](#timing-c) - Code timing utility\n* [minunit](#minunit) - Unit testing\n\n##### Recommended External Libraries\n* [set](https://github.com/barrust/set)\n* [hashmap](https://github.com/barrust/hashmap)\n* [bloom filter](https://github.com/barrust/bloom)\n* [kseq](https://github.com/lh3/readfq) - A fasta/fastq parser library\n* [utf-8](https://github.com/sheredom/utf8.h) - Single header UTF-8 string functions for C and C++\n\n\n##### Unit tests\n\nUnit tests are provided using the [minunit](#minunit) library. Each function is, **hopefully**, fully covered. Any help in getting as close to 100% coverage would be much appreciated!\n\nTo run the unit-test suite, simply compile the test files using the provided `Makefile` with the command `make test`. Then you can execute the tests using the executables `./dist/bitarray`, `./dist/strlib`, `./dist/fileutils`, `./dist/graph`, `./dist/llist`, `./dist/dllist`, `./dist/stack`, `./dist/queue`, `./dist/permutations`, `./dist/minunit`, or `./dist/timing`.\n\n#### Issues\n\nIf an unexpected outcome occurs, please submit an [issue on github](https://github.com/barrust/c-utils/issues). Please also provide a ***minimal code example*** that encapsulates the error.\n\nA great [issue](https://github.com/barrust/c-utils/issues) would provide the following:\n\u003e s_remove_unwanted_chars shows duplicate entries after removal.\n\u003e ``` c\n\u003e char test[] = \"This is a test\";\n\u003e // expect \"Ths s a es\"\n\u003e // get \"Ths s a esest\"\n\u003e // Notice the extra `est`; likely due to not erasing the trailing chars\n\u003e s_remove_unwanted_chars(test, \"ti\");  \n\u003e ```\n\n#### Examples\n\nExample programs are provided in the `./examples` folder. You can compile these examples using `make examples`. They can be run from the `./dist` folder and are named prepended with `ex_`.\n\nNot all functionality is demonstrated for all libraries, but hopefully enough is present to help make using these libraries easier. All functionality for each library is documented in the `.h` files.\n\n\n## stringlib\n\nA collection of `c-string` functions that I find myself writing for many of my projects. This library provides a single place to store this functionality while ensuring that everything is as minimalistic as possible. In most cases, the string is modified in place. No additional structs are needed as it uses vanilla `c-strings` everywhere.\n\nThose functions that have a `const char*` do not modify the string!\n\nDocumentation of each function is found in the `stringlib.h` file.\n\n#### Compiler Flags\n\n***NONE*** - There are no needed compiler flags for the `stringlib` library\n\n#### Usage\n\nTo use, copy the `stringlib.h` and `stringlib.c` files into your project folder and add them to your project.\n\n``` c\n#include \"stringlib.h\"\n\nchar str[] = \"   This is a \\t horrible \\n\\r string \\f  to\\n clean up... please help!\\n\\r\";\n// we can trim and stanardize whitespaces to a single whitespace\ns_single_space(str); // \"This is a horrible string to clean up... please help!\"\n\n// find the first `u`\nint pos = s_find(str, 'u'); // 35\n// find the first `ri`\npos = s_find_str(str, \"ri\"); // 13\n// find the last `ri`\npos = s_find_str_reverse(str, \"ri\"); // 21\n\n// remove unwanted characters\ns_remove_unwanted_chars(str, \"tph\"); // \"Tis is a orrible sring o clean u... lease el!\"\n```\n\n\n## fileutils\n\nThe file utils library provides utility functions to deal with basic file system operations. From determining if a file exists, to making directories, to reading in a file and parsing out the lines.\n\nAll functions are documented within the `fileutils.h` file.\n\nUnfortunately, I have not been able to test this library on Windows machines. If errors arise on Windows, please submit an issue or, even better, a ***pull request***! If something is shown to work on Windows, that information would also be very helpful!\n\n#### Compiler Flags\n\n***NONE*** - There are no needed compiler flags for the `fileutils` library\n\n#### Usage\n\nTo use, copy the `fileutils.h` and `fileutils.c` files into your project folder and add them to your project.\n\n``` c\n#include \"fileutils.h\"\n\nint res;\n\n/* General path / file functionality */\nchar* current_working_directory = fs_cwd();\nfs_mkdir(\"path_of_new_dir\", false);  /* do not recursively make the dirs */\n\n/* if the unknown path is a file, remove it! */\nif (fs_identify_path(\"unknown_path\") == FS_FILE) {\n    fs_remove_file(\"unkown_path\");\n}\n\nif (fs_rmdir_alt(\"path_to_non_empty_directory\", true) == FS_NO_EXISTS) {\n    printf(\"Successfully removed the directory and all sub directories and files!\");\n}\n\n/* parse and read a file */\nfile_t f = f_init(\"path_to_file\");\nprintf(\"Base dir: %s\\n\", f_basedir(f));\nprintf(\"Filename: %s\\n\", f_filename(f));\nprintf(\"Extension: %s\\n\", f_extension(f));\nprintf(\"File Size: %llu\\n\", f_filesize(f));\n/* read the file contents into a buffer */\nf_read_file(f);\n/* parse the file into lines */\nf_parse_lines(f);\n\nf_free(f);\n```\n\n\n## bitarray\n\nThe bit array library is provided to allow for a drop in bit array. It uses the smallest binary size possible for the array (`char`) to reduce the few extra bits needed compared to using an int (8 bits per element vs 32). It also tracks how many bits were desired and how many elements were used to hold the bit array.\n\n#### Compiler Flags\n\n***NONE*** - There are no needed compiler flags for the `bitarray` library\n\n#### Usage\n\nTo use, copy the `bitarray.h` and `bitarray.c` files into your project folder and add them to your project.\n\n``` c\n#include \"bitarray.h\"\n\nbitarray_t ba = ba_init(20000000);  // we want to track 20,000,000 items!\n\nfor (int i = 0; i \u003c 20000000; i++) {\n    if (i % 5 == 0)  // whatever makes us want to set track this element\n        ba_set_bit(ba, i);\n}\n\n// we can check bits easily!\nif (ba_check_bit(ba, 10000000) == BIT_SET)\n    printf(\"Bit 10,000,000 is set!\\n\");\nelse\n    printf(\"Bit 10,000,000 is not set!\\n\");\n\n// we can also clear a single bit or reset the whole array\nba_clear_bit(ba, 10000000); // a check would now be BIT_NOT_SET\n\nba_reset_bitarray(ba); // all the bits are set to 0\n\n// free all the memory!\nba_free(ba);\n```\n\n\n## linkedlist\n\nThis library adds a generic linked list implementation. Any type of data can be added to the list as the data type of the data is `void*`. Elements can be added or removed to the end or any location within the list. If you have fewer access and removal needs it may be better to use a [stack](#stack) which provides the same structure.\n\nAll functions are documented within the `llist.h` file.\n\n#### Compiler Flags\n\n***NONE*** - There are no needed compiler flags for the `linked list` library\n\n#### Usage\n\nTo use, simply copy the `llist.h` and `llist.c` files into your project and include it where needed.\n\n``` c\n#include \"llist.h\"\n\nllist_t l = ll_init();\n\nint* get_random() {\n    int* t = calloc(1, sizeof(int));\n    *t = rand() % 100000;\n    return t;\n}\n\nint i;\nfor (i = 0; i \u003c 1000; i++) {\n    int* t = get_random();\n    ll_append(l, t);\n}\n\ni = 0;\nll_node node;\nll_traverse(l, node) {\n    int val = *(int*)node-\u003edata;\n    printf(\"idx: %d\\tval: %d\\n\", i++, val);\n}\n\n// or iterate the old fashion way\nnode = ll_first_node(l);\nwhile (node != NULL) {\n    int val = *(int*)node-\u003edata;\n    printf(\"idx: %d\\tval: %d\\n\", i++, val);\n    node = node-\u003enext;\n}\n\nll_free_alt(l, true); // even free the data field\n```\n\n\n## doublylinkedlist\n\nThis library adds a generic doubly linked list implementation. Any type of data can be added to the list as the data type of the data is `void*`. Elements can be added or removed to the end or any location within the list. This is useful when you need to control where nodes are inserted and the order that they are removed. If you have fewer access and removal needs it may be better to use a [queue](#queue) which provides the same structure.\n\nAll functions are documented within the `dllist.h` file.\n\n#### Compiler Flags\n\n***NONE*** - There are no needed compiler flags for the `doubly linked list` library\n\n#### Usage\n\nTo use, simply copy the `dllist.h` and `dllist.c` files into your project and include it where needed.\n\n``` c\n#include \"dllist.h\"\n\ndllist_t l = dll_init();\n\nint* get_random() {\n    int* t = calloc(1, sizeof(int));\n    *t = rand() % 100000;\n    return t;\n}\n\nint i;\nfor (i = 0; i \u003c 1000; i++) {\n    int* t = get_random();\n    dll_append(l, t);\n}\n\ni = 0;\ndll_node node;\ndll_traverse(l, node) {\n    int val = *(int*)node-\u003edata;\n    printf(\"idx: %d\\tval: %d\\n\", i++, val);\n}\n\n// or iterate the old fashion way in reverse (or dll_reverse_traverse)\nnode = dll_last_node(l);\nwhile (node != NULL) {\n    int val = *(int*)node-\u003edata;\n    printf(\"idx: %d\\tval: %d\\n\", i++, val);\n    node = node-\u003eprev;\n}\n\ndll_free_alt(l, true); // even free the data field\n```\n\n## stack\n\nBuilt using the linked list code, this provides a special implementation of a linked list that always inserts and removes the first element in the linked list. This is useful in instances that there is no need for arbitrary insertion and removal locations from the linked list. As such, this version can be slightly faster than a linked list since insertion is constant.\n\nAll functions are documented within the `stack.h` file.\n\n#### Compiler Flags\n\n***NONE*** - There are no needed compiler flags for the `stack` library\n\n#### Usage\n\nTo use, simply copy the `stack.h` and `stack.c` files into your project and include it where needed.\n\n``` c\n#include \"stack.h\"\n\nstack_list_t stk = stk_init();\n\nint* get_random() {\n    int* t = calloc(1, sizeof(int));\n    *t = rand() % 100000;\n    return t;\n}\n\nint i;\nfor (i = 0; i \u003c 1000; i++) {\n    int* t = get_random();\n    stk_push(stk, t);\n}\n\nint* val = (int*) stk_pop(stk);  // this will be the last item pushed on the stack!\n```\n\n## queue\n\nBuilt using the doubly linked list code, this provides a special implementation of a doubly linked list that always inserts at the end of the list and always removes the first element. This is useful in instances that there is no need for arbitrary insertion and removal locations from the linked list but you want to either be able to access all nodes from both directions or you want to maintain a FIFO (first in first out) approach. As such, this version can be slightly faster than a doubly linked list since insertion and deletion are constant.\n\nAll functions are documented within the `queue.h` file.\n\n#### Compiler Flags\n\n***NONE*** - There are no needed compiler flags for the `queue` library\n\n#### Usage\n\nTo use, simply copy the `queue.h` and `queue.c` files into your project and include it where needed.\n\n``` c\n#include \"queue.h\"\n\nqueue_list_t q = q_init();\n\nint* get_random() {\n    int* t = calloc(1, sizeof(int));\n    *int = rand() % 100000;\n    return t;\n}\n\nint i;\nfor (i = 0; i \u003c 1000; i++) {\n    int* t = get_random();\n    q_push(q, t);\n}\n\nint* val = (int*) q_pop(q);  // this will be the first item pushed on the queue!\n```\n\n## graph\n\nThis library adds a directed graph implementation that allows for any data type to be used for vertex or edge metadata. It tracks all the vertices and edges inserted into the graph and helps ensure that there are no dangling edges.\n\nThere are several ways to traverse the graph or to easily loop over vertices and edges. Macros are provided to allow for iterating over vertices or over the edges that emanate from the vertex: `g_iterate_vertices` and `g_iterate_edges`. There are also to helper functions to do either a breadth first or depth first traverse starting from a particular vertex: `g_breadth_first_traverse` and `g_depth_first_traverse`.\n\nAll functions are documented within the `graph.h` file.\n\n#### Compiler Flags\n\n***NONE*** - There are no needed compiler flags for the `graph` library\n\n#### Usage\n\nTo use, simply copy the `graph.h` and `graph.c` files into your project and include it where needed.\n\n``` c\n#include \"graph.h\"\n\ngraph_t g = g_init();\n\n// add some verticies\ng_vertex_add(g, \"Washington D.C.\");\ng_vertex_add(g, \"Raleigh NC\");\ng_vertex_add(g, \"Boston, Mass\");\ng_vertex_add(g, \"Cincinati, OH\");\n\n// add edges\ng_edge_add(g, 0, 1, \"250 miles\"); // washington to raliegh\ng_edge_add(g, 0, 2, \"150 miles\"); // washington to boston\ng_edge_add(g, 0, 3, \"300 miles\"); // washington to cincinati\ng_edge_add(g, 1, 3, \"500 miles\"); // raliegh to cincinati\ng_edge_add(g, 2, 3, \"400 miles\"); // boston to cincinati\n\n// iterate over the verticies\nvertex_t v;\nunsigned int i, j;\ng_iterate_vertices(g, v, i) {\n    printf(\"idx: %d\\tcity: %s\\n\", i, g_vertex_metadata(v));\n\n    // iterate over the edges!\n    edge_t e;\n    g_iterate_edges(v, e, j) {\n        vertex_t dest = g_vertex_get(g_edge_dest(e));\n        printf(\"\\tto: %s\\tdistance: %s\\n\", g_vertex_metadata(dest), g_edge_metadata(e));\n    }\n}\n\ng_free_alt(g, false);\n```\n\n## permutations\n\nThere are times when one needs to run over all (most?) of the permutations of a set of characters, or numbers. This library allows the user to pass initialize a permutation list and give it a length and an alphabet and get the permutations as needed such as to check for all possible k-mers in a genome, among other uses!\n\n#### Compiler Flags\n\n***NONE*** - There are no needed compiler flags for the `permutations` library\n\n#### Usage\n\nTo use, simply copy the `permutations.h` and `permutations.c` files into your project and include it where needed.\n\n``` c\n#include \"permutations.h\"\n\npermutations_t p = perm_init(5, \"ATCG\");\n\n// number permutations is alphabet length raised to the input length\nfor (unsigned int i = 0; i \u003c 1024; ++i) {\n    perm_inc(p);\n    // do something with the new permutation\n    printf(\"%s\\n\", perm_to_string(p));\n}\nperm_free(p);\n```\n\n\n## timing-c\n\nThis header utility is to be able to quickly provide timing functionality to standard `C` code. It is designed to be beneficial to me as I am tired of re-writting the same type of functionality. To use, simply copy the header into your project folder.\n\n#### Compiler Flags\n\n***NONE*** - There are no needed compiler flags for the `timing.h` library\n\n#### Usage\n\nTo use, simply copy the `timing.h` file into your project and include it where needed.\n\n``` c\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n#include \"timing.h\"\n\nTiming t;\n\ntiming_start(\u0026t);\n// code to time here\ntiming_end(\u0026t);\nprintf(\"time elapsed: %f\\n\", t.timing_double);\n\n// get to elapsed time elements easily\nprintf(\"hours:        %d\\n\", timing_get_hours(t));\nprintf(\"minutes:      %d\\n\", timing_get_minutes(t));\nprintf(\"seconds:      %d\\n\", timing_get_seconds(t));\nprintf(\"milliseconds: %d\\n\", timing_get_milliseconds(t));\nprintf(\"microseconds: %d\\n\", timing_get_microseconds(t));\n\n// get to a pretty print version\nchar* output = format_time_diff(\u0026t);\nprintf(\"pretty output: %s\\n\", output);\nfree(output);\n```\n\n## minunit\n\nThis header utility is a testing framework for C programs. It is a fork of [siu/mununit](https://github.com/siu/minunit) that adds several assertions that are not in the base library. License ([MIT](https://github.com/siu/minunit/blob/master/MIT-LICENSE.txt)) information is contained in the header file.\n\n### Compiler Flags\n\n***NONE*** - There are no needed compiler flags for the `minunit.h` testing framework.\n\n### Usage\n\nFor full examples, please view the tests in the `./test` folder. A quick run down of setting up the tests is provided below along with a quick set of function documentation.\n\n``` c\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n#include \u003cminunit.h\u003e\n\nint arr[25];\n\nvoid test_setup(void) {\n    for (int i = 0; i \u003c 25; ++i)\n        arr[i] = i;\n}\n\nvoid test_teardown(void) {\n    // no teardown required\n}\n\nMU_TEST(test_simple) {\n    mu_assert_int_eq(0, arr[0]);\n}\n\n// Set up the test suite by configuring and stating which tests should be run\nMU_TEST_SUITE(test_suite) {\n    MU_SUITE_CONFIGURE(\u0026test_setup, \u0026test_teardown);\n\n    MU_RUN_TEST(test_simple);\n}\n\nint main() {\n    MU_RUN_SUITE(test_suite);\n    MU_REPORT();\n    printf(\"Number failed tests: %d\\n\", minunit_fail);\n    return minunit_fail;\n}\n```\n\n### Documentation\n\n* **mu_check(test)**: Checks to verify that the passed boolean expression test is `true`; fails otherwise.\n* **mu_fail(message)**: Automatically fails the assertion and returns the provided message; useful for non-implemented features, etc.\n* **mu_assert(test, message)**: Assert that the boolean expression `test` is true, otherwise fail and print the passed `message`.\n* **mu_assert_int_eq(expected, result)**: Assert that the `expected` int is the same as the passed `result`.\n* **mu_assert_int_not_eq(expected, result)**: Assert that the `result` does not equal `expected`; not this is useful for checking comparison functions, etc.\n* **mu_assert_int_greater_than(val, result)**: Assert that `result` is greater than `val`.\n* **mu_assert_int_less_than(val, result)**:  Assert that `result` is less than `val`.\n* **mu_assert_int_between(expected_lower, expected_upper, result)**: Assert that the `result` is between (inclusive) `expected_lower` and `expected_upper`; if upper and lower are reversed, then it is **not** between!\n* **mu_assert_int_in(expected, array_length, result)**: Assert that the `result` is a member of the `expected` array; `array_length` is needed to know the number of elements in the array.\n* **mu_assert_double_eq(expected, result)**: Assert that the double in `result` is the same as the `expected` double.\n* **mu_assert_double_greater_than(val, result)**: Assert that `result` is greater than `val`.\n* **mu_assert_double_less_than(val, result)**:  Assert that `result` is less than `val`.\n* **mu_assert_double_between(expected_lower, expected_upper, result)**: Assert that `result` is between (inclusive) `expected_lower` and `expected_upper`; if upper and lower are reversed, then it is **not** between!\n* **mu_assert_string_eq(expected, result)**: Assert that the `result` string (char* or char[]) is the same as the `expected` string.\n* **mu_assert_null(result)**: Assert that the passed `result` pointer is `NULL`.\n* **mu_assert_not_null(result)**: Assert that the passed `result` pointer is not `NULL`.\n* **mu_assert_pointers_eq(pointer1, pointer2)**: Assert that `pointer1` and `pointer2` point to the same memory location.\n* **mu_assert_pointers_not_eq(pointer1, pointer2)**: Assert that `pointer1` and `pointer2` do not point to the same memory location.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbarrust%2Fc-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbarrust%2Fc-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbarrust%2Fc-utils/lists"}