added:
* coroutines * string modified: * http: fixed a couple of bugs * strutils: renamed to os, it is now a header for some generic platform-indipendent code * tracelog: added option to not print newline at the end of a message + bug fixes
This commit is contained in:
parent
d8b44c1281
commit
bb5cce33f0
15 changed files with 523 additions and 76 deletions
|
|
@ -4,7 +4,9 @@ add_library(Colla STATIC
|
|||
http.c
|
||||
strstream.c
|
||||
strview.c
|
||||
strutils.c
|
||||
str.c
|
||||
coroutine.c
|
||||
os.c
|
||||
)
|
||||
|
||||
IF (WIN32)
|
||||
|
|
|
|||
11
coroutine.c
Normal file
11
coroutine.c
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include "coroutine.h"
|
||||
|
||||
coroutine_t coInit() {
|
||||
return (coroutine_t) {
|
||||
.state = 0
|
||||
};
|
||||
}
|
||||
|
||||
bool coIsDead(coroutine_t co) {
|
||||
return co.state == -1;
|
||||
}
|
||||
127
coroutine.h
Normal file
127
coroutine.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h> // bool
|
||||
#include <string.h> // memset
|
||||
|
||||
// heavily inspired by https://gist.github.com/Enichan/5f01140530ff0133fde19c9549a2a973
|
||||
|
||||
#if 0
|
||||
// Usage example:
|
||||
typedef struct {
|
||||
int result;
|
||||
coroutine_t co;
|
||||
} co_int_t;
|
||||
|
||||
bool coVoid(co_void_t *co) {
|
||||
costate(co_nostate);
|
||||
coroutine({
|
||||
printf("hello"); yield();
|
||||
printf("world"); yield();
|
||||
printf("how"); yield();
|
||||
printf("is"); yield();
|
||||
printf("it"); yield();
|
||||
printf("going?\n");
|
||||
});
|
||||
}
|
||||
|
||||
bool countToTen(co_int_t *co) {
|
||||
costate(int i; int ii;);
|
||||
coroutine({
|
||||
for(self.i = 0; self.i < 10; ++self.i) {
|
||||
self.ii += self.i;
|
||||
yieldVal(self.ii);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int main() {
|
||||
co_void_t covoid = {0};
|
||||
while(coVoid(&covoid)) {
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
co_int_t coint;
|
||||
coint.co = coInit();
|
||||
while(countToTen(&coint)) {
|
||||
printf("%d ", coint.result);
|
||||
}
|
||||
printf("\n");
|
||||
// reset coroutine for next call
|
||||
coint.co = coInit();
|
||||
while(countToTen(&coint)) {
|
||||
printf("%d ", coint.result);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int state;
|
||||
} coroutine_t;
|
||||
|
||||
typedef struct {
|
||||
coroutine_t co;
|
||||
} co_void_t;
|
||||
|
||||
coroutine_t coInit();
|
||||
bool coIsDead(coroutine_t co);
|
||||
|
||||
#define COVAR co
|
||||
#define COSELF self
|
||||
|
||||
#define costate(...) \
|
||||
typedef struct { bool init; __VA_ARGS__ } COSTATE; \
|
||||
static COSTATE self = {0}
|
||||
|
||||
#define co_nostate { char __dummy__; }
|
||||
|
||||
#define yieldBreak() \
|
||||
COVAR->co.state = -1; \
|
||||
self.init = false; \
|
||||
return false;
|
||||
|
||||
#define coroutine(...) \
|
||||
if(!self.init) { \
|
||||
memset(&self, 0, sizeof(self)); \
|
||||
self.init = true; \
|
||||
} \
|
||||
switch(COVAR->co.state) { \
|
||||
case 0:; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
yieldBreak();
|
||||
|
||||
#define yield() _yield(__COUNTER__)
|
||||
#define _yield(count) \
|
||||
do { \
|
||||
COVAR->co.state = count; \
|
||||
return true; \
|
||||
case count:; \
|
||||
} while(0);
|
||||
|
||||
#define yieldVal(v) _yieldVal(v, __COUNTER__)
|
||||
#define _yieldVal(v, count) \
|
||||
do { \
|
||||
COVAR->co.state = count; \
|
||||
COVAR->result = v; \
|
||||
return true; \
|
||||
case count:; \
|
||||
} while(0);
|
||||
|
||||
// increment __COUNTER__ past 0 so we don't get double case errors
|
||||
#define CONCAT_IMPL(x, y) x##y
|
||||
#define MACRO_CONCAT(x, y) CONCAT_IMPL(x, y)
|
||||
#define __INC_COUNTER int MACRO_CONCAT(__counter_tmp_, __COUNTER__)
|
||||
__INC_COUNTER;
|
||||
|
||||
#undef CONCAT_IMPL
|
||||
#undef MACRO_CONCAT
|
||||
#undef __INC_COUNTER
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
4
http.c
4
http.c
|
|
@ -4,7 +4,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "strutils.h"
|
||||
#include "os.h"
|
||||
#include "tracelog.h"
|
||||
|
||||
// == INTERNAL ================================================================
|
||||
|
|
@ -282,7 +282,7 @@ http_response_t hcliSendRequest(http_client_t *ctx, http_request_t *req) {
|
|||
|
||||
http_response_t res = resInit();
|
||||
char *request_str = NULL;
|
||||
str_ostream_t received = ostrInit(1024);
|
||||
str_ostream_t received = ostrInitLen(1024);
|
||||
|
||||
if(!skInit()) {
|
||||
err("couldn't initialize sockets %s", skGetErrorString());
|
||||
|
|
|
|||
6
http.h
6
http.h
|
|
@ -75,7 +75,7 @@ typedef struct {
|
|||
char *body;
|
||||
} http_request_t;
|
||||
|
||||
http_request_t reqInit();
|
||||
http_request_t reqInit(void);
|
||||
void reqFree(http_request_t *ctx);
|
||||
|
||||
bool reqHasField(http_request_t *ctx, const char *key);
|
||||
|
|
@ -96,7 +96,7 @@ typedef struct {
|
|||
char *body;
|
||||
} http_response_t;
|
||||
|
||||
http_response_t resInit();
|
||||
http_response_t resInit(void);
|
||||
void resFree(http_response_t *ctx);
|
||||
|
||||
bool resHasField(http_response_t *ctx, const char *key);
|
||||
|
|
@ -113,7 +113,7 @@ typedef struct {
|
|||
socket_t socket;
|
||||
} http_client_t;
|
||||
|
||||
http_client_t hcliInit();
|
||||
http_client_t hcliInit(void);
|
||||
void hcliFree(http_client_t *ctx);
|
||||
|
||||
void hcliSetHost(http_client_t *ctx, const char *hostname);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include "strutils.h"
|
||||
#include "os.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -65,29 +65,3 @@ ssize_t getline(char **line_ptr, size_t *n, FILE *stream) {
|
|||
return getdelim(line_ptr, n, '\n', stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
void strToLower(char *str) {
|
||||
for(char *beg = str; *beg; ++beg) {
|
||||
*beg = tolower(*beg);
|
||||
}
|
||||
}
|
||||
|
||||
void strnToLower(char *str, size_t len) {
|
||||
for(size_t i = 0; i < len; ++i) {
|
||||
str[i] = tolower(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
char *cstrdup(const char *str) {
|
||||
size_t len = strlen(str);
|
||||
char *buf = malloc(len + 1);
|
||||
memcpy(buf, str, len);
|
||||
buf[len] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *cstrToLower(const char *str) {
|
||||
char *buf = cstrdup(str);
|
||||
strToLower(buf);
|
||||
return buf;
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ extern "C" {
|
|||
|
||||
#ifdef _WIN32
|
||||
#include <stdio.h>
|
||||
#include <BaseTsd.h>
|
||||
#include <BaseTsd.h> // SSIZE_T
|
||||
typedef SSIZE_T ssize_t;
|
||||
ssize_t getdelim(char **buf, size_t *bufsz, int delimiter, FILE *fp);
|
||||
ssize_t getline(char **line_ptr, size_t *n, FILE *stream);
|
||||
|
|
@ -18,19 +18,9 @@ extern "C" {
|
|||
#define stricmp strcasecmp
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h> // ssize_t
|
||||
#endif
|
||||
|
||||
// prefix str -> changes string
|
||||
// prefix cstr -> allocates new string and returns it
|
||||
|
||||
// int str
|
||||
|
||||
void strToLower(char *str);
|
||||
void strnToLower(char *str, size_t len);
|
||||
|
||||
char *cstrdup(const char *str);
|
||||
char *cstrToLower(const char *str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
10
socket.h
10
socket.h
|
|
@ -30,12 +30,12 @@ struct sockaddr;
|
|||
#endif
|
||||
|
||||
// Initialize sockets, returns true on success
|
||||
bool skInit();
|
||||
bool skInit(void);
|
||||
// Terminates sockets, returns true on success
|
||||
bool skCleanup();
|
||||
bool skCleanup(void);
|
||||
|
||||
// Opens a socket, check socket_t with skValid
|
||||
socket_t skOpen();
|
||||
socket_t skOpen(void);
|
||||
// Opens a socket using 'protocol', options are
|
||||
// ip, icmp, ggp, tcp, egp, pup, udp, hmp, xns-idp, rdp
|
||||
// check socket_t with skValid
|
||||
|
|
@ -79,9 +79,9 @@ int skReceivePro(socket_t sock, char *buf, int len, int flags);
|
|||
bool skIsValid(socket_t sock);
|
||||
|
||||
// Returns latest socket error, returns 0 if there is no error
|
||||
int skGetError();
|
||||
int skGetError(void);
|
||||
// Returns a human-readable string from a skGetError
|
||||
const char *skGetErrorString();
|
||||
const char *skGetErrorString(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
|||
267
str.c
Normal file
267
str.c
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
#include "str.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
str_t strInit(void) {
|
||||
return (str_t) {
|
||||
.buf = NULL,
|
||||
.len = 0
|
||||
};
|
||||
}
|
||||
|
||||
str_t strInitStr(const char *cstr) {
|
||||
return strInitBuf(cstr, strlen(cstr));
|
||||
}
|
||||
|
||||
str_t strInitView(strview_t view) {
|
||||
return strInitBuf(view.buf, view.size);
|
||||
}
|
||||
|
||||
str_t strInitBuf(const char *buf, size_t len) {
|
||||
str_t str;
|
||||
str.len = len;
|
||||
str.buf = malloc(len + 1);
|
||||
memcpy(str.buf, buf, len);
|
||||
str.buf[len] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
void strFree(str_t *ctx) {
|
||||
free(ctx->buf);
|
||||
ctx->buf = NULL;
|
||||
ctx->len = 0;
|
||||
}
|
||||
|
||||
str_t strMove(str_t *ctx) {
|
||||
str_t str = strInitBuf(ctx->buf, ctx->len);
|
||||
ctx->buf = NULL;
|
||||
ctx->len = 0;
|
||||
return str;
|
||||
}
|
||||
|
||||
str_t strDup(str_t ctx) {
|
||||
return strInitBuf(ctx.buf, ctx.len);
|
||||
}
|
||||
|
||||
strview_t strGetView(str_t *ctx) {
|
||||
return (strview_t) {
|
||||
.buf = ctx->buf,
|
||||
.size = ctx->len
|
||||
};
|
||||
}
|
||||
|
||||
char *strBegin(str_t *ctx) {
|
||||
return ctx->buf;
|
||||
}
|
||||
|
||||
char *strEnd(str_t *ctx) {
|
||||
return ctx->buf ? ctx->buf + ctx->len : NULL;
|
||||
}
|
||||
|
||||
char strBack(str_t *ctx) {
|
||||
return ctx->buf ? ctx->buf[ctx->len - 1] : '\0';
|
||||
}
|
||||
|
||||
bool strIsEmpty(str_t *ctx) {
|
||||
return ctx->len == 0;
|
||||
}
|
||||
|
||||
void strAppend(str_t *ctx, const char *str) {
|
||||
strAppendBuf(ctx, str, strlen(str));
|
||||
}
|
||||
|
||||
void strAppendStr(str_t *ctx, str_t str) {
|
||||
strAppendBuf(ctx, str.buf, str.len);
|
||||
}
|
||||
|
||||
void strAppendView(str_t *ctx, strview_t view) {
|
||||
strAppendBuf(ctx, view.buf, view.size);
|
||||
}
|
||||
|
||||
void strAppendBuf(str_t *ctx, const char *buf, size_t len) {
|
||||
size_t oldlen = ctx->len;
|
||||
ctx->len += len;
|
||||
ctx->buf = realloc(ctx->buf, ctx->len + 1);
|
||||
memcpy(ctx->buf + oldlen, buf, len);
|
||||
ctx->buf[ctx->len] = '\0';
|
||||
}
|
||||
|
||||
void strAppendChars(str_t *ctx, char c, size_t count) {
|
||||
size_t oldlen = ctx->len;
|
||||
ctx->len += count;
|
||||
ctx->buf = realloc(ctx->buf, ctx->len + 1);
|
||||
memset(ctx->buf + oldlen, c, count);
|
||||
ctx->buf[ctx->len] = '\0';
|
||||
}
|
||||
|
||||
void strPush(str_t *ctx, char c) {
|
||||
strAppendChars(ctx, c, 1);
|
||||
}
|
||||
|
||||
char strPop(str_t *ctx) {
|
||||
char c = strBack(ctx);
|
||||
ctx->buf = realloc(ctx->buf, ctx->len);
|
||||
ctx->len -= 1;
|
||||
ctx->buf[ctx->len] = '\0';
|
||||
return c;
|
||||
}
|
||||
|
||||
void strSwap(str_t *ctx, str_t *other) {
|
||||
char *buf = other->buf;
|
||||
size_t len = other->len;
|
||||
other->buf = ctx->buf;
|
||||
other->len = ctx->len;
|
||||
ctx->buf = buf;
|
||||
ctx->len = len;
|
||||
}
|
||||
|
||||
#include "tracelog.h"
|
||||
|
||||
str_t strSubstr(str_t *ctx, size_t pos, size_t len) {
|
||||
if(strIsEmpty(ctx)) return strInit();
|
||||
if(len == SIZE_MAX || (pos + len) > ctx->len) len = ctx->len - pos;
|
||||
return strInitBuf(ctx->buf + pos, len);
|
||||
}
|
||||
|
||||
strview_t strSubview(str_t *ctx, size_t pos, size_t len) {
|
||||
if(strIsEmpty(ctx)) return strvInit(NULL);
|
||||
if(len == SIZE_MAX || (pos + len) > ctx->len) len = ctx->len - pos;
|
||||
return (strview_t) {
|
||||
.buf = ctx->buf + pos,
|
||||
.size = len
|
||||
};
|
||||
}
|
||||
|
||||
void strLower(str_t *ctx) {
|
||||
for(size_t i = 0; i < ctx->len; ++i) {
|
||||
ctx->buf[i] = tolower(ctx->buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
str_t strToLower(str_t ctx) {
|
||||
str_t str = strDup(ctx);
|
||||
strLower(&str);
|
||||
return str;
|
||||
}
|
||||
|
||||
#ifdef STR_TESTING
|
||||
#include <stdio.h>
|
||||
#include "tracelog.h"
|
||||
|
||||
void strTest(void) {
|
||||
str_t s;
|
||||
debug("== testing init =================");
|
||||
{
|
||||
s = strInit();
|
||||
printf("%s %zu\n", s.buf, s.len);
|
||||
strFree(&s);
|
||||
s = strInitStr("hello world");
|
||||
printf("\"%s\" %zu\n", s.buf, s.len);
|
||||
strFree(&s);
|
||||
uint8_t buf[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' };
|
||||
s = strInitBuf((char *)buf, sizeof(buf));
|
||||
printf("\"%s\" %zu\n", s.buf, s.len);
|
||||
strFree(&s);
|
||||
}
|
||||
debug("== testing view =================");
|
||||
{
|
||||
s = strInitStr("hello world");
|
||||
strview_t view = strGetView(&s);
|
||||
printf("\"%.*s\" %zu\n", (int)view.size, view.buf, view.size);
|
||||
strFree(&s);
|
||||
}
|
||||
debug("== testing begin/end ============");
|
||||
{
|
||||
s = strInitStr("hello world");
|
||||
char *beg = strBegin(&s);
|
||||
char *end = strEnd(&s);
|
||||
printf("[ ");
|
||||
for(; beg < end; ++beg) {
|
||||
printf("%c ", *beg);
|
||||
}
|
||||
printf("]\n");
|
||||
strFree(&s);
|
||||
}
|
||||
debug("== testing back/isempty =========");
|
||||
{
|
||||
s = strInitStr("hello world");
|
||||
printf("[ ");
|
||||
while(!strIsEmpty(&s)) {
|
||||
printf("%c ", strBack(&s));
|
||||
strPop(&s);
|
||||
}
|
||||
printf("]\n");
|
||||
strFree(&s);
|
||||
}
|
||||
debug("== testing append ===============");
|
||||
{
|
||||
s = strInitStr("hello ");
|
||||
printf("\"%s\" %zu\n", s.buf, s.len);
|
||||
strAppend(&s, "world");
|
||||
printf("\"%s\" %zu\n", s.buf, s.len);
|
||||
strAppendView(&s, strvInit(", how is it "));
|
||||
printf("\"%s\" %zu\n", s.buf, s.len);
|
||||
uint8_t buf[] = { 'g', 'o', 'i', 'n', 'g' };
|
||||
strAppendBuf(&s, (char*)buf, sizeof(buf));
|
||||
printf("\"%s\" %zu\n", s.buf, s.len);
|
||||
strAppendChars(&s, '?', 2);
|
||||
printf("\"%s\" %zu\n", s.buf, s.len);
|
||||
strFree(&s);
|
||||
}
|
||||
debug("== testing push/pop =============");
|
||||
{
|
||||
s = strInit();
|
||||
str_t s2 = strInitStr("hello world");
|
||||
|
||||
printf("%-14s %-14s\n", "s", "s2");
|
||||
printf("----------------------------\n");
|
||||
while(!strIsEmpty(&s2)) {
|
||||
printf("%-14s %-14s\n", s.buf, s2.buf);
|
||||
strPush(&s, strPop(&s2));
|
||||
}
|
||||
printf("%-14s %-14s\n", s.buf, s2.buf);
|
||||
|
||||
strFree(&s);
|
||||
strFree(&s2);
|
||||
}
|
||||
debug("== testing swap =================");
|
||||
{
|
||||
s = strInitStr("hello");
|
||||
str_t s2 = strInitStr("world");
|
||||
printf("%-8s %-8s\n", "s", "s2");
|
||||
printf("----------------\n");
|
||||
printf("%-8s %-8s\n", s.buf, s2.buf);
|
||||
strSwap(&s, &s2);
|
||||
printf("%-8s %-8s\n", s.buf, s2.buf);
|
||||
|
||||
strFree(&s);
|
||||
strFree(&s2);
|
||||
}
|
||||
debug("== testing substr ===============");
|
||||
{
|
||||
s = strInitStr("hello world");
|
||||
printf("s: %s\n", s.buf);
|
||||
|
||||
printf("-- string\n");
|
||||
str_t s2 = strSubstr(&s, 0, 5);
|
||||
printf("0..5: \"%s\"\n", s2.buf);
|
||||
strFree(&s2);
|
||||
|
||||
s2 = strSubstr(&s, 5, SIZE_MAX);
|
||||
printf("6..SIZE_MAX: \"%s\"\n", s2.buf);
|
||||
strFree(&s2);
|
||||
|
||||
printf("-- view\n");
|
||||
strview_t v = strSubview(&s, 0, 5);
|
||||
printf("0..5: \"%.*s\"\n", (int)v.size, v.buf);
|
||||
v = strSubview(&s, 5, SIZE_MAX);
|
||||
printf("6..SIZE_MAX: \"%.*s\"\n", (int)v.size, v.buf);
|
||||
|
||||
strFree(&s);
|
||||
}
|
||||
|
||||
strFree(&s);
|
||||
}
|
||||
#endif
|
||||
61
str.h
Normal file
61
str.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include "strview.h"
|
||||
|
||||
#define STR_TESTING
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
size_t len;
|
||||
} str_t;
|
||||
|
||||
str_t strInit(void);
|
||||
str_t strInitStr(const char *cstr);
|
||||
str_t strInitView(strview_t view);
|
||||
str_t strInitBuf(const char *buf, size_t len);
|
||||
|
||||
void strFree(str_t *ctx);
|
||||
|
||||
str_t strMove(str_t *ctx);
|
||||
str_t strDup(str_t ctx);
|
||||
|
||||
strview_t strGetView(str_t *ctx);
|
||||
|
||||
char *strBegin(str_t *ctx);
|
||||
char *strEnd(str_t *ctx);
|
||||
|
||||
char strBack(str_t *ctx);
|
||||
|
||||
bool strIsEmpty(str_t *ctx);
|
||||
|
||||
void strAppend(str_t *ctx, const char *str);
|
||||
void strAppendStr(str_t *ctx, str_t str);
|
||||
void strAppendView(str_t *ctx, strview_t view);
|
||||
void strAppendBuf(str_t *ctx, const char *buf, size_t len);
|
||||
void strAppendChars(str_t *ctx, char c, size_t count);
|
||||
|
||||
void strPush(str_t *ctx, char c);
|
||||
char strPop(str_t *ctx);
|
||||
|
||||
void strSwap(str_t *ctx, str_t *other);
|
||||
|
||||
// if len == SIZE_MAX, copies until end
|
||||
str_t strSubstr(str_t *ctx, size_t pos, size_t len);
|
||||
// if len == SIZE_MAX, returns until end
|
||||
strview_t strSubview(str_t *ctx, size_t pos, size_t len);
|
||||
|
||||
void strLower(str_t *ctx);
|
||||
str_t strToLower(str_t ctx);
|
||||
|
||||
#ifdef STR_TESTING
|
||||
void strTest(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
@ -485,9 +485,9 @@ void ostrAppendi64(str_ostream_t *ctx, int64_t val) {
|
|||
|
||||
void ostrAppendfloat(str_ostream_t *ctx, float val) {
|
||||
char buf[APPEND_BUF_LEN * 3];
|
||||
int len = snprintf(buf, sizeof(buf), "%f", (double)val);
|
||||
int len = snprintf(buf, sizeof(buf), "%g", (double)val);
|
||||
if(len <= 0) {
|
||||
err("ostrAppendfloat: couldn't write %f", val);
|
||||
err("ostrAppendfloat: couldn't write %g", (double)val);
|
||||
return;
|
||||
}
|
||||
ostrAppendview(ctx, strvInitLen(buf, len));
|
||||
|
|
@ -495,9 +495,9 @@ void ostrAppendfloat(str_ostream_t *ctx, float val) {
|
|||
|
||||
void ostrAppenddouble(str_ostream_t *ctx, double val) {
|
||||
char buf[APPEND_BUF_LEN * 3];
|
||||
int len = snprintf(buf, sizeof(buf), "%f", val);
|
||||
int len = snprintf(buf, sizeof(buf), "%g", val);
|
||||
if(len <= 0) {
|
||||
err("ostrAppenddouble: couldn't write %f", val);
|
||||
err("ostrAppenddouble: couldn't write %g", val);
|
||||
return;
|
||||
}
|
||||
ostrAppendview(ctx, strvInitLen(buf, len));
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ typedef struct {
|
|||
size_t allocated;
|
||||
} str_ostream_t;
|
||||
|
||||
str_ostream_t ostrInit();
|
||||
str_ostream_t ostrInit(void);
|
||||
str_ostream_t ostrInitLen(size_t initial_alloc);
|
||||
str_ostream_t ostrInitStr(const char *buf, size_t len);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
|
||||
strview_t strvInit(const char *cstr) {
|
||||
return strvInitLen(cstr, strlen(cstr));
|
||||
return strvInitLen(cstr, cstr ? strlen(cstr) : 0);
|
||||
}
|
||||
|
||||
strview_t strvInitLen(const char *buf, size_t size) {
|
||||
|
|
|
|||
50
tracelog.c
50
tracelog.c
|
|
@ -30,46 +30,58 @@
|
|||
#define RESET ""
|
||||
#define BOLD ""
|
||||
#else
|
||||
#define BLACK "\x1B[30m"
|
||||
#define RED "\x1B[31m"
|
||||
#define GREEN "\x1B[32m"
|
||||
#define YELLOW "\x1B[33m"
|
||||
#define BLUE "\x1B[34m"
|
||||
#define MAGENTA "\x1B[35m"
|
||||
#define CYAN "\x1B[36m"
|
||||
#define WHITE "\x1B[37m"
|
||||
#define RESET "\x1B[0m"
|
||||
#define BOLD "\x1B[1m"
|
||||
#define BLACK "\033[30m"
|
||||
#define RED "\033[31m"
|
||||
#define GREEN "\033[32m"
|
||||
#define YELLOW "\033[33m"
|
||||
#define BLUE "\033[22;34m"
|
||||
#define MAGENTA "\033[35m"
|
||||
#define CYAN "\033[36m"
|
||||
#define WHITE "\033[37m"
|
||||
#define RESET "\033[0m"
|
||||
#define BOLD "\033[1m"
|
||||
#endif
|
||||
|
||||
#define MAX_TRACELOG_MSG_LENGTH 1024
|
||||
|
||||
bool use_newline = true;
|
||||
|
||||
void traceLog(LogLevel level, const char *fmt, ...) {
|
||||
char buffer[MAX_TRACELOG_MSG_LENGTH];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
const char *beg;
|
||||
switch (level) {
|
||||
case LogTrace: strcpy(buffer, BOLD WHITE "[TRACE]: " RESET); break;
|
||||
case LogDebug: strcpy(buffer, BOLD BLUE "[DEBUG]: " RESET); break;
|
||||
case LogInfo: strcpy(buffer, BOLD GREEN "[INFO]: " RESET); break;
|
||||
case LogWarning: strcpy(buffer, BOLD YELLOW "[WARNING]: " RESET); break;
|
||||
case LogError: strcpy(buffer, BOLD RED "[ERROR]: " RESET); break;
|
||||
case LogFatal: strcpy(buffer, BOLD RED "[FATAL]: " RESET); break;
|
||||
case LogTrace: beg = BOLD WHITE "[TRACE]: " RESET; break;
|
||||
case LogDebug: beg = BOLD BLUE "[DEBUG]: " RESET; break;
|
||||
case LogInfo: beg = BOLD GREEN "[INFO]: " RESET; break;
|
||||
case LogWarning: beg = BOLD YELLOW "[WARNING]: " RESET; break;
|
||||
case LogError: beg = BOLD RED "[ERROR]: " RESET; break;
|
||||
case LogFatal: beg = BOLD RED "[FATAL]: " RESET; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
size_t offset = strlen(beg);
|
||||
strncpy(buffer, beg, sizeof(buffer));
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
vsnprintf(buffer + offset, sizeof(buffer) - offset, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
#ifdef TLOG_VS
|
||||
OutputDebugStringA(buffer);
|
||||
OutputDebugStringA("\n");
|
||||
if(use_newline) OutputDebugStringA("\n");
|
||||
#else
|
||||
puts(buffer);
|
||||
printf("%s", buffer);
|
||||
if(use_newline) puts("");
|
||||
#endif
|
||||
|
||||
#ifndef TLOG_DONT_EXIT_ON_FATAL
|
||||
if (level == LogFatal) exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void traceUseNewline(bool newline) {
|
||||
use_newline = newline;
|
||||
}
|
||||
|
|
@ -10,11 +10,14 @@ extern "C" {
|
|||
* -> TLOG_DONT_EXIT_ON_FATAL: don't call 'exit(1)' when using LogFatal
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
LogAll, LogTrace, LogDebug, LogInfo, LogWarning, LogError, LogFatal
|
||||
} LogLevel;
|
||||
|
||||
void traceLog(LogLevel level, const char *fmt, ...);
|
||||
void traceUseNewline(bool use_newline);
|
||||
|
||||
#define trace(...) traceLog(LogTrace, __VA_ARGS__)
|
||||
#define debug(...) traceLog(LogDebug, __VA_ARGS__)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue