{"id":13544513,"url":"https://github.com/DanielGibson/Snippets","last_synced_at":"2025-04-02T14:31:22.532Z","repository":{"id":29962636,"uuid":"33509449","full_name":"DanielGibson/Snippets","owner":"DanielGibson","description":"(Hopefully) useful code snippets and header-only libs","archived":false,"fork":false,"pushed_at":"2024-05-01T04:08:27.000Z","size":93,"stargazers_count":182,"open_issues_count":1,"forks_count":15,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-05-22T00:15:24.820Z","etag":null,"topics":["c","dynamic-array","header-only","imageloader","public-domain","sdl2","single-header-lib","standalone-library","string-manipulation"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DanielGibson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2015-04-06T22:35:58.000Z","updated_at":"2024-06-06T20:00:24.415Z","dependencies_parsed_at":"2024-06-06T20:00:18.320Z","dependency_job_id":null,"html_url":"https://github.com/DanielGibson/Snippets","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielGibson%2FSnippets","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielGibson%2FSnippets/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielGibson%2FSnippets/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielGibson%2FSnippets/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DanielGibson","download_url":"https://codeload.github.com/DanielGibson/Snippets/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246832260,"owners_count":20841143,"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":["c","dynamic-array","header-only","imageloader","public-domain","sdl2","single-header-lib","standalone-library","string-manipulation"],"created_at":"2024-08-01T11:00:50.414Z","updated_at":"2025-04-02T14:31:17.523Z","avatar_url":"https://github.com/DanielGibson.png","language":"C++","readme":"# Snippets\n\nSome standalone source files that don't deserve their own repositories.\n\n| File                          | Description    |\n|-------------------------------|----------------|\n| [**DG_misc.h**](/DG_misc.h) | A public domain single-header C/C++ library with some useful functions to get the path/dir/name of the current executable and misc. string operations that are not available on all platforms - [***List of Functions***]( #list-of-functions-in-dg_misch) |\n| [**DG_dynarr.h**](/DG_dynarr.h) | A public domain single-header library providing typesafe dynamic arrays for *plain C*, kinda like C++ std::vector (works with C++, but only with \"simple\" types) - [***Usage Example and List of Functions***]( #example-and-list-of-functions-for-dg_dynarrh) |\n| [**imgui_keybindmenu.cpp**](/imgui_keybindmenu.cpp) | Example/prototype/demo of a keybinding menu using [Dear ImGui](https://github.com/ocornut/imgui/), meant to be merged into games and similar software that use Dear ImGui. Released under MIT License, like Dear ImGui. |\n| [**imgui_savestyle.cpp**](/imgui_savestyle.cpp) | Addon code for [Dear ImGui](https://github.com/ocornut/imgui/) that reads and writes styles (ImGuiStyle) to .ini-like textfiles, or generates C++ code for them. Released under MIT License, like Dear ImGui. |\n| [**SDL_stbimage.h**](/SDL_stbimage.h) | A public domain header-only C/C++ library for converting images to [SDL2](http://libsdl.org) `SDL_Surface*` using [stb_image.h](https://github.com/nothings/stb) - [***List of Functions***]( #list-of-functions-in-sdl_stbimageh) |\n| [**sdl2_scancode_to_dinput.h**](/sdl2_scancode_to_dinput.h) | One static C array that maps SDL2 scancodes to Direct Input keynums (values of those DIK_* constants) - also public domain. |\n| [**ImgToC.c**](/ImgToC.c) | Commandline tool converting images to .c files with a struct containing the image data. Same format as Gimp's \"Export as .c\" feature. Needs [stb_image.h](https://github.com/nothings/stb/) |\n\n## List of functions in [**DG_misc.h**](/DG_misc.h)\n\nThe \"DG_\" prefix is not just to please my big ego, but mostly to (hopefully) avoid name collisions.\n\nThe `DG_GetExecutable*()` functions have been tested on Linux, Windows and FreeBSD.  \nThey *should* also work with NetBSD, OpenBSD and Mac OS X (not sure what they do with .app bundles, though).  \nAdding more platforms shouldn't be hard, patches/pull requests are welcome :-)\n\n```c\n// get full path to your executable, including the executable itself\nconst char* DG_GetExecutablePath(void);\n\n// get full path to the directory your executable is in, without executable itself\nconst char* DG_GetExecutableDir(void);\n\n// get filename of the executable, without the path\nconst char* DG_GetExecutableFilename(void);\n\n// copy up to n chars of str into a new string, guaranteed to be'\\0'-terminated.\nchar* DG_strndup(const char* str, size_t n);\n\n// copies up to dstsize-1 bytes from src to dst and ensures '\\0' termination\nsize_t DG_strlcpy(char* dst, const char* src, size_t dstsize);\n\n// appends src to the existing null-terminated(!) string in dst\nsize_t DG_strlcat(char* dst, const char* src, size_t dstsize);\n\n// See also https://www.freebsd.org/cgi/man.cgi?query=strlcpy\u0026sektion=3\n// for details on strlcpy() and strlcat().\n\n// search for needle in haystack, like strstr(), but for binary data.\nvoid* DG_memmem(const void* haystack, size_t haystacklen,\n                const void* needle, size_t needlelen);\n\n// search for last occurence of needle in haystack, like DG_memmem() but backwards.\nvoid* DG_memrmem(const void* haystack, size_t haystacklen,\n                 const void* needle, size_t needlelen);\n\n// returns the last occurence byte c in buf. Like strrchr() for binary data.\nvoid* DG_memrchr(const void* buf, unsigned char c, size_t buflen);\n\n// search for last occurence of needle in haystack, like strstr() but backwards.\n// also like DG_memrmem(), but for '\\0'-terminated strings.\n// returns the address of the last match, or NULL if it wasn't found\nchar* DG_strrstr(const char* haystack, const char* needle);\n\n// reentrant (threadsafe) version of strtok(), saves its progress into context.\nchar* DG_strtok_r(char* str, const char* delim, char** context);\n\n// returns the length of the '\\0'-terminated string s.\n// might be faster than default strnlen(), otherwise it will use default strnlen()\nsize_t DG_strnlen(const char* s, size_t n);\n\n// calculates length of s. might be faster than default strlen()\n// (otherwise it will use default strlen)\nsize_t DG_strlen(const char* s);\n\n// a snprintf() implementation that is conformant to C99 by ensuring\n// '\\0'-termination of dst and returning the number of chars (without\n// terminating '\\0') that would've been written to a big enough buffer\n// (for non-windows platforms it's just a #define to snprintf())\nint DG_snprintf(char *dst, size_t size, const char *format, ...);\n\n// the same for vsnprintf() (only enabled if you #include \u003cstdarg.h\u003e first!)\nint DG_vsnprintf(char *dst, size_t size, const char *format, va_list ap);\n```\n\n## List of functions in [**SDL_stbimage.h**](/SDL_stbimage.h)\n\n```c\n// loads the image file at the given path into a RGB(A) SDL_Surface\n// Returns NULL on error, use SDL_GetError() to get more information.\nSDL_Surface* STBIMG_Load(const char* file);\n\n// loads the image file in the given memory buffer into a RGB(A) SDL_Surface\n// Returns NULL on error, use SDL_GetError() to get more information.\nSDL_Surface* STBIMG_LoadFromMemory(const unsigned char* buffer, int length);\n\n// loads an image file into a RGB(A) SDL_Surface from a seekable SDL_RWops (src)\n// if you set freesrc to non-zero, SDL_RWclose(src) will be executed after reading.\n// Returns NULL on error, use SDL_GetError() to get more information.\nSDL_Surface* STBIMG_Load_RW(SDL_RWops* src, int freesrc);\n\n\n//   If you're gonna use SDL_Renderer, the following convenience functions\n//   create SDL_Texture directly\n\n// loads the image file at the given path into a RGB(A) SDL_Texture\n// Returns NULL on error, use SDL_GetError() to get more information.\nSDL_Texture* STBIMG_LoadTexture(SDL_Renderer* renderer, const char* file);\n\n// loads the image file in the given memory buffer into a RGB(A) SDL_Texture\n// Returns NULL on error, use SDL_GetError() to get more information.\nSDL_Texture*\nSTBIMG_LoadTextureFromMemory(SDL_Renderer* renderer, const unsigned char* buffer, int length);\n\n// loads an image file into a RGB(A) SDL_Texture from a seekable SDL_RWops (src)\n// if you set freesrc to non-zero, SDL_RWclose(src) will be executed after reading.\n// Returns NULL on error, use SDL_GetError() to get more information.\nSDL_Texture* STBIMG_LoadTexture_RW(SDL_Renderer* renderer, SDL_RWops* src, int freesrc);\n\n\n\n// Creates an SDL_Surface* using the raw RGB(A) pixelData with given width/height\n// (this doesn't use stb_image and is just a simple SDL_CreateSurfaceFrom()-wrapper)\n// ! It must be byte-wise 24bit RGB (\"888\", bytesPerPixel=3) !\n// !  or byte-wise 32bit RGBA (\"8888\", bytesPerPixel=4) data !\n// If freeWithSurface is SDL_TRUE, SDL_FreeSurface() will free the pixelData\n//  you passed with SDL_free() - NOTE that you should only do that if pixelData\n//  was allocated with SDL_malloc(), SDL_calloc() or SDL_realloc()!\n// Returns NULL on error (in that case pixelData won't be freed!),\n//  use SDL_GetError() to get more information.\nSDL_Surface* STBIMG_CreateSurface(unsigned char* pixelData, int width, int height,\n                                  int bytesPerPixel, SDL_bool freeWithSurface);\n\n// Creates an SDL_Texture* using the raw RGB(A) pixelData with given width/height\n// (this doesn't use stb_image and is just a simple SDL_CreateSurfaceFrom()-wrapper)\n// ! It must be byte-wise 24bit RGB (\"888\", bytesPerPixel=3) !\n// !  or byte-wise 32bit RGBA (\"8888\", bytesPerPixel=4) data !\n// Returns NULL on error, use SDL_GetError() to get more information.\nSDL_Texture* STBIMG_CreateTexture(SDL_Renderer* renderer, const unsigned char* pixelData,\n                                  int width, int height, int bytesPerPixel);\n\n\n// creates stbi_io_callbacks and userdata to use stbi_*_from_callbacks() directly,\n//  especially useful to use SDL_RWops with stb_image, without using SDL_Surface\n// src must be readable and seekable!\n// Returns SDL_FALSE on error (SDL_GetError() will give you info), else SDL_TRUE\n// NOTE: If you want to use src twice (e.g. for info and load), remember to rewind\n//       it by seeking back to its initial position and resetting out-\u003eatEOF to 0\n//       inbetween the uses!\nSDL_bool STBIMG_stbi_callback_from_RW(SDL_RWops* src, STBIMG_stbio_RWops* out);\n\ntypedef struct {\n\tSDL_RWops* src;\n\tstbi_io_callbacks stb_cbs;\n\tint atEOF; // defaults to 0; 1: reached EOF or error on read, 2: error on seek\n} STBIMG_stbio_RWops;\n```\n\n## Example and List of functions for [**DG_dynarr.h**](/DG_dynarr.h)\n\n### Usage Example\n\n```c\n#define DG_DYNARR_IMPLEMENTATION // this define is only needed in *one* .c/.cpp file!\n#include \"DG_dynarr.h\"\n\nDA_TYPEDEF(int, MyIntArrType); // creates MyIntArrType - a dynamic array for ints\n\nvoid printIntArr(MyIntArrType* arr, const char* name)\n{\n    // note that arr is a pointer here, so use *arr in the da_*() functions.\n    printf(\"%s = {\", name);\n    if(da_count(*arr) \u003e 0)\n        printf(\" %d\", arr-\u003ep[0]);\n    for(int i=1; i\u003cda_count(*arr); ++i)\n        printf(\", %d\", arr-\u003ep[i]);\n    printf(\" }\\n\");\n}\n\nvoid myFunction()\n{\n    MyIntArrType a1 = {0}; // make sure to zero out the struct\n    // instead of = {0}; you could also call da_init(a1);\n\n    da_push(a1, 42);\n    assert(da_count(a1) == 1 \u0026\u0026 a1.p[0] == 42);\n\n    int* addedElements = da_addn_uninit(a1, 3);\n    assert(da_count(a1) == 4);\n    for(size_t i=0; i\u003c3; ++i)\n        addedElements[i] = i+5;\n\n    printIntArr(\u0026a1, \"a1\"); // \"a1 = { 42, 5, 6, 7 }\"\n\n    MyIntArrType a2;\n    da_init(a2);\n\n    da_addn(a2, a1.p, da_count(a1)); // copy all elements from a1 to a2\n    assert(da_count(a2) == 4);\n\n    da_insert(a2, 1, 11);\n    printIntArr(\u0026a2, \"a2\"); // \"a2 = { 42, 11, 5, 6, 7 }\"\n\n    da_delete(a2, 2);\n    printIntArr(\u0026a2, \"a2\"); // \"a2 = { 42, 11, 6, 7 }\"\n\n    da_deletefast(a2, 0);\n    printIntArr(\u0026a2, \"a2\"); // \"a2 = { 7, 11, 6 }\"\n\n    da_push(a1, 3);\n    printIntArr(\u0026a1, \"a1\"); // \"a1 = { 42, 5, 6, 7, 3 }\"\n\n    int x=da_pop(a1);\n    printf(\"x = %d\\n\", x);  // \"x = 3\"\n    printIntArr(\u0026a1, \"a1\"); // \"a1 = { 42, 5, 6, 7 }\"\n    \n    da_free(a1); // make sure not to leak memory!\n    da_free(a2);\n}\n```\n\n### List of Functions (macros, really)\n\nNote that for each `da_foo()` function there is a `dg_dynarr_foo()` equivalent\nthat you can use in case the short form name collides with other names your project uses.\n`#define DG_DYNARR_NO_SHORTNAMES` before `#include \"DG_dynarr.h\"` disables the short versions.  \n\nOne thing to keep in mind is that, because of using macros, the arguments to\nthe \"functions\" are usually evaluated more than once, so you should avoid putting\nthings with side effect (like function-calls with side effects or `i++`) into them.\nNotable exceptions are the value arguments (`v`) of `da_push()`, `da_set()`\nand `da_insert()`, so it's still ok to do `da_push(arr, fun_with_sideffects());`\nor `da_insert(a, 3, x++);`.\n\nThis library is inteded to be used with ***plain C*** code, but it also works with *C++*; however you\nshould only use it with \"simple\" types that can be moved around with `memcpy()`, i.e. don't\nrequire copy- or move-constructors or destructors to work correctly.\nSo if you're writing C code that should also compile as C++ use this, but if you're\nwriting \"real\" C++ code, use `std::vector` or something else instead.\n\nFurthermore, by default some sanity checks (like \"is idx valid?\") are done using\nassertions and by returning NULL/doing nothing on error if possible.  \nAs this has some overhead, the behavior can be controlled with\n`#define DG_DYNARR_INDEX_CHECK_LEVEL [0-3]`; see [DG_dynarr.h](/DG_dynarr.h) for details.\n\nIn this function reference:\n* `T` refers to the element type of the array (usually used to indicate the return value type of some functions)\n* `a` is always the dynamic array the function should operate on (of a type created with `DA_TYPEDEF`)\n* `v` is always a single value that can be assigned to the array's element type\n* `vals` is an array of values that can be assigned\n* `idx` is always an integer (int, size_t, whatever, but must be `\u003e= 0`) referring to a (0-based) index into the array\n* `n` is always a positive integer, used to specify a number of elements\n\nIn addition to these functions, you can always access the `i`-th element of an\narray `arr` by using `arr.p[i]`.\n\n```c\n// this macro is used to create an array type (struct) for elements of TYPE\n// use like DA_TYPEDEF(int, MyIntArrType); MyIntArrType ia = {0}; da_push(ia, 42); ...\nDA_TYPEDEF(TYPE, NewArrayTypeName)\n\n// makes sure the array is initialized and can be used.\n// either do YourArray arr = {0}; or YourArray arr; da_init(arr);\nvoid da_init(a)\n\n/*\n * This allows you to provide an external buffer that'll be used as long as it's big enough\n * once you add more elements than buf can hold, fresh memory will be allocated on the heap\n * Use like:\n * DA_TYPEDEF(double, MyDoubleArrType);\n * MyDoubleArrType arr;\n * double buf[8];\n * dg_dynarr_init_external(arr, buf, 8);\n * dg_dynarr_push(arr, 1.23);\n * ...\n */\nvoid da_init_external(a, T* buf, size_t buf_cap)\n\n// use this to free the memory allocated by dg_dynarr once you don't need the array anymore\n// Note: it is safe to add new elements to the array after da_free()\n//       it will allocate new memory, just like it would directly after da_init()\nvoid da_free(a)\n\n\n// add an element to the array (appended at the end)\nvoid da_push(a, v)\n\n// same as da_push(), just for consistency with addn (like insert and insertn)\nvoid da_add(a, v)\n\n// append n elements to a and initialize them from array vals, doesn't return anything\n// ! vals (and all other args) are evaluated multiple times !\nvoid da_addn(a, vals, n)\n\n// add n elements to the end of the array and zeroes them with memset()\n// returns pointer to first added element, NULL if out of memory (array is empty then)\nT* da_addn_zeroed(a, n)\n\n// add n elements to the end of the array, will remain uninitialized\n// returns pointer to first added element, NULL if out of memory (array is empty then)\nT* da_addn_uninit(a, n)\n\n\n// insert a single value v at index idx\nvoid da_insert(a, idx, v)\n\n// insert n elements into a at idx, initialize them from array vals\n// doesn't return anything\n// ! vals (and all other args) is evaluated multiple times ! \nvoid da_insertn(a, idx, vals, n)\n\n// insert n elements into a at idx and zeroe them with memset() \n// returns pointer to first inserted element or NULL if out of memory\nT* da_insertn_zeroed(a, idx, n)\n\n// insert n uninitialized elements into a at idx;\n// returns pointer to first inserted element or NULL if out of memory\nT* da_insertn_uninit(a, idx, n) \n\n\n// set a single value v at index idx - like \"a.p[idx] = v;\" but with checks (unless disabled)\nT da_set(a, idx, v)\n\n// overwrite n elements of a, starting at idx, with values from array vals\n// doesn't return anything\n// ! vals (and all other args) is evaluated multiple times ! \nvoid da_setn(a, idx, vals, n)\n\n\n// delete the element at idx, moving all following elements (=\u003e keeps order)\nvoid da_delete(a, idx)\n\n// delete n elements starting at idx, moving all following elements (=\u003e keeps order)\nvoid da_deleten(a, idx, n) \n\n// delete the element at idx, move the last element there (=\u003e doesn't keep order)\nvoid da_deletefast(a, idx)\n\n// delete n elements starting at idx, move the last n elements there (=\u003e doesn't keep order)\nvoid da_deletenfast(a, idx, n)\n\n// removes all elements from the array, but does not free the buffer\n// (if you want to free the buffer too, just use da_free())\nvoid da_clear(a)\n\n// sets the logical number of elements in the array\n// if n \u003e dg_dynarr_count(a), the logical count will be increased accordingly\n// and the new elements will be uninitialized\n// returns new count if successful, else 0\nsize_t da_setcount(a, n)\n\n// make sure the array can store n elements without reallocating\n// logical count remains unchanged\nvoid da_reserve(a, n)\n\n\n// this makes sure a only uses as much memory as for its elements\n// =\u003e maybe useful if a used to contain a huge amount of elements,\n//    but you deleted most of them and want to free some memory\n// Note however that this implies an allocation and copying the remaining\n// elements, so only do this if it frees enough memory to be worthwhile!\nvoid da_shrink_to_fit(a)\n\n// removes and returns the last element of the array\nT da_pop(a)\n\n\n// returns the last element of the array\nT da_last(a)\n\n// returns the pointer *to* the last element of the array\n// (in contrast to dg_dynarr_end() which returns a pointer *after* the last element)\n// returns NULL if array is empty\nT* da_lastptr(a)\n\n// get element at index idx (like a.p[idx]), but with checks\n// (unless you disabled them with #define DG_DYNARR_INDEX_CHECK_LEVEL 0)\nT da_get(a, idx)\n\n// get pointer to element at index idx (like \u0026a.p[idx]), but with checks\n// and it returns NULL if idx is invalid\nT* da_getptr(a, idx)\n\n// returns a pointer to the first element of the array\n// (together with dg_dynarr_end() you can do C++-style iterating)\nT* da_begin(a)\n\n// returns a pointer to the past-the-end element of the array\n// Allows C++-style iterating, in case you're into that kind of thing:\n// for(T *it=da_begin(a), *end=da_end(a); it!=end; ++it) foo(*it);\n// (see da_lastptr() to get a pointer *to* the last element)\nT* da_end(a)\n\n\n// returns (logical) number of elements currently in the array\nsize_t da_count(a)\n\n// get the current reserved capacity of the array\nsize_t da_capacity(a)\n\n// returns 1 if the array is empty, else 0\nbool da_empty(a)\n\n// returns 1 if the last (re)allocation when inserting failed (Out Of Memory)\n//   or if the array has never allocated any memory yet, else 0\n// deleting the contents when growing fails instead of keeping old may seem\n// a bit uncool, but it's simple and OOM should rarely happen on modern systems\n// anyway - after all you need to deplete both RAM and swap/pagefile.sys\nbool da_oom(a)\n\n\n// sort a using the given qsort()-comparator cmp\n// (just a slim wrapper around qsort())\nvoid da_sort(a, cmp)\n```\n","funding_links":[],"categories":["C/C++","Libraries"],"sub_categories":["Libraries"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDanielGibson%2FSnippets","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDanielGibson%2FSnippets","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDanielGibson%2FSnippets/lists"}