#pragma once #include <cstdarg>#include <cstring> #define NEEDS_ESCAPE(c) ((c) < ' ' || (c) > '~' || (c) == '&' || (c) == '<' || (c) == '>' || (c) == '"')#define IS_SPACE(c) (c == ' ' || c == '\t' || c == '\r' || c == '\n') #define SECS_UNTIL_RELOAD 60 #define RESPONSE_FILE 1#define RESPONSE_HTML 2#define RESPONSE_MULTI 3 #define LIST_DIR_MAX_FILES (1 << 12)#define LIST_DIR_LEN (1 << 20) #define N_CLOSING_TAGS 100 #define NAV_IDX_NULL -1#define NAV_IDX_HOME 0#define NAV_IDX_BLOG 1#define NAV_IDX_PROJECTS 2 #define HTML_METAS "\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n" typedef unsigned char u8;typedef unsigned int u32;typedef long long s64;typedef unsigned long long u64; struct Space { int offset; int size;}; struct String; void init_logger();void log_info(const char *fmt, ...);void log_error(const char *fmt, ...); void write_formatted_string(String& str, const char *fmt, va_list args);char *append_string(char *dst, char *src, int len); void write_escaped_byte(int ch, char *buf); bool caseless_match(const char *a, const char *b); // Can be used as a managed or unmanaged string.// If the string is unmanaged, the LSB of 'ptr' is set to 1.// This class *must* have access to at least len+1 bytes of memory.struct String { static constexpr int INITIAL_SIZE = 32; char *ptr; int capacity; int len; char initial_buf[INITIAL_SIZE]; String(); String(char *buf, int size); String(String& other); ~String(); char *data(); char last(); void scrub(int len_from_end); int resize(int sz); void reserve(int sz); int add(String str); int add(const char *str, int size); int add(char c); int add(const char *str); void add_chars(char c, int n); int add_and_escape(const char *str, int size = 0); void assign(const char *str, int size); static String make_escaped(const char *str, int size) { String s; s.add_and_escape(str, size); return s; } void reformat(const char *fmt, ...) { va_list args; va_start(args, fmt); write_formatted_string(*this, fmt, args); va_end(args); } static String format(const char *fmt, ...) { va_list args; va_start(args, fmt); String str; write_formatted_string(str, fmt, args); va_end(args); return str; }}; struct Pool { char *buf = nullptr; int cap = 0; int head = 0; Pool(); ~Pool(); void init(int capacity); char *at(int offset); int add(const char *str, int add_len = 0); void add_and_escape(const char *str, int size = 0); void reserve_extra(int bytes);}; template<typename T>struct Vector { T *data; int cap; int size; Vector<T>() { data = nullptr; cap = 0; size = 0; } ~Vector<T>() { if (data) delete[] data; } T& operator[](int idx) { return data[idx]; } void resize(int new_size) { if (new_size <= size) return; int old_cap = cap; if (cap < 16) cap = 16; while (new_size > cap) cap *= 2; if (cap > old_cap) { T *new_data = new T[cap]; if (data) { if (old_cap > 0) memcpy(new_data, data, old_cap * sizeof(T)); delete[] data; } data = new_data; } size = new_size; } void add(T t) { int old_size = size; resize(old_size + 1); data[old_size] = t; } void add_multiple(T *array, int n) { int old_size = size; resize(old_size + n); memcpy(&data[old_size], array, n * sizeof(T)); }}; template <typename T>struct Inline_Vector { static constexpr int INLINE_COUNT = 32; T space[INLINE_COUNT]; T *ptr; int cap; int size; Inline_Vector() { ptr = nullptr; cap = INLINE_COUNT; size = 0; } ~Inline_Vector() { if (ptr) delete[] ptr; } T *data() { return ptr ? ptr : space; } T& operator[](int idx) { return data()[idx]; } void resize(int new_size) { if (new_size < 0) new_size = 0; int c = cap; if (c < INLINE_COUNT) c = INLINE_COUNT; while (new_size > c) c *= 2; if (c != cap && c > INLINE_COUNT) { T *new_data = new T[c]; memcpy(new_data, data(), cap * sizeof(T)); if (ptr) delete[] ptr; ptr = new_data; } cap = c; size = new_size; } void add(T t) { int idx = size; resize(size+1); data()[idx] = t; }}; struct HTML_Type { const char *mime; const char *tag;}; struct Request { String str; int header_size; int accept;}; struct Response { int format; int file_size; char *file_buffer; const char *status; const char *mime; String html;}; struct DB_File { long last_reloaded; u32 flags; int size; u8 *buffer; char *label; char *type; char *fname;}; struct File_Database { int pool_size; int n_files; char *map_buffer; char *label_pool; char *fname_pool; char *type_pool; DB_File *files; int init(const char *fname); int lookup_file(char *name, int len);}; #define FS_ORDER_ALPHA 0#define FS_ORDER_MODIFIED 1#define FS_ORDER_CREATED 2 #define FS_FLAG_WAS_LINK 1#define FS_FLAG_ASCII 2 union FS_Next { struct { int alpha; int modified; int created; }; int array[3];}; struct FS_Directory { FS_Next next; int parent; int name_idx; long created_time; long modified_time; FS_Next first_dir; FS_Next first_file; u32 flags; static FS_Directory make_empty() { return { .next = {-1, -1, -1}, .parent = -1, .name_idx = -1, .created_time = 0, .modified_time = 0, .first_dir = {-1, -1, -1}, .first_file = {-1, -1, -1}, .flags = 0 }; }}; struct FS_File { FS_Next next; int parent; int name_idx; long created_time; long modified_time; u8 *buffer; int size; u32 crc; u32 flags; static FS_File make_empty() { return { .next = {-1, -1, -1}, .parent = -1, .name_idx = -1, .created_time = 0, .modified_time = 0, .buffer = nullptr, .size = 0, .flags = 0 }; }}; struct Filesystem { String starting_path; Pool name_pool; Vector<FS_Directory> dirs; Vector<FS_File> files; int total_name_tree_size; Filesystem() = default; ~Filesystem() { for (int i = 0; i < files.size; i++) { if (files[i].buffer) delete[] files[i].buffer; } } int init_at(const char *initial_path, Pool& allowed_dirs, Pool& links, char *list_dir_buffer); void lookup(int *dir_idx, int *file_idx, const char *path, int max_len); int lookup_dir(const char *path); int lookup_file(const char *path); void walk(int dir_idx, int order, void (*dir_cb)(Filesystem*, int, void*), void (*file_cb)(Filesystem*, int, void*), void *cb_data); int get_path(char *buf, int ancestor, int parent, char *name); //int refresh_file(int idx); bool add_file_to_html(String *html, const char *path);}; struct Markdown_Params { char *path; long created_time; int line_limit; bool disable_anchors;}; bool strings_match(const char *a, const char *b, int len);int find_character(const char *str, char c, int len);HTML_Type lookup_ext(const char *ext);void get_datetime(char *buf);void write_http_header(int request_fd, const char *status, const char *content_type, int size);void add_banner(Filesystem& fs, String *html, int hl_idx); void write_zip_as_response(Filesystem& fs, int dir_idx, Response& response); Space produce_markdown_html(Filesystem& fs, String& html, const char *input, int in_sz, Markdown_Params& md_params);void serve_markdown_tester(Filesystem& fs, Request& request, Response& response); void serve_404(Filesystem& fs, Response& response);void serve_home_page(Filesystem& fs, Response& response);void serve_blog_overview(Filesystem& fs, Response& response);void serve_specific_blog(Filesystem& fs, Response& response, char *name, int len);void serve_projects_overview(Filesystem& fs, Response& response);void serve_specific_project(Filesystem& fs, Response& response, char *project_type, int slash_pos, int name_len);