/* * This code is part of the programming language Ivy. * Ivy comes with ABSOLUTELY NO WARRANTY and is licensed under AGPL-3.0 or later. * Copyright (C) 2024 VegOwOtenks * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "StringView.h" #include #include #include StringView StringView_FromString(const char* source) { return StringView_FromStringSized(source, strlen(source)); } StringView StringView_FromStringSized(const char* source, size_t length) { StringView view = { .source = source, .length = length, }; return view; } bool StringView_Equal(StringView first, StringView second) { return first.length == second.length && strncmp(first.source, second.source, first.length) == 0; } bool StringView_StartsWith(StringView string, StringView start) { return strncmp(string.source, start.source, start.length) == 0; } bool StringView_EndsWith(StringView string, StringView end) { if (end.length > string.length) { return false; } return StringView_Equal( end, StringView_Slice( string, string.length - end.length, string.length ) ); } bool StringView_Contains(StringView string, StringView find) { return StringView_FindString(string, find).source != NULL; } size_t StringView_Count(StringView string, StringView find) { size_t count = 0; while ((find = StringView_FindString(string, find)).source != NULL) { size_t offset = (uintptr_t) (find.source) - (uintptr_t) (string.source); string = (StringView) {string.source + offset, string.length - offset}; } return count; } size_t StringView_FindStringOffset(StringView haystack, StringView needle) { size_t offset = 0; size_t index = 0; while (offset < haystack.length) { while (index < needle.length && needle.source[index] == haystack.source[offset + index]) { index++; } if (index == needle.length) { return offset; } offset++; } return SIZE_MAX; } StringView StringView_FindString(StringView haystack, StringView needle) { size_t offset = 0; size_t index = 0; while (offset < haystack.length) { while (index < needle.length && needle.source[index] == haystack.source[offset + index]) { index++; } if (index == needle.length) { return (StringView) {haystack.source + offset, needle.length}; } offset++; } return (StringView) {NULL, 0}; } StringView StringView_Slice(StringView string, size_t start, size_t end) { if (end > string.length || start > string.length) { return (StringView) {NULL, 0}; } StringView slice = { .length = end - start, .source = string.source + start, }; return slice; } bool StringView_NextSplit(StringView* dest, StringView* source, StringView delim) { if (source->length == 0) return false; size_t offset = StringView_FindStringOffset(*source, delim); if (offset == SIZE_MAX) { // No more delimiters, return entire source offset = source->length; } *dest = StringView_Slice(*source, 0, offset); *source = StringView_Slice(*source, offset + delim.length, source->length); return true; } StringView StringView_StripLeft(StringView sv, StringView strip) { while (StringView_StartsWith(sv, strip)) { sv = StringView_Slice(sv, strip.length, sv.length); } return sv; } StringView StringView_StripRight(StringView sv, StringView strip) { while (StringView_EndsWith(sv, strip)) { sv = StringView_Slice(sv, 0, sv.length - strip.length); } return sv; } void StringView_Paste(char* destination, StringView source) { memcpy(destination, source.source, source.length); } int StringView_ParseInt(StringView source) { int value = 0; int sign = 1; switch (source.source[0]) { case '+': sign = 1; source.source++; source.length--; break; case '-': sign = -1; source.source++; source.length--; break; default: break; } while (source.length && isdigit(source.source[0])) { int digit = source.source[0] - '0'; value *= 10; value += digit; source.source++; source.length--; } return value * sign; }