#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 #include #include #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; }