commit 2ccbf002517851da67ffb1958c3b8a69679de0a4
parent 9a3f229d3556657e4442bf407a3e7179748cb59c
Author: quantumish <freifeld.david@gmail.com>
Date: Sat, 25 Jul 2026 15:28:09 -0700
Clean up formatting for readability
Diffstat:
19 files changed, 258 insertions(+), 295 deletions(-)
diff --git a/bench.cpp b/bench.cpp
@@ -1,38 +0,0 @@
-#include <benchmark/benchmark.h>
-
-extern "C" {
- #include "http/request.h"
- #include <string.h>
-
- const char* method_names[] = {"GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE"};
-
- enum http_method method_naive_enum(char* p) {
- for (int i = 0; i < 8; i++) {
- if (strcmp(method_names[i], p) == 0) {
- return (enum http_method) i;
- }
- }
- }
-}
-
-static void BM_PHF(benchmark::State& state) {
- // Perform setup here
- for (auto _ : state) {
- // This code gets timed
- method_enum((char*)"OPTIONS");
- }
-}
-
-static void BM_Naive(benchmark::State& state) {
- // Perform setup here
- for (auto _ : state) {
- // This code gets timed
- method_naive_enum((char*)"OPTIONS");
- }
-}
-
-// Register the function as a benchmark
-BENCHMARK(BM_PHF);
-BENCHMARK(BM_Naive);
-// Run the benchmark
-BENCHMARK_MAIN();
diff --git a/http.c b/http.c
@@ -134,7 +134,7 @@ response_t make_response (request_t* req, int pfd) {
return serve_error(BadRequest);
}
- if (hashmap_get(&req->headers, "Profile") != 0x0) {
+ if (hashmap_get(&req->headers, "Profile") != 0x0) {
int profile = true;
if (ptrace(PTRACE_TRACEME, NULL) < 0) {
log_error("PTRACE_TRACME failed with err %d", errno);
@@ -231,7 +231,6 @@ struct conn_ctxt {
int fd;
};
-// TODO some sort of DDOS protection idk
int main() {
int s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) die("socket");
@@ -281,7 +280,7 @@ int main() {
exit(0);
}
struct conn_ctxt ctxt = {.fd = pfds[0], .pid = pid };
- vec_push(&conns, &ctxt);
+ vec_push(&conns, &ctxt);
}
for (int i = 0; i < conns.vec_sz; i++) {
struct conn_ctxt* ctxt = vec_get(&conns, i);
@@ -290,7 +289,7 @@ int main() {
struct profile_node prof_res = profile_res_new();
while(true) {
vec_t stack = profile(ctxt->pid);
- profile_proc_stack(&prof_res, &stack);
+ profile_proc_stack(&prof_res, &stack);
usleep(3);
if (read(ctxt->fd, &msg, 5) == 5 && strcmp(msg, "stop") == 0) break;
}
@@ -304,7 +303,4 @@ int main() {
// - TODO HTML parsing maybe but that makes me want to cry
// - TODO nice ways of dynamically *generating* html
// - TODO dynamically profile requests
-
-
-
// - TODO some kinda config file parsing
diff --git a/http/request.c b/http/request.c
@@ -6,35 +6,19 @@
#include "../utils/log.h"
#include "request.h"
-const char* method_names[] = {"GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE"};
+const char* method_names[] =
+ {"GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE"};
const char* method_name(enum http_method m) {
return method_names[m];
}
-const enum http_method method_codes[] = {DELETE, CONNECT, PUT, POST, TRACE, HEAD, OPTIONS, GET};
+const enum http_method method_codes[] =
+ {DELETE, CONNECT, PUT, POST, TRACE, HEAD, OPTIONS, GET};
enum http_method method_enum(char* p) {
return method_codes[((*(uint64_t*)p*0x1b8b6e6d) % 0x100000000) >> 28];
}
-
-/* enum parse_qvals_err { */
-/* PARSE_QVALS_SUCCESS, */
-/* PARSE_QVALS_MALFORMED, */
-/* }; */
-
-/* struct parse_qvals_res { */
-/* enum parse_qval_err err; */
-/* union { */
-/* vec_t items; */
-
-/* } data; */
-/* }; */
-
-/* vec_t parse_qvalues(char* str) { */
-
-/* } */
-
// Be careful about passing by value! if the internal hashmap resizes
// a req_free() call on the original (the one copied *from*) will be a
// double free() error
@@ -42,8 +26,8 @@ request_t req_new(char* reqbuf, size_t bufsize) {
request_t req;
req.buf = reqbuf;
req.bufsize = bufsize;
- req.headers = hashmap_new(MAX_HEADER_NAME, MAX_HEADER_VALUE);
- req.headers.vark = true;
+ req.headers = hashmap_new(MAX_HEADER_NAME, MAX_HEADER_VALUE);
+ req.headers.vark = true;
return req;
}
@@ -66,7 +50,7 @@ vec_t hdr_parse_accept(char* val) {
float q = 1;
char* qptr = NULL;
- char* end = next != NULL ? next : start+strlen(start);
+ char* end = next != NULL ? next : start+strlen(start);
if ((qptr = (char*)memchr(start, ';', end-start))) {
sscanf(qptr, ";q=%f", &q);
}
@@ -83,32 +67,33 @@ vec_t hdr_parse_accept(char* val) {
}
struct mime_type parse_mimetype(char* str) {
- char* slash = strchr(str, '/');
- // if (slash == NULL) handle_error();
- char* subtype = slash + 1;
+ char* slash = strchr(str, '/');
+ // if (slash == NULL) handle_error();
+ char* subtype = slash + 1;
}
int req_parse(request_t* req) {
char method[8] = {0};
- int matched = sscanf(req->buf, "%s %s HTTP/%f\r\n", (char*)method, (char*)req->path, &req->ver);
+ int matched = sscanf(req->buf, "%s %s HTTP/%f\r\n",
+ (char*)method, (char*)req->path, &req->ver);
if (matched < 3 || matched == EOF) return -1;
req->method = method_enum((char*)method);
-
+
// FIXME if start is null this causes problems
char* start = memchr(req->buf, '\n', MAX_HEADER_NAME+MAX_HEADER_VALUE)+1;
while (start+MAX_HEADER_NAME+MAX_HEADER_VALUE < req->buf+req->bufsize) {
- char name[MAX_HEADER_NAME] = {0};
- char value[MAX_HEADER_VALUE] = {0};
+ char name[MAX_HEADER_NAME] = {0};
+ char value[MAX_HEADER_VALUE] = {0};
int matched = sscanf(start, "%32[^:]: %s", name, value);
- // printf("%d matched. %s: %s\n", matched, name, value);
- if (matched == 0) return 0; // No more headers;
+ if (matched == 0) return 0; // No more headers;
else if (matched == 1) {
if (name[0] == '\r') return 0; // TODO sketch
- return -1; // Uhh... half a header. NOTE doesn't even seem to work. fun.
+ // Uhh... half a header. NOTE doesn't even seem to work. fun.
+ return -1;
}
- hashmap_set(&req->headers, name, value);
+ hashmap_set(&req->headers, name, value);
start = memchr(start, '\n', MAX_HEADER_NAME+MAX_HEADER_VALUE)+1;
}
return 0;
@@ -141,7 +126,8 @@ void test_method_str_to_enum() {
};
void test_hdr_parse_accept() {
- char hdr[MAX_HEADER_VALUE] = "text/html,application/xml;q=0.9,image/webp,*/*;q=0.8";
+ char hdr[MAX_HEADER_VALUE] =
+ "text/html,application/xml;q=0.9,image/webp,*/*;q=0.8";
vec_t mtypes = hdr_parse_accept(hdr);
assert_size_eq(mtypes.vec_sz, 4);
@@ -163,18 +149,8 @@ void test_hdr_parse_accept() {
}
void test_bad_req_total_garbage() {
- request_t r = req_new("this is not a request.", 23);
- assert_int_eq(-1, req_parse(&r));
+ request_t r = req_new("this is not a request.", 23);
+ assert_int_eq(-1, req_parse(&r));
}
-/* void test_bad_req_half_header() { */
-/* char bigbuf[1024] = "GET / HTTP/1.1\r\nProfile:\n"; */
-/* request_t r = req_new(bigbuf, 1024); */
-/* assert_int_eq(-1, req_parse(&r)); */
-
-/* bzero(bigbuf, 1024); */
-/* bigbuf = "GET / HTTP/1.1\r\nProfile: */
-/* } */
-
-
#endif
diff --git a/http/request.h b/http/request.h
@@ -24,19 +24,19 @@ enum http_method method_enum(char* p);
#define MAX_MIME_SUBTYPE_LEN 32
enum mime_disctype {
- MIME_APPLICATION,
- MIME_AUDIO,
- MIME_EXAMPLE,
- MIME_FONT,
- MIME_IMAGE,
- MIME_MODEL,
- MIME_TEXT,
- MIME_VIDEO,
+ MIME_APPLICATION,
+ MIME_AUDIO,
+ MIME_EXAMPLE,
+ MIME_FONT,
+ MIME_IMAGE,
+ MIME_MODEL,
+ MIME_TEXT,
+ MIME_VIDEO,
};
struct mime_type {
- enum mime_disctype type;
- char subtype[MAX_MIME_SUBTYPE_LEN];
+ enum mime_disctype type;
+ char subtype[MAX_MIME_SUBTYPE_LEN];
};
struct req_mimetype {
@@ -44,11 +44,6 @@ struct req_mimetype {
char item[MAX_MIMETYPE_LEN];
};
-/* typedef struct header_line { */
-/* char name[MAX_HEADER_NAME]; */
-/* char value[MAX_HEADER_VALUE]; */
-/* } header_line_t; */
-
vec_t hdr_parse_accept(char* val);
typedef struct request {
diff --git a/http/response.c b/http/response.c
@@ -9,57 +9,62 @@
#include "response.h"
response_t __resp_new(enum StatusCode code, char* code_name) {
- response_t resp;
- memset(resp.header, 0, 512);
- sprintf(resp.header, "HTTP/1.1 %d %s\r\n", code, code_name);
+ response_t resp;
+ memset(resp.header, 0, 512);
+ sprintf(resp.header, "HTTP/1.1 %d %s\r\n", code, code_name);
- resp_add_hdr(&resp, "Server", "Bunkum/0.0.1");
-
- char datebuf[32];
- time_to_str(time(0), datebuf);
- resp_add_hdr(&resp, "Date", datebuf);
-
- return resp;
+ resp_add_hdr(&resp, "Server", "Bunkum/0.0.1");
+
+ char datebuf[32];
+ time_to_str(time(0), datebuf);
+ resp_add_hdr(&resp, "Date", datebuf);
+
+ return resp;
}
void resp_add_hdr(response_t* r, char* hdr, char* val) {
- char header[64];
- sprintf(header, "%s: %s\r\n", hdr, val);
- strcat(r->header, header);
+ char header[64];
+ sprintf(header, "%s: %s\r\n", hdr, val);
+ strcat(r->header, header);
}
void resp_add_content(response_t* r, char* content, size_t content_len) {
- char length[32];
- sprintf(length, "%ld", content_len);
- resp_add_hdr(r, "Content-Length", length);
-
- strcat(r->header, "\r\n");
- size_t header_len = strlen(r->header);
+ char length[32];
+ sprintf(length, "%ld", content_len);
+ resp_add_hdr(r, "Content-Length", length);
- r->sz = strlen(r->header)+content_len;
- r->content = malloc(r->sz);
- strcpy(r->content, r->header);
- memcpy(r->content+header_len, content, content_len);
+ strcat(r->header, "\r\n");
+ size_t header_len = strlen(r->header);
+
+ r->sz = strlen(r->header)+content_len;
+ r->content = malloc(r->sz);
+ strcpy(r->content, r->header);
+ memcpy(r->content+header_len, content, content_len);
}
-const char* exts[] = {"html", "css", "js", "png", "gif", "jpeg", "svg", "ttf", "woff", "woff2",
- "pdf", "csv", "gz", "tar", "zip", "json", NULL}; // TODO sentinel sketchy
-const char* mtypes[] = {"text/html", "text/css", "text/javascript", "image/png",
- "image/gif", "image/jpeg", "image/svg+xml", "font/ttf", "font/woff", "font/woff2",
- "application/pdf", "text/csv", "application/gzip", "application/x-tar", "application/zip",
- "application/json"};
+const char* exts[] = {
+ "html", "css", "js", "png", "gif", "jpeg", "svg", "ttf",
+ "woff", "woff2", "pdf", "csv", "gz", "tar", "zip", "json", NULL
+}; // TODO sentinel sketchy
+
+const char* mtypes[] = {
+ "text/html", "text/css", "text/javascript", "image/png", "image/gif",
+ "image/jpeg", "image/svg+xml", "font/ttf", "font/woff", "font/woff2",
+ "application/pdf", "text/csv", "application/gzip", "application/x-tar",
+ "application/zip", "application/json"
+};
const char* ext_to_mtype(char* ext) {
- if (ext == NULL) return"text/plain";
+ if (ext == NULL) return"text/plain";
- for (size_t i = 0; exts[i] != NULL; i++) {
- if (strcmp(ext, exts[i]) == 0) return mtypes[i];
- }
+ for (size_t i = 0; exts[i] != NULL; i++) {
+ if (strcmp(ext, exts[i]) == 0) return mtypes[i];
+ }
- log_warn("Giving up on mapping %s extension to a MIME type!", ext);
- return "text/plain";
+ log_warn("Giving up on mapping %s extension to a MIME type!", ext);
+ return "text/plain";
}
void resp_set_ctype(response_t* r, char* ext) {
- resp_add_hdr(r, "Content-Type", (char*)ext_to_mtype(ext));
+ resp_add_hdr(r, "Content-Type", (char*)ext_to_mtype(ext));
}
diff --git a/readme.md b/readme.md
@@ -1,17 +1,37 @@
# bunkum
-A silly personal webserver with the goal to hand-roll basically whatever I can (only dependencies are pthread, zlib, and libunwind).
+A silly personal webserver with the goal to hand-roll basically whatever I can
+(only dependencies are pthread, zlib, and libunwind).
Fun features include
-- **Self-profiling**. If you pass a "Profile" header in any request, `bunkum` will automatically profile itself as it serves the request and report the profile info. This was remarkably painful to implement given weird quirks of the ptrace() API for child threads.
-- A **custom testing framework** with **automatic test discovery**. After compiling the code as a dynamic library, It works by parsing the ELF file to extract symbol names and find all of those that start with "test". As there's an enforced test interface, it can then load the dynamic library and run the tests.
-- A custom **channel type** for inter-thread communications that is directly implemented with atomic intrinsics
+- **Self-profiling**. If you pass a "Profile" header in any request, `bunkum`
+ will automatically profile itself as it serves the request and report the
+ profile info. This was remarkably painful to implement given weird quirks of
+ the ptrace() API for child threads.
+- A **custom testing framework** with **automatic test discovery**. After
+ compiling the code as a dynamic library, It works by parsing the ELF file to
+ extract symbol names and find all of those that start with "test". As there's
+ an enforced test interface, it can then load the dynamic library and run the
+ tests.
+- A custom **channel type** for inter-thread communications that is directly
+ implemented with atomic intrinsics
- A silly **PHF** for rapidly converting HTTP methods to their enum form
```c
-const enum http_method method_codes[] = {DELETE, CONNECT, PUT, POST, TRACE, HEAD, OPTIONS, GET};
+const enum http_method method_codes[] = {
+ DELETE, CONNECT, PUT, POST, TRACE, HEAD, OPTIONS, GET
+};
enum http_method method_enum(char* p) {
return method_codes[((*(uint64_t*)p*0x1b8b6e6d) % 0x100000000) >> 28];
}
```
-alongside others (custom logging, data structures, html generation utilities, etc.)
+alongside others (custom logging, data structures, html generation utilities)
+# building and usage
+
+Build with `make`, test with `make test`.
+
+You can then run it with `./serv` and it'll start a web server serving files
+under ./public on port 8080 or the next available port. Web requests with a
+"Profile" header will dump profiling info to logs.
+
+You can also run the server in a Docker container with `make run`
diff --git a/test.c b/test.c
@@ -20,43 +20,43 @@ char* symtabs_off = (char*)&symtabs;
void get_symbols(char* path) {
FILE* fptr = fopen(path, "r");
- Elf64_Ehdr header = {0};
- fread(&header, sizeof(Elf64_Ehdr), 1, fptr);
- if (strncmp((char*)&header, ELFMAG, 3) != 0) {
+ Elf64_Ehdr header = {0};
+ fread(&header, sizeof(Elf64_Ehdr), 1, fptr);
+ if (strncmp((char*)&header, ELFMAG, 3) != 0) {
printf("Attempted read of invalid ELF file.");
}
fseek(fptr, header.e_shoff, SEEK_SET);
- Elf64_Shdr syment[2] = {0};
+ Elf64_Shdr syment[2] = {0};
for (int i = 0; i < header.e_shnum-1; i++) {
- fread(&syment, sizeof(Elf64_Shdr), 2, fptr); // NOTE: questionable
- if (syment[0].sh_type == SHT_SYMTAB && syment[1].sh_type == SHT_STRTAB) {
+ fread(&syment, sizeof(Elf64_Shdr), 2, fptr); // NOTE: questionable
+ if (syment[0].sh_type == SHT_SYMTAB && syment[1].sh_type == SHT_STRTAB) {
memcpy(symtabs_off, &syment[0], sizeof(Elf64_Shdr));
memcpy(symtabs_off+sizeof(Elf64_Shdr), &syment[1], sizeof(Elf64_Shdr));
symtabs_off = symtabs_off+(sizeof(Elf64_Shdr)*2);
- }
- fseek(fptr, -sizeof(Elf64_Shdr), SEEK_CUR); // HACK
- }
- for (int i = 0; i < (symtabs_off-symtabs)/(sizeof(Elf64_Shdr)*2); i++) {
+ }
+ fseek(fptr, -sizeof(Elf64_Shdr), SEEK_CUR); // HACK
+ }
+ for (int i = 0; i < (symtabs_off-symtabs)/(sizeof(Elf64_Shdr)*2); i++) {
Elf64_Shdr symtab0 = ((Elf64_Shdr*)symtabs)[i*2];
Elf64_Shdr symtab1 = ((Elf64_Shdr*)symtabs)[i*2+1];
-
+
fseek(fptr, symtab1.sh_offset, SEEK_SET);
- char* strtbl = malloc(symtab1.sh_size);
- fread(strtbl, symtab1.sh_size, 1, fptr);
- fseek(fptr, symtab0.sh_offset, SEEK_SET);
- Elf64_Sym symbol = {0};
- for (size_t i = 0; i < symtab0.sh_size; i+=sizeof(Elf64_Sym)) {
- fread(&symbol, sizeof(Elf64_Sym), 1, fptr);
- if (symbol.st_name != 0) {
- char* mangled = (char*)(&strtbl[symbol.st_name]);
+ char* strtbl = malloc(symtab1.sh_size);
+ fread(strtbl, symtab1.sh_size, 1, fptr);
+ fseek(fptr, symtab0.sh_offset, SEEK_SET);
+ Elf64_Sym symbol = {0};
+ for (size_t i = 0; i < symtab0.sh_size; i+=sizeof(Elf64_Sym)) {
+ fread(&symbol, sizeof(Elf64_Sym), 1, fptr);
+ if (symbol.st_name != 0) {
+ char* mangled = (char*)(&strtbl[symbol.st_name]);
if (strncmp(mangled, "test_", 5) == 0) {
strcpy(symbols_off, mangled);
symbols_off += MAX_SYMBOL_LEN;
- }
- }
- }
- }
- fclose(fptr);
+ }
+ }
+ }
+ }
+ fclose(fptr);
}
int run_test_safe(bool(*testf)(void)) {
@@ -68,7 +68,7 @@ int run_test_safe(bool(*testf)(void)) {
int status;
waitpid(pid, &status, 0);
return status;
- }
+ }
}
#define ANSI_RED "\x1b[31m"
@@ -78,7 +78,7 @@ int run_test_safe(bool(*testf)(void)) {
int main(int argc, char** argv) {
bool imode = false;
- if (argc > 2 && strcmp(argv[2], "-i") == 0) imode = true;
+ if (argc > 2 && strcmp(argv[2], "-i") == 0) imode = true;
get_symbols(argv[1]);
char path[64] = {0};
sprintf(path, "./%s", argv[1]);
@@ -89,9 +89,9 @@ int main(int argc, char** argv) {
for (char* sym = symbols; sym < symbols_off; sym+=MAX_SYMBOL_LEN) {
printf(" %s ", sym+5);
fflush(STDIN_FILENO);
- bool(*testf)(void) = dlsym(lib, sym);
+ bool(*testf)(void) = dlsym(lib, sym);
int status = run_test_safe(testf);
-
+
if (status == 0) {
passed += 1;
puts(" " ANSI_GREEN "[GOOD]" ANSI_RESET);
@@ -102,7 +102,8 @@ int main(int argc, char** argv) {
}
if (status != 0 && status != 1 && imode) testf();
}
- printf("\n" ANSI_GREEN "%ld tests" ANSI_RESET " passed, " ANSI_RED "%ld tests" ANSI_RESET " failed.\n" ANSI_RESET,
+ printf("\n" ANSI_GREEN "%ld tests" ANSI_RESET " passed, "
+ ANSI_RED "%ld tests" ANSI_RESET " failed.\n" ANSI_RESET,
passed, total-passed);
dlclose(lib);
}
diff --git a/utils/compression.c b/utils/compression.c
@@ -22,12 +22,13 @@ char* gzip_compress(char* buf, size_t* bufsize) {
zs.avail_out = (uInt)clen;
zs.next_out = (Bytef *)cbuf;
*bufsize = clen;
- // "Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper"
- deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY);
+
+ // "Add 16 to windowBits to write a simple gzip header and trailer
+ // around the compressed data instead of a zlib wrapper"
+ deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
+ 15 | 16, 8, Z_DEFAULT_STRATEGY);
deflate(&zs, Z_FINISH);
deflateEnd(&zs);
- // zs.total_out
-
return cbuf;
}
diff --git a/utils/hashmap.c b/utils/hashmap.c
@@ -65,7 +65,7 @@ void hashmap_resize(hashmap_t* h) {
h->len *= 2;
// Simple to use calloc here because keys need to be initialized to zero.
h->keys = calloc(h->len, h->k_sz);
- h->vals = malloc(h->len * h->v_sz);
+ h->vals = malloc(h->len * h->v_sz);
// Copy all keys and values
for (size_t off = 0; off < (h->len / 2); off++) {
// Don't bother copying entries with empty keys
@@ -142,7 +142,7 @@ int hashmap_del(hashmap_t* h, void* k) {
int looped_once = 0;
for (size_t off = index; off < h->len; off+=1) {
if (hashmap_kcmp(h, h->keys + (off * h->k_sz), k) == 0) {
- memset(h->keys + (off * h->k_sz), 0, h->k_sz);
+ memset(h->keys + (off * h->k_sz), 0, h->k_sz);
// No reason to delete value, will just be overwritten next time.
return 0;
}
@@ -178,7 +178,7 @@ void test_hashmap_sanity() {
void test_hashmap_del() {
hashmap_t h = hashmap_new(16, 64);
assert_int_eq(hashmap_del(&h, "abc"), 1);
- assert_int_eq(hashmap_set(&h, "abc", "whoo"), 0);
+ assert_int_eq(hashmap_set(&h, "abc", "whoo"), 0);
assert_int_eq(hashmap_del(&h, "abc"), 0);
assert_int_eq((long)hashmap_get(&h, "abc"), 0);
}
diff --git a/utils/hashmap.h b/utils/hashmap.h
@@ -11,7 +11,7 @@ typedef struct hashmap_t {
size_t v_sz;
size_t len;
size_t filled;
- bool vark;
+ bool vark;
} hashmap_t;
// Generates a new hashmap_t.
@@ -19,10 +19,12 @@ hashmap_t hashmap_new(size_t ksize, size_t vsize);
#define hashmap_init(t1, t2) hashmap_new(sizeof(t1), sizeof(t2))
-// Sets a key-value pair in the hashmap_t passed to it. Returns 0x0 for success, 0x1 for failure.
+// Sets a key-value pair in the hashmap_t passed to it.
+// Returns 0x0 for success, 0x1 for failure.
int hashmap_set(hashmap_t* h, void* k, void* v);
-// Returns address of value associated with key in hashmap if it exists, otherwise returns 0x0 for no value or 0x1 for full table.
+// Returns address of value associated with key in hashmap if it exists,
+// otherwise returns 0x0 for no value or 0x1 for full table.
void* hashmap_get(hashmap_t* h, void* k);
// Deletes key in hashmap (but not value).
diff --git a/utils/html.c b/utils/html.c
@@ -2,63 +2,63 @@
#include "log.h"
html_t html_new() {
- html_t out;
- out._buf = vec_new(sizeof(char));
- html_body_t body;
- body.content = vec_new(sizeof(html_fc_t));
- out.body = body;
- return out;
+ html_t out;
+ out._buf = vec_new(sizeof(char));
+ html_body_t body;
+ body.content = vec_new(sizeof(html_fc_t));
+ out.body = body;
+ return out;
}
html_fc_t html_p_new(char* content) {
- html_fc_t out;
- out.type = HTML_P;
- out.value.text = content;
- return out;
+ html_fc_t out;
+ out.type = HTML_P;
+ out.value.text = content;
+ return out;
}
html_fc_t html_h1_new(char* content) {
- html_fc_t out;
- out.type = HTML_H1;
- out.value.text = content;
- return out;
+ html_fc_t out;
+ out.type = HTML_H1;
+ out.value.text = content;
+ return out;
}
void html_body_add(html_body_t* body, html_fc_t fc) {
- vec_push(&body->content, &fc);
+ vec_push(&body->content, &fc);
}
void c_sv_pushs(vec_t* sv, char* str) {
- for (int i = 0; str[i] != '\0'; i++) {
- vec_push(sv, &str[i]);
- }
+ for (int i = 0; str[i] != '\0'; i++) {
+ vec_push(sv, &str[i]);
+ }
}
char* html_render(html_t* html) {
- c_sv_pushs(&html->_buf, "<!DOCTYPE html><html>");
- c_sv_pushs(&html->_buf, "<body>");
- for (int i = 0; i < html->body.content.vec_sz; i++) {
- html_fc_t* elem = vec_get(&html->body.content, i);
- switch (elem->type) {
- case HTML_TEXT:
-
- case HTML_P:
- c_sv_pushs(&html->_buf, "<p>");
- c_sv_pushs(&html->_buf, elem->value.text);
- c_sv_pushs(&html->_buf, "</p>");
- break;
- case HTML_H1:
- c_sv_pushs(&html->_buf, "<h1>");
- c_sv_pushs(&html->_buf, elem->value.text);
- c_sv_pushs(&html->_buf, "</h1>");
- break;
- default:
- log_error("Didn't handle rendering HTML element!");
- }
- }
- c_sv_pushs(&html->_buf, "</body>");
- c_sv_pushs(&html->_buf, "</html>");
- vec_push(&html->_buf, "\0");
+ c_sv_pushs(&html->_buf, "<!DOCTYPE html><html>");
+ c_sv_pushs(&html->_buf, "<body>");
+ for (int i = 0; i < html->body.content.vec_sz; i++) {
+ html_fc_t* elem = vec_get(&html->body.content, i);
+ switch (elem->type) {
+ case HTML_TEXT:
+
+ case HTML_P:
+ c_sv_pushs(&html->_buf, "<p>");
+ c_sv_pushs(&html->_buf, elem->value.text);
+ c_sv_pushs(&html->_buf, "</p>");
+ break;
+ case HTML_H1:
+ c_sv_pushs(&html->_buf, "<h1>");
+ c_sv_pushs(&html->_buf, elem->value.text);
+ c_sv_pushs(&html->_buf, "</h1>");
+ break;
+ default:
+ log_error("Didn't handle rendering HTML element!");
+ }
+ }
+ c_sv_pushs(&html->_buf, "</body>");
+ c_sv_pushs(&html->_buf, "</html>");
+ vec_push(&html->_buf, "\0");
- return html->_buf.arr;
+ return html->_buf.arr;
}
diff --git a/utils/html.h b/utils/html.h
@@ -4,41 +4,41 @@
#include "vec.h"
enum html_fc_type {
- HTML_TEXT,
- HTML_A,
- HTML_P,
- HTML_BR,
- HTML_H1,
+ HTML_TEXT,
+ HTML_A,
+ HTML_P,
+ HTML_BR,
+ HTML_H1,
};
typedef struct html_fc {
- enum html_fc_type type;
- union {
- char* text;
- struct { char* href; char* content; } a;
- } value;
+ enum html_fc_type type;
+ union {
+ char* text;
+ struct { char* href; char* content; } a;
+ } value;
} html_fc_t;
typedef struct title {
- char* text;
+ char* text;
} html_title_t;
typedef struct base {
- char* href;
- char* target;
+ char* href;
+ char* target;
} html_base_t;
typedef struct head {
- vec_t meta;
+ vec_t meta;
} html_head_t;
typedef struct body {
- vec_t content;
+ vec_t content;
} html_body_t;
typedef struct html {
- vec_t _buf;
- html_body_t body;
+ vec_t _buf;
+ html_body_t body;
} html_t;
html_t html_new();
diff --git a/utils/log.c b/utils/log.c
@@ -19,8 +19,9 @@
#define ANSI_MAGENTA "\x1b[36m"
#define ANSI_RESET "\x1b[0m"
-const char* lvl_colors[] =
- {ANSI_MAGENTA, ANSI_GREEN, ANSI_CYAN, ANSI_YELLOW, ANSI_RED, ANSI_BOLDRED};
+const char* lvl_colors[] = {
+ ANSI_MAGENTA, ANSI_GREEN, ANSI_CYAN, ANSI_YELLOW, ANSI_RED, ANSI_BOLDRED
+};
size_t log_min_level = 0;
@@ -28,9 +29,9 @@ FILE* log_file = NULL;
void log_msg(enum log_level lvl, char* lvl_name, char* fmt, ...) {
if (lvl < log_min_level) return;
-
+
char msg[LOG_MAX_MSGLEN];
-
+
va_list args;
va_start(args, fmt);
vsprintf(msg, fmt, args);
@@ -46,10 +47,10 @@ void log_msg(enum log_level lvl, char* lvl_name, char* fmt, ...) {
local->tm_min, local->tm_sec, lvl_color, lvl_name, msg);
} else {
fprintf(log_file, "%02d/%02d/%04d %02d:%02d:%02d %s: %s\n",
- local->tm_mon+1, local->tm_mday, 1900+local->tm_year, local->tm_hour,
- local->tm_min, local->tm_sec, lvl_name, msg);
+ local->tm_mon+1, local->tm_mday, 1900+local->tm_year,
+ local->tm_hour, local->tm_min, local->tm_sec, lvl_name, msg);
}
-
+
va_end(args);
}
@@ -62,6 +63,6 @@ void log_set_log_file(char* path) {
}
void die(char* p) {
- log_fatal("(%s) %s", p, strerror(errno));
+ log_fatal("(%s) %s", p, strerror(errno));
exit(1);
}
diff --git a/utils/profile.c b/utils/profile.c
@@ -44,48 +44,48 @@ vec_t profile(pid_t tid) {
}
struct profile_node profile_node_new(char* name) {
- struct profile_node out = {
- .children = vec_new(sizeof(struct profile_node)),
- .samples = 0,
- .symbol = {0}
- };
- strcpy(out.symbol, name);
- return out;
+ struct profile_node out = {
+ .children = vec_new(sizeof(struct profile_node)),
+ .samples = 0,
+ .symbol = {0}
+ };
+ strcpy(out.symbol, name);
+ return out;
}
struct profile_node profile_res_new() {
- return profile_node_new("");
+ return profile_node_new("");
}
int cmp_prof_node(void* _a, void* _b) {
- struct profile_node* a = _a;
- struct profile_node* b = _b;
- return strcmp(a->symbol, b->symbol);
+ struct profile_node* a = _a;
+ struct profile_node* b = _b;
+ return strcmp(a->symbol, b->symbol);
}
void profile_proc_stack(struct profile_node* prof_res, vec_t* stack) {
- if (stack->vec_sz == 0) return;
- struct profile_node* node = prof_res;
- for (int i = stack->vec_sz-1; i > 0; i--) {
- char* sym = vec_get(stack, i);
- int index = vec_check(&node->children, sym, cmp_prof_node);
- if (index == -1) {
- struct profile_node new = profile_node_new(sym);
- vec_push(&node->children, &new);
- index = node->children.vec_sz - 1;
- }
- node = vec_get(&node->children, index);
- node->samples += 1;
- }
+ if (stack->vec_sz == 0) return;
+ struct profile_node* node = prof_res;
+ for (int i = stack->vec_sz-1; i > 0; i--) {
+ char* sym = vec_get(stack, i);
+ int index = vec_check(&node->children, sym, cmp_prof_node);
+ if (index == -1) {
+ struct profile_node new = profile_node_new(sym);
+ vec_push(&node->children, &new);
+ index = node->children.vec_sz - 1;
+ }
+ node = vec_get(&node->children, index);
+ node->samples += 1;
+ }
}
void profile_dump(struct profile_node* prof_res, int indent) {
- struct profile_node* node = prof_res;
- if (indent >= 0) {
- for (int i = 0; i < indent; i++) printf(" ");
- printf("%s (%d) \n", node->symbol, node->samples);
- }
- for (int i = 0; i < node->children.vec_sz; i++) {
- profile_dump(vec_get(&node->children, i), indent+1);
- }
+ struct profile_node* node = prof_res;
+ if (indent >= 0) {
+ for (int i = 0; i < indent; i++) printf(" ");
+ printf("%s (%d) \n", node->symbol, node->samples);
+ }
+ for (int i = 0; i < node->children.vec_sz; i++) {
+ profile_dump(vec_get(&node->children, i), indent+1);
+ }
}
diff --git a/utils/profile.h b/utils/profile.h
@@ -9,9 +9,9 @@
vec_t profile(pid_t pid);
struct profile_node {
- char symbol[MAX_SYMLEN];
- unsigned int samples;
- vec_t children;
+ char symbol[MAX_SYMLEN];
+ unsigned int samples;
+ vec_t children;
};
struct profile_node profile_res_new();
diff --git a/utils/result.c b/utils/result.c
diff --git a/utils/time.c b/utils/time.c
@@ -2,9 +2,13 @@
#include "time.h"
-const char* days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
-const char* months[] =
- {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+const char* days[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+const char* months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
void time_to_str(time_t t, char* buf) {
struct tm* gmt = gmtime(&t);
diff --git a/utils/toml.c b/utils/toml.c
diff --git a/utils/vec.c b/utils/vec.c
@@ -19,7 +19,7 @@ void* vec_get(vec_t* sv, size_t index) {
}
void* vec_last(vec_t* sv) {
- return vec_get(sv, sv->vec_sz-1);
+ return vec_get(sv, sv->vec_sz-1);
}
void vec_push(vec_t* sv, void* item) {