From 1034f5e5c4809ea0a7f4387e0cd37c5184de3cdd Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sat, 4 May 2019 08:19:18 -0700 Subject: [PATCH] add stb_include.h --- README.md | 19 +++- stb_include.h | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 302 insertions(+), 5 deletions(-) create mode 100644 stb_include.h diff --git a/README.md b/README.md index 36028a1..ab0fab2 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,14 @@ stb single-file public domain (or MIT licensed) libraries for C/C++ +Noteworthy: + +* image loader: stb_image.h +* image writer: stb_image_write.h +* image resizer: stb_image_resize.h> +* font text rasterizer: stb_truetype.h +* typesafe containers: stb_ds.h + Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, stb_image_resize by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts. @@ -12,7 +20,7 @@ by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts. library | lastest version | category | LoC | description --------------------- | ---- | -------- | --- | -------------------------------- **[stb_vorbis.c](stb_vorbis.c)** | 1.16 | audio | 5486 | decode ogg vorbis files from file/memory to float/16-bit signed output -**[stb_image.h](stb_image.h)** | 2.22 | graphics | 7547 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC +**[stb_image.h](stb_image.h)** | 2.22 | graphics | 7555 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC **[stb_truetype.h](stb_truetype.h)** | 1.21 | graphics | 4882 | parse, decode, and rasterize characters from truetype fonts **[stb_image_write.h](stb_image_write.h)** | 1.13 | graphics | 1622 | image writing to disk: PNG, TGA, BMP **[stb_image_resize.h](stb_image_resize.h)** | 0.96 | graphics | 2630 | resize images larger/smaller with good quality @@ -23,18 +31,19 @@ library | lastest version | category | LoC | description **[stb_textedit.h](stb_textedit.h)** | 1.13 | user interface | 1404 | guts of a text editor for games etc implementing them from scratch **[stb_voxel_render.h](stb_voxel_render.h)** | 0.88 | 3D graphics | 3806 | Minecraft-esque voxel rendering "engine" with many more features **[stb_dxt.h](stb_dxt.h)** | 1.08b | 3D graphics | 728 | Fabian "ryg" Giesen's real-time DXT compressor -**[stb_perlin.h](stb_perlin.h)** | 0.4 | 3D graphics | 366 | revised Perlin noise (3D input, 1D output) +**[stb_perlin.h](stb_perlin.h)** | 0.4 | 3D graphics | 427 | revised Perlin noise (3D input, 1D output) **[stb_easy_font.h](stb_easy_font.h)** | 1.0 | 3D graphics | 303 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc **[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.41 | game dev | 4161 | embeddable tilemap editor **[stb_herringbone_wa...](stb_herringbone_wang_tile.h)** | 0.7 | game dev | 1221 | herringbone Wang tile map generator **[stb_c_lexer.h](stb_c_lexer.h)** | 0.10 | parsing | 964 | simplify writing parsers for C-like languages **[stb_divide.h](stb_divide.h)** | 0.92 | math | 421 | more useful 32-bit modulus e.g. "euclidean divide" **[stb_connected_comp...](stb_connected_components.h)** | 0.96 | misc | 1049 | incrementally compute reachability on grids -**[stb.h](stb.h)** | 2.34 | misc | 14453 | helper functions for C, mostly redundant in C++; basically author's personal stuff +**[stb.h](stb.h)** | 2.34 | misc | 14451 | helper functions for C, mostly redundant in C++; basically author's personal stuff **[stb_leakcheck.h](stb_leakcheck.h)** | 0.5 | misc | 190 | quick-and-dirty malloc/free leak-checking +**[stb_include.h](stb_include.h)** | 0.01 | misc | 288 | implement recursive #include support, particularly for GLSL -Total libraries: 21 -Total lines of C code: 55652 +Total libraries: 22 +Total lines of C code: 56007 FAQ diff --git a/stb_include.h b/stb_include.h new file mode 100644 index 0000000..7bdf7c4 --- /dev/null +++ b/stb_include.h @@ -0,0 +1,288 @@ +// stb_include.h - v0.01 - parse and process #include directives - public domain +// +// To build this, in one source file that includes this file do +// #define STB_INCLUDE_IMPLEMENTATION +// +// This program parses a string and replaces lines of the form +// #include "foo" +// with the contents of a file named "foo". It also embeds the +// appropriate #line directives. Note that all include files must +// reside in the location specified in the path passed to the API; +// it does not check multiple directories. +// +// If the string contains a line of the form +// #inject +// then it will be replaced with the contents of the string 'inject' passed to the API. +// +// Options: +// +// Define STB_INCLUDE_LINE_GLSL to get GLSL-style #line directives +// which use numbers instead of filenames. +// +// Define STB_INCLUDE_LINE_NONE to disable output of #line directives. +// +// Standard libraries: +// +// stdio.h FILE, fopen, fclose, fseek, ftell +// stdlib.h malloc, realloc, free +// string.h strcpy, strncmp, memcpy + +#ifndef STB_INCLUDE_STB_INCLUDE_H +#define STB_INCLUDE_STB_INCLUDE_H + +// Do include-processing on the string 'str'. To free the return value, pass it to free() +char *stb_include_string(char *str, char *inject, char *path_to_includes, char *filename_for_line_directive, char error[256]); + +// Concatenate the strings 'strs' and do include-processing on the result. To free the return value, pass it to free() +char *stb_include_strings(char **strs, int count, char *inject, char *path_to_includes, char *filename_for_line_directive, char error[256]); + +// Load the file 'filename' and do include-processing on the string therein. note that +// 'filename' is opened directly; 'path_to_includes' is not used. To free the return value, pass it to free() +char *stb_include_file(char *filename, char *inject, char *path_to_includes, char error[256]); + +#endif + + +#ifdef STB_INCLUDE_IMPLEMENTATION + +#include +#include +#include + +static char *stb_include_load_file(char *filename, size_t *plen) +{ + char *text; + size_t len; + FILE *f = fopen(filename, "rb"); + if (f == 0) return 0; + fseek(f, 0, SEEK_END); + len = (size_t) ftell(f); + if (plen) *plen = len; + text = (char *) malloc(len+1); + if (text == 0) return 0; + fseek(f, 0, SEEK_SET); + fread(text, 1, len, f); + fclose(f); + text[len] = 0; + return text; +} + +typedef struct +{ + int offset; + int end; + char *filename; + int next_line_after; +} include_info; + +static include_info *stb_include_append_include(include_info *array, int len, int offset, int end, char *filename, int next_line) +{ + include_info *z = (include_info *) realloc(array, sizeof(*z) * (len+1)); + z[len].offset = offset; + z[len].end = end; + z[len].filename = filename; + z[len].next_line_after = next_line; + return z; +} + +static void stb_include_free_includes(include_info *array, int len) +{ + int i; + for (i=0; i < len; ++i) + free(array[i].filename); + free(array); +} + +static int stb_include_isspace(int ch) +{ + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == 'n'); +} + +// find location of all #include and #inject +static int stb_include_find_includes(char *text, include_info **plist) +{ + int line_count = 1; + int inc_count = 0; + char *s = text, *start; + include_info *list = NULL; + while (*s) { + // parse is always at start of line when we reach here + start = s; + while (*s == ' ' || *s == '\t') + ++s; + if (*s == '#') { + ++s; + while (*s == ' ' || *s == '\t') + ++s; + if (0==strncmp(s, "include", 7) && stb_include_isspace(s[7])) { + s += 7; + while (*s == ' ' || *s == '\t') + ++s; + if (*s == '"') { + char *t = ++s; + while (*t != '"' && *t != '\n' && *t != '\r' && *t != 0) + ++t; + if (*t == '"') { + char *filename = (char *) malloc(t-s+1); + memcpy(filename, s, t-s); + filename[t-s] = 0; + s=t; + while (*s != '\r' && *s != '\n' && *s != 0) + ++s; + // s points to the newline, so s-start is everything except the newline + list = stb_include_append_include(list, inc_count++, start-text, s-text, filename, line_count+1); + } + } + } else if (0==strncmp(s, "inject", 6) && (stb_include_isspace(s[6]) || s[6]==0)) { + while (*s != '\r' && *s != '\n' && *s != 0) + ++s; + list = stb_include_append_include(list, inc_count++, start-text, s-text, NULL, line_count+1); + } + } + while (*s != '\r' && *s != '\n' && *s != 0) + ++s; + if (*s == '\r' || *s == '\n') { + s = s + (s[0] + s[1] == '\r' + '\n' ? 2 : 1); + } + ++line_count; + } + *plist = list; + return inc_count; +} + +// avoid dependency on sprintf() +static void stb_include_itoa(char str[9], int n) +{ + int i; + for (i=0; i < 8; ++i) + str[i] = ' '; + str[i] = 0; + + for (i=1; i < 8; ++i) { + str[7-i] = '0' + (n % 10); + n /= 10; + if (n == 0) + break; + } +} + +static char *stb_include_append(char *str, size_t *curlen, char *addstr, size_t addlen) +{ + str = (char *) realloc(str, *curlen + addlen); + memcpy(str + *curlen, addstr, addlen); + *curlen += addlen; + return str; +} + +char *stb_include_string(char *str, char *inject, char *path_to_includes, char *filename, char error[256]) +{ + char temp[4096]; + include_info *inc_list; + int i, num = stb_include_find_includes(str, &inc_list); + size_t source_len = strlen(str); + char *text=0; + size_t textlen=0, last=0; + for (i=0; i < num; ++i) { + text = stb_include_append(text, &textlen, str+last, inc_list[i].offset - last); + // write out line directive for the include + #ifndef STB_INCLUDE_LINE_NONE + #ifdef STB_INCLUDE_LINE_GLSL + if (textlen != 0) // GLSL #version must appear first, so don't put a #line at the top + #endif + { + strcpy(temp, "#line "); + stb_include_itoa(temp+6, 1); + strcat(temp, " "); + #ifdef STB_INCLUDE_LINE_GLSL + stb_include_itoa(temp+15, i+1); + #else + strcat(temp, "\""); + if (inc_list[i].filename == 0) + strcmp(temp, "INJECT"); + else + strcat(temp, inc_list[i].filename); + strcat(temp, "\""); + #endif + strcat(temp, "\n"); + text = stb_include_append(text, &textlen, temp, strlen(temp)); + } + #endif + if (inc_list[i].filename == 0) { + if (inject != 0) + text = stb_include_append(text, &textlen, inject, strlen(inject)); + } else { + char *inc; + strcpy(temp, path_to_includes); + strcat(temp, "/"); + strcat(temp, inc_list[i].filename); + inc = stb_include_file(temp, inject, path_to_includes, error); + if (inc == NULL) { + stb_include_free_includes(inc_list, num); + return NULL; + } + text = stb_include_append(text, &textlen, inc, strlen(inc)); + free(inc); + } + // write out line directive + #ifndef STB_INCLUDE_LINE_NONE + strcpy(temp, "\n#line "); + stb_include_itoa(temp+6, inc_list[i].next_line_after); + strcat(temp, " "); + #ifdef STB_INCLUDE_LINE_GLSL + stb_include_itoa(temp+15, 0); + #else + strcat(temp, filename != 0 ? filename : "source-file"); + #endif + text = stb_include_append(text, &textlen, temp, strlen(temp)); + // no newlines, because we kept the #include newlines, which will get appended next + #endif + last = inc_list[i].end; + } + text = stb_include_append(text, &textlen, str+last, source_len - last + 1); // append '\0' + stb_include_free_includes(inc_list, num); + return text; +} + +char *stb_include_strings(char **strs, int count, char *inject, char *path_to_includes, char *filename, char error[256]) +{ + char *text; + char *result; + int i; + size_t length=0; + for (i=0; i < count; ++count) + length += strlen(strs[i]); + text = (char *) malloc(length+1); + length = 0; + for (i=0; i < count; ++count) { + strcpy(text + length, strs[i]); + length += strlen(strs[i]); + } + result = stb_include_string(text, inject, path_to_includes, filename, error); + free(text); + return result; +} + +char *stb_include_file(char *filename, char *inject, char *path_to_includes, char error[256]) +{ + size_t len; + char *result; + char *text = stb_include_load_file(filename, &len); + if (text == NULL) { + strcpy(error, "Error: couldn't load '"); + strcat(error, filename); + strcat(error, "'"); + return 0; + } + result = stb_include_string(text, inject, path_to_includes, filename, error); + free(text); + return result; +} + +#if 0 // @TODO, GL_ARB_shader_language_include-style system that doesn't touch filesystem +char *stb_include_preloaded(char *str, char *inject, char *includes[][2], char error[256]) +{ + +} +#endif + +#endif // STB_INCLUDE_IMPLEMENTATION