added:
* file: small wrap over winapi for windows and stdio for posix * fs: small wrapper over stat * slice: slice macro type modified: * str and strview are now slices
This commit is contained in:
parent
bb5cce33f0
commit
c4d1ffe539
15 changed files with 451 additions and 88 deletions
|
|
@ -7,6 +7,8 @@ add_library(Colla STATIC
|
|||
str.c
|
||||
coroutine.c
|
||||
os.c
|
||||
fs.c
|
||||
file.c
|
||||
)
|
||||
|
||||
IF (WIN32)
|
||||
|
|
|
|||
28
coroutine.h
28
coroutine.h
|
|
@ -4,8 +4,9 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h> // bool
|
||||
#include <string.h> // memset
|
||||
#include <stdbool.h> // bool
|
||||
#include <string.h> // memset
|
||||
#include "tracelog.h" // fatal
|
||||
|
||||
// heavily inspired by https://gist.github.com/Enichan/5f01140530ff0133fde19c9549a2a973
|
||||
|
||||
|
|
@ -84,15 +85,20 @@ bool coIsDead(coroutine_t co);
|
|||
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__ \
|
||||
} \
|
||||
#define coroutine(...) \
|
||||
if(!self.init) { \
|
||||
if(COVAR->co.state != 0) { \
|
||||
fatal("coroutine not initialized in %s:%d,\n" \
|
||||
"did you forget to do '= {0};'?", \
|
||||
__FILE__, __LINE__); \
|
||||
} \
|
||||
memset(&self, 0, sizeof(self)); \
|
||||
self.init = true; \
|
||||
} \
|
||||
switch(COVAR->co.state) { \
|
||||
case 0:; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
yieldBreak();
|
||||
|
||||
#define yield() _yield(__COUNTER__)
|
||||
|
|
|
|||
160
file.c
Normal file
160
file.c
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#include "file.h"
|
||||
|
||||
#include "tracelog.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define VC_EXTRALEAN
|
||||
#include <windows.h>
|
||||
|
||||
static DWORD _toWin32Access(int mode) {
|
||||
switch(mode) {
|
||||
case FILE_READ: return GENERIC_READ;
|
||||
case FILE_WRITE: return GENERIC_WRITE;
|
||||
case FILE_BOTH: return GENERIC_READ | GENERIC_WRITE;
|
||||
default: fatal("unrecognized mode: %d", mode); return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD _toWin32Creation(int mode) {
|
||||
switch(mode) {
|
||||
case FILE_READ: return OPEN_EXISTING;
|
||||
case FILE_WRITE: return OPEN_ALWAYS;
|
||||
case FILE_BOTH: return OPEN_ALWAYS;
|
||||
default: fatal("unrecognized mode: %d", mode); return 0;
|
||||
}
|
||||
}
|
||||
|
||||
file_t fileOpen(const char *fname, int mode) {
|
||||
return (file_t) {
|
||||
.handle = CreateFile(fname,
|
||||
_toWin32Access(mode),
|
||||
0,
|
||||
NULL,
|
||||
_toWin32Creation(mode),
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL)
|
||||
};
|
||||
}
|
||||
|
||||
void fileClose(file_t *ctx) {
|
||||
if(ctx->handle) {
|
||||
CloseHandle((HANDLE)ctx->handle);
|
||||
ctx->handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool fileIsValid(file_t *ctx) {
|
||||
return ctx->handle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
bool filePutc(file_t *ctx, char c) {
|
||||
return fileWrite(ctx, &c, 1) == 1;
|
||||
}
|
||||
|
||||
bool filePuts(file_t *ctx, const char *str) {
|
||||
size_t len = strlen(str);
|
||||
return fileWrite(ctx, str, len) == len;
|
||||
}
|
||||
|
||||
bool filePutstr(file_t *ctx, str_t str) {
|
||||
return fileWrite(ctx, str.buf, str.len) == str.len;
|
||||
}
|
||||
|
||||
bool filePutview(file_t *ctx, strview_t view) {
|
||||
return fileWrite(ctx, view.buf, view.len) == view.len;
|
||||
}
|
||||
|
||||
size_t fileRead(file_t *ctx, void *buf, size_t len) {
|
||||
DWORD bytes_read = 0;
|
||||
BOOL result = ReadFile((HANDLE)ctx->handle, buf, (DWORD)len, &bytes_read, NULL);
|
||||
return result == TRUE ? (size_t)bytes_read : 0;
|
||||
}
|
||||
|
||||
size_t fileWrite(file_t *ctx, const void *buf, size_t len) {
|
||||
DWORD bytes_read = 0;
|
||||
BOOL result = WriteFile((HANDLE)ctx->handle, buf, (DWORD)len, &bytes_read, NULL);
|
||||
return result == TRUE ? (size_t)bytes_read : 0;
|
||||
}
|
||||
|
||||
bool fileSeekEnd(file_t *ctx) {
|
||||
return SetFilePointerEx((HANDLE)ctx->handle, (LARGE_INTEGER){0}, NULL, FILE_END) == TRUE;
|
||||
}
|
||||
|
||||
void fileRewind(file_t *ctx) {
|
||||
SetFilePointerEx((HANDLE)ctx->handle, (LARGE_INTEGER){0}, NULL, FILE_BEGIN);
|
||||
}
|
||||
|
||||
uint64_t fileTell(file_t *ctx) {
|
||||
LARGE_INTEGER tell;
|
||||
BOOL result = SetFilePointerEx((HANDLE)ctx->handle, (LARGE_INTEGER){0}, &tell, FILE_CURRENT);
|
||||
return result == TRUE ? (uint64_t)tell.QuadPart : 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
const char *_toStdioMode(int mode) {
|
||||
switch(mode) {
|
||||
case FILE_READ: return "rb";
|
||||
case FILE_BOTH: return "r+b";
|
||||
case FILE_WRITE: return "wb";
|
||||
default: fatal("mode not recognized: %d", mode); return "";
|
||||
}
|
||||
}
|
||||
|
||||
file_t fileOpen(const char *fname, int mode) {
|
||||
return (file_t) {
|
||||
.handle = (void*) fopen(fname, _toStdioMode(mode)),
|
||||
};
|
||||
}
|
||||
|
||||
void fileClose(file_t *ctx) {
|
||||
if(ctx->handle) {
|
||||
fclose((FILE*)ctx->handle);
|
||||
ctx->handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool fileIsValid(file_t *ctx) {
|
||||
info("handle: %p", ctx->handle);
|
||||
return ctx->handle != NULL;
|
||||
}
|
||||
|
||||
bool filePutc(file_t *ctx, char c) {
|
||||
return fputc(c, (FILE*)ctx->handle) == c;
|
||||
}
|
||||
|
||||
bool filePuts(file_t *ctx, const char *str) {
|
||||
return fputs(str, (FILE*)ctx->handle) != EOF;
|
||||
}
|
||||
|
||||
bool filePutstr(file_t *ctx, str_t str) {
|
||||
return fileWrite(ctx, str.buf, str.len) == str.len;
|
||||
}
|
||||
|
||||
bool filePutview(file_t *ctx, strview_t view) {
|
||||
return fileWrite(ctx, view.buf, view.len) == view.len;
|
||||
}
|
||||
|
||||
size_t fileRead(file_t *ctx, void *buf, size_t len) {
|
||||
return fread(buf, 1, len, (FILE*)ctx->handle);
|
||||
}
|
||||
|
||||
size_t fileWrite(file_t *ctx, const void *buf, size_t len) {
|
||||
return fwrite(buf, 1, len, (FILE*)ctx->handle);
|
||||
}
|
||||
|
||||
bool fileSeekEnd(file_t *ctx) {
|
||||
return fseek((FILE*)ctx->handle, 0, SEEK_END) == 0;
|
||||
}
|
||||
|
||||
void fileRewind(file_t *ctx) {
|
||||
rewind((FILE*)ctx->handle);
|
||||
}
|
||||
|
||||
uint64_t fileTell(file_t *ctx) {
|
||||
return (uint64_t)ftell((FILE*)ctx->handle);
|
||||
}
|
||||
#endif
|
||||
31
file.h
Normal file
31
file.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "str.h"
|
||||
#include "strview.h"
|
||||
|
||||
enum {
|
||||
FILE_READ, FILE_WRITE, FILE_BOTH
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
void *handle;
|
||||
} file_t;
|
||||
|
||||
file_t fileOpen(const char *fname, int mode);
|
||||
void fileClose(file_t *ctx);
|
||||
|
||||
bool fileIsValid(file_t *ctx);
|
||||
|
||||
bool filePutc(file_t *ctx, char c);
|
||||
bool filePuts(file_t *ctx, const char *str);
|
||||
bool filePutstr(file_t *ctx, str_t str);
|
||||
bool filePutview(file_t *ctx, strview_t view);
|
||||
|
||||
size_t fileRead(file_t *ctx, void *buf, size_t len);
|
||||
size_t fileWrite(file_t *ctx, const void *buf, size_t len);
|
||||
|
||||
bool fileSeekEnd(file_t *ctx);
|
||||
void fileRewind(file_t *ctx);
|
||||
|
||||
uint64_t fileTell(file_t *ctx);
|
||||
121
fs.c
Normal file
121
fs.c
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
#include "fs.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tracelog.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define VC_EXTRALEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
static int _modeToType(unsigned int mode) {
|
||||
switch(mode & _S_IFMT) {
|
||||
case _S_IFDIR: return FS_MODE_DIR;
|
||||
case _S_IFCHR: return FS_MODE_CHARACTER_DEVICE;
|
||||
case _S_IFREG: return FS_MODE_FILE;
|
||||
case _S_IFIFO: return FS_MODE_FIFO;
|
||||
default: return FS_MODE_UKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
fs_stat_t fsStat(file_t fp) {
|
||||
TCHAR path[MAX_PATH];
|
||||
DWORD pathlen = GetFinalPathNameByHandle(
|
||||
(HANDLE)fp.handle,
|
||||
path,
|
||||
MAX_PATH,
|
||||
0);
|
||||
|
||||
struct stat statbuf;
|
||||
int res = stat(path, &statbuf);
|
||||
if(res == 0) {
|
||||
return (fs_stat_t) {
|
||||
.type = _modeToType(statbuf.st_mode),
|
||||
.size = statbuf.st_size,
|
||||
.last_access = statbuf.st_atime,
|
||||
.last_modif = statbuf.st_mtime
|
||||
};
|
||||
}
|
||||
else {
|
||||
return (fs_stat_t) { 0 };
|
||||
}
|
||||
}
|
||||
|
||||
fs_time_t fsAsTime(int64_t timer) {
|
||||
struct tm t;
|
||||
errno_t error = localtime_s(&t, &timer);
|
||||
|
||||
if(error == 0) {
|
||||
return (fs_time_t) {
|
||||
.year = t.tm_year + 1900,
|
||||
.month = t.tm_mon + 1,
|
||||
.day = t.tm_mday,
|
||||
.hour = t.tm_hour,
|
||||
.minutes = t.tm_min,
|
||||
.seconds = t.tm_sec,
|
||||
.daylight_saving = t.tm_isdst > 0
|
||||
};
|
||||
}
|
||||
else {
|
||||
char buf[128];
|
||||
strerror_s(buf, sizeof(buf), error);
|
||||
err("%s", buf);
|
||||
return (fs_time_t) { 0 };
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
|
||||
static int _modeToType(unsigned int mode) {
|
||||
switch(mode & __S_IFMT) {
|
||||
case __S_IFDIR: return FS_MODE_DIR;
|
||||
case __S_IFCHR: return FS_MODE_CHARACTER_DEVICE;
|
||||
case __S_IFREG: return FS_MODE_FILE;
|
||||
case __S_IFIFO: return FS_MODE_FIFO;
|
||||
default: return FS_MODE_UKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
fs_stat_t fsStat(file_t fp) {
|
||||
int fd = fileno((FILE*)fp.handle);
|
||||
struct stat statbuf;
|
||||
int res = fstat(fd, &statbuf);
|
||||
if(res == 0) {
|
||||
return (fs_stat_t) {
|
||||
.type = _modeToType(statbuf.st_mode),
|
||||
.size = statbuf.st_size,
|
||||
.last_access = statbuf.st_atime,
|
||||
.last_modif = statbuf.st_mtime
|
||||
};
|
||||
}
|
||||
else {
|
||||
return (fs_stat_t) { 0 };
|
||||
}
|
||||
}
|
||||
|
||||
fs_time_t fsAsTime(int64_t timer) {
|
||||
struct tm *t = localtime(&timer);
|
||||
|
||||
if(t) {
|
||||
return (fs_time_t) {
|
||||
.year = t->tm_year + 1900,
|
||||
.month = t->tm_mon + 1,
|
||||
.day = t->tm_mday,
|
||||
.hour = t->tm_hour,
|
||||
.minutes = t->tm_min,
|
||||
.seconds = t->tm_sec,
|
||||
.daylight_saving = t->tm_isdst > 0
|
||||
};
|
||||
}
|
||||
else {
|
||||
err("%s", strerror(errno));
|
||||
return (fs_time_t) { 0 };
|
||||
}
|
||||
}
|
||||
#endif
|
||||
34
fs.h
Normal file
34
fs.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "file.h"
|
||||
|
||||
enum {
|
||||
FS_MODE_FILE,
|
||||
FS_MODE_DIR,
|
||||
FS_MODE_CHARACTER_DEVICE,
|
||||
FS_MODE_FIFO,
|
||||
FS_MODE_UKNOWN,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
uint64_t size;
|
||||
int64_t last_access;
|
||||
int64_t last_modif;
|
||||
} fs_stat_t;
|
||||
|
||||
typedef struct {
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
int hour;
|
||||
int minutes;
|
||||
int seconds;
|
||||
bool daylight_saving;
|
||||
} fs_time_t;
|
||||
|
||||
fs_stat_t fsStat(file_t fp);
|
||||
fs_time_t fsAsTime(int64_t time);
|
||||
2
http.c
2
http.c
|
|
@ -225,7 +225,7 @@ void resParseFields(http_response_t *ctx, str_istream_t *in) {
|
|||
}
|
||||
|
||||
istrSkip(in, 2); // skip \r\n
|
||||
} while(line.size > 2);
|
||||
} while(line.len > 2);
|
||||
}
|
||||
|
||||
// == HTTP CLIENT =============================================================
|
||||
|
|
|
|||
5
slice.h
Normal file
5
slice.h
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
#define slice_t(type) struct { type buf; size_t len; }
|
||||
8
socket.c
8
socket.c
|
|
@ -2,11 +2,8 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#undef INVALID_SOCKET
|
||||
#undef SOCKET_ERROR
|
||||
|
||||
#if SOCK_WINDOWS
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
static bool _win_skInit();
|
||||
static bool _win_skCleanup();
|
||||
|
|
@ -72,7 +69,9 @@ bool skClose(socket_t sock) {
|
|||
bool skBind(socket_t sock, const char *ip, uint16_t port) {
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
// TODO use inet_pton instead
|
||||
addr.sin_addr.s_addr = inet_addr(ip);
|
||||
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
return skBindPro(sock, (struct sockaddr *) &addr, sizeof(addr));
|
||||
|
|
@ -101,6 +100,7 @@ socket_t skAcceptPro(socket_t sock, struct sockaddr *addr, socket_len_t *addrlen
|
|||
}
|
||||
|
||||
bool skConnect(socket_t sock, const char *server, unsigned short server_port) {
|
||||
// TODO use getaddrinfo insetad
|
||||
struct hostent *host = gethostbyname(server);
|
||||
// if gethostbyname fails, inet_addr will also fail and return an easier to debug error
|
||||
const char *address = server;
|
||||
|
|
|
|||
2
socket.h
2
socket.h
|
|
@ -19,8 +19,6 @@ struct sockaddr;
|
|||
#include <winsock2.h>
|
||||
typedef SOCKET socket_t;
|
||||
typedef int socket_len_t;
|
||||
#define INVALID_SOCKET (socket_t)(~0)
|
||||
#define SOCKET_ERROR (-1)
|
||||
#elif SOCK_POSIX
|
||||
#include <sys/socket.h>
|
||||
typedef int socket_t;
|
||||
|
|
|
|||
14
str.c
14
str.c
|
|
@ -16,7 +16,7 @@ str_t strInitStr(const char *cstr) {
|
|||
}
|
||||
|
||||
str_t strInitView(strview_t view) {
|
||||
return strInitBuf(view.buf, view.size);
|
||||
return strInitBuf(view.buf, view.len);
|
||||
}
|
||||
|
||||
str_t strInitBuf(const char *buf, size_t len) {
|
||||
|
|
@ -48,7 +48,7 @@ str_t strDup(str_t ctx) {
|
|||
strview_t strGetView(str_t *ctx) {
|
||||
return (strview_t) {
|
||||
.buf = ctx->buf,
|
||||
.size = ctx->len
|
||||
.len = ctx->len
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ void strAppendStr(str_t *ctx, str_t str) {
|
|||
}
|
||||
|
||||
void strAppendView(str_t *ctx, strview_t view) {
|
||||
strAppendBuf(ctx, view.buf, view.size);
|
||||
strAppendBuf(ctx, view.buf, view.len);
|
||||
}
|
||||
|
||||
void strAppendBuf(str_t *ctx, const char *buf, size_t len) {
|
||||
|
|
@ -130,7 +130,7 @@ strview_t strSubview(str_t *ctx, size_t pos, size_t len) {
|
|||
if(len == SIZE_MAX || (pos + len) > ctx->len) len = ctx->len - pos;
|
||||
return (strview_t) {
|
||||
.buf = ctx->buf + pos,
|
||||
.size = len
|
||||
.len = len
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -169,7 +169,7 @@ void strTest(void) {
|
|||
{
|
||||
s = strInitStr("hello world");
|
||||
strview_t view = strGetView(&s);
|
||||
printf("\"%.*s\" %zu\n", (int)view.size, view.buf, view.size);
|
||||
printf("\"%.*s\" %zu\n", (int)view.len, view.buf, view.len);
|
||||
strFree(&s);
|
||||
}
|
||||
debug("== testing begin/end ============");
|
||||
|
|
@ -255,9 +255,9 @@ void strTest(void) {
|
|||
|
||||
printf("-- view\n");
|
||||
strview_t v = strSubview(&s, 0, 5);
|
||||
printf("0..5: \"%.*s\"\n", (int)v.size, v.buf);
|
||||
printf("0..5: \"%.*s\"\n", (int)v.len, v.buf);
|
||||
v = strSubview(&s, 5, SIZE_MAX);
|
||||
printf("6..SIZE_MAX: \"%.*s\"\n", (int)v.size, v.buf);
|
||||
printf("6..SIZE_MAX: \"%.*s\"\n", (int)v.len, v.buf);
|
||||
|
||||
strFree(&s);
|
||||
}
|
||||
|
|
|
|||
12
str.h
12
str.h
|
|
@ -4,15 +4,17 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include "slice.h"
|
||||
#include "strview.h"
|
||||
|
||||
#define STR_TESTING
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
size_t len;
|
||||
} str_t;
|
||||
// typedef struct {
|
||||
// char *buf;
|
||||
// size_t len;
|
||||
// } str_t;
|
||||
|
||||
typedef slice_t(char *) str_t;
|
||||
|
||||
str_t strInit(void);
|
||||
str_t strInitStr(const char *cstr);
|
||||
|
|
|
|||
|
|
@ -504,10 +504,10 @@ void ostrAppenddouble(str_ostream_t *ctx, double val) {
|
|||
}
|
||||
|
||||
void ostrAppendview(str_ostream_t *ctx, strview_t view) {
|
||||
if((ctx->allocated - ctx->size) < view.size) {
|
||||
_ostrRealloc(ctx, view.size + 1);
|
||||
if((ctx->allocated - ctx->size) < view.len) {
|
||||
_ostrRealloc(ctx, view.len + 1);
|
||||
}
|
||||
memcpy(ctx->buf + ctx->size, view.buf, view.size);
|
||||
ctx->size += view.size;
|
||||
memcpy(ctx->buf + ctx->size, view.buf, view.len);
|
||||
ctx->size += view.len;
|
||||
ctx->buf[ctx->size] = '\0';
|
||||
}
|
||||
100
strview.c
100
strview.c
|
|
@ -20,7 +20,7 @@ strview_t strvInit(const char *cstr) {
|
|||
strview_t strvInitLen(const char *buf, size_t size) {
|
||||
strview_t view;
|
||||
view.buf = buf;
|
||||
view.size = size;
|
||||
view.len = size;
|
||||
return view;
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ char strvFront(strview_t ctx) {
|
|||
}
|
||||
|
||||
char strvBack(strview_t ctx) {
|
||||
return ctx.buf[ctx.size - 1];
|
||||
return ctx.buf[ctx.len - 1];
|
||||
}
|
||||
|
||||
const char *strvBegin(strview_t *ctx) {
|
||||
|
|
@ -37,31 +37,31 @@ const char *strvBegin(strview_t *ctx) {
|
|||
}
|
||||
|
||||
const char *strvEnd(strview_t *ctx) {
|
||||
return ctx->buf + ctx->size;
|
||||
return ctx->buf + ctx->len;
|
||||
}
|
||||
|
||||
bool strvIsEmpty(strview_t ctx) {
|
||||
return ctx.size == 0;
|
||||
return ctx.len == 0;
|
||||
}
|
||||
|
||||
void strvRemovePrefix(strview_t *ctx, size_t n) {
|
||||
ctx->buf += n;
|
||||
ctx->size -= n;
|
||||
ctx->len -= n;
|
||||
}
|
||||
|
||||
void strvRemoveSuffix(strview_t *ctx, size_t n) {
|
||||
ctx->size -= n;
|
||||
ctx->len -= n;
|
||||
}
|
||||
|
||||
size_t strvCopy(strview_t ctx, char **buf) {
|
||||
*buf = malloc(ctx.size + 1);
|
||||
memcpy(*buf, ctx.buf, ctx.size);
|
||||
(*buf)[ctx.size] = '\0';
|
||||
return ctx.size;
|
||||
*buf = malloc(ctx.len + 1);
|
||||
memcpy(*buf, ctx.buf, ctx.len);
|
||||
(*buf)[ctx.len] = '\0';
|
||||
return ctx.len;
|
||||
}
|
||||
|
||||
size_t strvCopyN(strview_t ctx, char **buf, size_t count, size_t from) {
|
||||
size_t sz = ctx.size + 1 - from;
|
||||
size_t sz = ctx.len + 1 - from;
|
||||
count = min(count, sz);
|
||||
*buf = malloc(count + 1);
|
||||
memcpy(*buf, ctx.buf + from, count);
|
||||
|
|
@ -70,7 +70,7 @@ size_t strvCopyN(strview_t ctx, char **buf, size_t count, size_t from) {
|
|||
}
|
||||
|
||||
size_t strvCopyBuf(strview_t ctx, char *buf, size_t len, size_t from) {
|
||||
size_t sz = ctx.size + 1 - from;
|
||||
size_t sz = ctx.len + 1 - from;
|
||||
len = min(len, sz);
|
||||
memcpy(buf, ctx.buf + from, len);
|
||||
buf[len - 1] = '\0';
|
||||
|
|
@ -78,21 +78,21 @@ size_t strvCopyBuf(strview_t ctx, char *buf, size_t len, size_t from) {
|
|||
}
|
||||
|
||||
strview_t strvSubstr(strview_t ctx, size_t from, size_t len) {
|
||||
if(from > ctx.size) from = ctx.size - len;
|
||||
size_t sz = ctx.size - from;
|
||||
if(from > ctx.len) from = ctx.len - len;
|
||||
size_t sz = ctx.len - from;
|
||||
return strvInitLen(ctx.buf + from, min(len, sz));
|
||||
}
|
||||
|
||||
int strvCompare(strview_t ctx, strview_t other) {
|
||||
if(ctx.size < other.size) return -1;
|
||||
if(ctx.size > other.size) return 1;
|
||||
return memcmp(ctx.buf, other.buf, ctx.size);
|
||||
if(ctx.len < other.len) return -1;
|
||||
if(ctx.len > other.len) return 1;
|
||||
return memcmp(ctx.buf, other.buf, ctx.len);
|
||||
}
|
||||
|
||||
int strvICompare(strview_t ctx, strview_t other) {
|
||||
if(ctx.size < other.size) return -1;
|
||||
if(ctx.size > other.size) return 1;
|
||||
for(size_t i = 0; i < ctx.size; ++i) {
|
||||
if(ctx.len < other.len) return -1;
|
||||
if(ctx.len > other.len) return 1;
|
||||
for(size_t i = 0; i < ctx.len; ++i) {
|
||||
char a = tolower(ctx.buf[i]);
|
||||
char b = tolower(other.buf[i]);
|
||||
if(a != b) return a - b;
|
||||
|
|
@ -105,8 +105,8 @@ bool strvStartsWith(strview_t ctx, char c) {
|
|||
}
|
||||
|
||||
bool strvStartsWithView(strview_t ctx, strview_t view) {
|
||||
if(ctx.size < view.size) return false;
|
||||
return memcmp(ctx.buf, view.buf, view.size) == 0;
|
||||
if(ctx.len < view.len) return false;
|
||||
return memcmp(ctx.buf, view.buf, view.len) == 0;
|
||||
}
|
||||
|
||||
bool strvEndsWith(strview_t ctx, char c) {
|
||||
|
|
@ -114,45 +114,45 @@ bool strvEndsWith(strview_t ctx, char c) {
|
|||
}
|
||||
|
||||
bool strvEndsWithView(strview_t ctx, strview_t view) {
|
||||
if(ctx.size < view.size) return false;
|
||||
return memcmp(ctx.buf + ctx.size - view.size, view.buf, view.size) == 0;
|
||||
if(ctx.len < view.len) return false;
|
||||
return memcmp(ctx.buf + ctx.len - view.len, view.buf, view.len) == 0;
|
||||
}
|
||||
|
||||
bool strvContains(strview_t ctx, char c) {
|
||||
for(size_t i = 0; i < ctx.size; ++i) {
|
||||
for(size_t i = 0; i < ctx.len; ++i) {
|
||||
if(ctx.buf[i] == c) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool strvContainsView(strview_t ctx, strview_t view) {
|
||||
if(ctx.size < view.size) return false;
|
||||
size_t end = ctx.size - view.size;
|
||||
if(ctx.len < view.len) return false;
|
||||
size_t end = ctx.len - view.len;
|
||||
for(size_t i = 0; i < end; ++i) {
|
||||
if(memcmp(ctx.buf + i, view.buf, view.size) == 0) return true;
|
||||
if(memcmp(ctx.buf + i, view.buf, view.len) == 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t strvFind(strview_t ctx, char c, size_t from) {
|
||||
for(size_t i = from; i < ctx.size; ++i) {
|
||||
for(size_t i = from; i < ctx.len; ++i) {
|
||||
if(ctx.buf[i] == c) return i;
|
||||
}
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
size_t strvFindView(strview_t ctx, strview_t view, size_t from) {
|
||||
if(ctx.size < view.size) return SIZE_MAX;
|
||||
size_t end = ctx.size - view.size;
|
||||
if(ctx.len < view.len) return SIZE_MAX;
|
||||
size_t end = ctx.len - view.len;
|
||||
for(size_t i = from; i < end; ++i) {
|
||||
if(memcmp(ctx.buf + i, view.buf, view.size) == 0) return i;
|
||||
if(memcmp(ctx.buf + i, view.buf, view.len) == 0) return i;
|
||||
}
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
size_t strvRFind(strview_t ctx, char c, size_t from) {
|
||||
if(from >= ctx.size) {
|
||||
from = ctx.size - 1;
|
||||
if(from >= ctx.len) {
|
||||
from = ctx.len - 1;
|
||||
}
|
||||
|
||||
const char *buf = ctx.buf + from;
|
||||
|
|
@ -164,23 +164,23 @@ size_t strvRFind(strview_t ctx, char c, size_t from) {
|
|||
}
|
||||
|
||||
size_t strvRFindView(strview_t ctx, strview_t view, size_t from) {
|
||||
from = min(from, ctx.size);
|
||||
from = min(from, ctx.len);
|
||||
|
||||
if(view.size > ctx.size) {
|
||||
from -= view.size;
|
||||
if(view.len > ctx.len) {
|
||||
from -= view.len;
|
||||
}
|
||||
|
||||
const char *buf = ctx.buf + from;
|
||||
for(; buf >= ctx.buf; --buf) {
|
||||
if(memcmp(buf, view.buf, view.size) == 0) return (buf - ctx.buf);
|
||||
if(memcmp(buf, view.buf, view.len) == 0) return (buf - ctx.buf);
|
||||
}
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
size_t strvFindFirstOf(strview_t ctx, strview_t view, size_t from) {
|
||||
if(ctx.size < view.size) return SIZE_MAX;
|
||||
for(size_t i = from; i < ctx.size; ++i) {
|
||||
for(size_t j = 0; j < view.size; ++j) {
|
||||
if(ctx.len < view.len) return SIZE_MAX;
|
||||
for(size_t i = from; i < ctx.len; ++i) {
|
||||
for(size_t j = 0; j < view.len; ++j) {
|
||||
if(ctx.buf[i] == view.buf[j]) return i;
|
||||
}
|
||||
}
|
||||
|
|
@ -188,13 +188,13 @@ size_t strvFindFirstOf(strview_t ctx, strview_t view, size_t from) {
|
|||
}
|
||||
|
||||
size_t strvFindLastOf(strview_t ctx, strview_t view, size_t from) {
|
||||
if(from >= ctx.size) {
|
||||
from = ctx.size - 1;
|
||||
if(from >= ctx.len) {
|
||||
from = ctx.len - 1;
|
||||
}
|
||||
|
||||
const char *buf = ctx.buf + from;
|
||||
for(; buf >= ctx.buf; --buf) {
|
||||
for(size_t j = 0; j < view.size; ++j) {
|
||||
for(size_t j = 0; j < view.len; ++j) {
|
||||
if(*buf == view.buf[j]) return (buf - ctx.buf);
|
||||
}
|
||||
}
|
||||
|
|
@ -203,7 +203,7 @@ size_t strvFindLastOf(strview_t ctx, strview_t view, size_t from) {
|
|||
}
|
||||
|
||||
size_t strvFindFirstNot(strview_t ctx, char c, size_t from) {
|
||||
size_t end = ctx.size - 1;
|
||||
size_t end = ctx.len - 1;
|
||||
for(size_t i = from; i < end; ++i) {
|
||||
if(ctx.buf[i] != c) return i;
|
||||
}
|
||||
|
|
@ -211,7 +211,7 @@ size_t strvFindFirstNot(strview_t ctx, char c, size_t from) {
|
|||
}
|
||||
|
||||
size_t strvFindFirstNotOf(strview_t ctx, strview_t view, size_t from) {
|
||||
for(size_t i = from; i < ctx.size; ++i) {
|
||||
for(size_t i = from; i < ctx.len; ++i) {
|
||||
if(!strvContains(view, ctx.buf[i])) {
|
||||
return i;
|
||||
}
|
||||
|
|
@ -220,8 +220,8 @@ size_t strvFindFirstNotOf(strview_t ctx, strview_t view, size_t from) {
|
|||
}
|
||||
|
||||
size_t strvFindLastNot(strview_t ctx, char c, size_t from) {
|
||||
if(from >= ctx.size) {
|
||||
from = ctx.size - 1;
|
||||
if(from >= ctx.len) {
|
||||
from = ctx.len - 1;
|
||||
}
|
||||
|
||||
const char *buf = ctx.buf + from;
|
||||
|
|
@ -235,8 +235,8 @@ size_t strvFindLastNot(strview_t ctx, char c, size_t from) {
|
|||
}
|
||||
|
||||
size_t strvFindLastNotOf(strview_t ctx, strview_t view, size_t from) {
|
||||
if(from >= ctx.size) {
|
||||
from = ctx.size - 1;
|
||||
if(from >= ctx.len) {
|
||||
from = ctx.len - 1;
|
||||
}
|
||||
|
||||
const char *buf = ctx.buf + from;
|
||||
|
|
|
|||
12
strview.h
12
strview.h
|
|
@ -9,12 +9,16 @@ extern "C" {
|
|||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "slice.h"
|
||||
|
||||
#define STRV_NOT_FOUND SIZE_MAX
|
||||
|
||||
typedef struct {
|
||||
const char *buf;
|
||||
size_t size;
|
||||
} strview_t;
|
||||
// typedef struct {
|
||||
// const char *buf;
|
||||
// size_t size;
|
||||
// } strview_t;
|
||||
|
||||
typedef slice_t(const char *) strview_t;
|
||||
|
||||
strview_t strvInit(const char *cstr);
|
||||
strview_t strvInitLen(const char *buf, size_t size);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue