#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" // more complicated str functions (e.g. for parsing) // return the str with the first [count] bytes removed static str str_drop(str s, ptrdiff_t count){ assert(s.len >= 0 && count >= 0 && count <= s.len); return (str){.data=s.data+count, .len=s.len-count}; } static str str_drop_safe(str s, ptrdiff_t count){ if(count > s.len) return (str){0}; return str_drop(s, count); } // return the prefix of the string of length [count] bytes static str str_take(str s, ptrdiff_t count){ assert(s.len >= 0 && count >= 0 && count <= s.len); return (str){.data=s.data, .len=count}; } // return the str with the last [count] bytes removed static str str_drop_last(str s, ptrdiff_t count){ assert(s.len >= 0 && count >= 0 && count <= s.len); return (str){.data=s.data, .len=s.len-count}; } typedef struct str_pair str_pair; struct str_pair{ str a,b; }; // return a pair (a,b) where a is the prefix of s before pos // and b is the suffix of s from pos (including pos) to the end. static str_pair str_split_at_pos(str s, ptrdiff_t pos){ assert(s.len >= 0 && pos >= 0 && pos < s.len); return (str_pair){ .a={.data=s.data, .len=pos}, .b={.data=s.data+pos, .len=s.len-pos}, }; } // if byte c is found in the string, we return (a,b) // where a is the prefix before the found byte, and b the suffix after the found byte // (neither prefix nor suffix include the found byte) // if byte c is not found we return (s,) // safely check for fail with str_eq(s, x.a) not x.b is empty static str_pair str_split_at(str s, byte c){ assert(s.len >= 0); if(0==s.len) return (str_pair){0}; byte *p = memchr(s.data, c, s.len); if(p){ ptrdiff_t const n = p-s.data; assert(n >= 0 && n < s.len); return (str_pair){ .a={.data=s.data, .len=n}, .b={.data=s.data+n+1, .len=s.len-n-1}, }; }else{ return (str_pair){.a=s}; } } // split a str at a given mark string // if the mark is found (memmem) then it returns (prefix_before_mark, suffix_after_mark) // otherwise it returns (s, empty) // safely check for fail with str_eq(s, x.a) not x.b is empty static str_pair str_split_at_str(str s, str mark){ unless(s.len && mark.len) return (str_pair){0}; byte* at = (byte*)memmem(s.data, s.len, mark.data, mark.len); if(at){ ptrdiff_t const prefix_len = (at - s.data); return (str_pair){.a=str_take(s, prefix_len), .b=str_drop(s, prefix_len+mark.len)}; }else{ return (str_pair){.a=s}; } } // check a string starts with a prefix, every string starts with empty static bool str_starts_with(str s, str prefix){ if(0==prefix.len) return true; if(prefix.len > s.len) return false; return 0==memcmp(s.data, prefix.data, prefix.len); } // check a string ends with a suffix, every string ends with empty static bool str_ends_with(str s, str suffix){ if(0==suffix.len) return true; if(suffix.len > s.len) return false; return 0==memcmp(s.data+s.len-suffix.len, suffix.data, suffix.len); } // check a string starts with a prefix, every string starts with empty (case insensitive) static bool str_starts_with_ci(str s, str prefix){ if(0==prefix.len) return true; if(prefix.len > s.len) return false; for(ptrdiff_t i=0; i