113 lines
3.2 KiB
C
113 lines
3.2 KiB
C
#pragma once
|
|
// sys_string.h - shared native string-view ABI.
|
|
// A SYS_STRING_VIEW is a borrowed byte span. It is not NUL-terminated by
|
|
// contract and it does not own the pointed-to storage.
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#ifndef SYS_STRING_VIEW_DEFINED
|
|
#define SYS_STRING_VIEW_DEFINED 1
|
|
typedef struct SYS_STRING_VIEW {
|
|
const char* Data;
|
|
size_t Length;
|
|
} SYS_STRING_VIEW;
|
|
#endif
|
|
|
|
#define SYS_SV_LITERAL(s) ((SYS_STRING_VIEW){ (s), sizeof(s) - 1 })
|
|
#define SYS_SV_NULL ((SYS_STRING_VIEW){ (const char*)0, 0 })
|
|
|
|
static inline SYS_STRING_VIEW SysSvFromParts(const char* data, size_t length) {
|
|
SYS_STRING_VIEW v;
|
|
v.Data = data;
|
|
v.Length = length;
|
|
return v;
|
|
}
|
|
|
|
static inline SYS_STRING_VIEW SysSvFromCstr(const char* s) {
|
|
SYS_STRING_VIEW v;
|
|
v.Data = s;
|
|
v.Length = s ? strlen(s) : 0;
|
|
return v;
|
|
}
|
|
|
|
static inline int SysSvIsEmpty(SYS_STRING_VIEW s) {
|
|
return s.Length == 0;
|
|
}
|
|
|
|
static inline int SysSvIsValid(SYS_STRING_VIEW s) {
|
|
return s.Data != (const char*)0 || s.Length == 0;
|
|
}
|
|
|
|
static inline int SysSvEqual(SYS_STRING_VIEW a, SYS_STRING_VIEW b) {
|
|
if (a.Length != b.Length) return 0;
|
|
if (a.Length == 0) return 1;
|
|
if (!a.Data || !b.Data) return 0;
|
|
return memcmp(a.Data, b.Data, a.Length) == 0;
|
|
}
|
|
|
|
static inline char SysAsciiLower(char c) {
|
|
return (c >= 'A' && c <= 'Z') ? (char)(c + ('a' - 'A')) : c;
|
|
}
|
|
|
|
static inline int SysSvEqualAsciiI(SYS_STRING_VIEW a, SYS_STRING_VIEW b) {
|
|
if (a.Length != b.Length) return 0;
|
|
if (a.Length == 0) return 1;
|
|
if (!a.Data || !b.Data) return 0;
|
|
for (size_t i = 0; i < a.Length; i++) {
|
|
if (SysAsciiLower(a.Data[i]) != SysAsciiLower(b.Data[i])) return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static inline int SysSvEqualLit(SYS_STRING_VIEW a, const char* lit) {
|
|
return SysSvEqual(a, SysSvFromCstr(lit));
|
|
}
|
|
|
|
static inline int SysSvEqualLitAsciiI(SYS_STRING_VIEW a, const char* lit) {
|
|
return SysSvEqualAsciiI(a, SysSvFromCstr(lit));
|
|
}
|
|
|
|
static inline int SysSvContainsByte(SYS_STRING_VIEW s, char ch) {
|
|
if (!s.Data && s.Length) return 0;
|
|
for (size_t i = 0; i < s.Length; i++) {
|
|
if (s.Data[i] == ch) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline SYS_STRING_VIEW SysSvSlice(SYS_STRING_VIEW s, size_t off, size_t len) {
|
|
if (off > s.Length) off = s.Length;
|
|
if (len > s.Length - off) len = s.Length - off;
|
|
return SysSvFromParts(s.Data ? s.Data + off : (const char*)0, len);
|
|
}
|
|
|
|
static inline SYS_STRING_VIEW SysSvTrimAscii(SYS_STRING_VIEW s) {
|
|
size_t begin = 0;
|
|
size_t end = s.Length;
|
|
while (begin < end) {
|
|
char c = s.Data[begin];
|
|
if (c != ' ' && c != '\t' && c != '\r' && c != '\n') break;
|
|
begin++;
|
|
}
|
|
while (end > begin) {
|
|
char c = s.Data[end - 1];
|
|
if (c != ' ' && c != '\t' && c != '\r' && c != '\n') break;
|
|
end--;
|
|
}
|
|
return SysSvSlice(s, begin, end - begin);
|
|
}
|
|
|
|
static inline int SysSvCopyZ(char* dst, size_t dstSize, SYS_STRING_VIEW src) {
|
|
if (!dst || dstSize == 0) return 0;
|
|
if (src.Length && !src.Data) return 0;
|
|
if (src.Length + 1 > dstSize) {
|
|
dst[0] = '\0';
|
|
return 0;
|
|
}
|
|
if (src.Length) memcpy(dst, src.Data, src.Length);
|
|
dst[src.Length] = '\0';
|
|
return 1;
|
|
}
|