//----------------------------------------------------------------------------// // GNU GPL OS/K // // // // Authors: spectral` // // NeoX // // // // Desc: String-related functions // //----------------------------------------------------------------------------// #include // // Compare two strings // int strcmp(const char *str1, const char *str2) { while (*str1 == *str2 && *str2) str1++, str2++; return *(uchar *)str1 - *(uchar *)str2; } // // Compare at most n bytes of two strings // int strncmp(const char *str1, const char *str2, size_t n) { size_t it = 0; while (*str1 == *str2 && *str2 && it < n) str1++, str2++, it++; return *(uchar *)str1 - *(uchar *)str2; } // // Return str's length // size_t strlen(const char *str) { const char *base = str; while (*str) str++; return str - base; } // // Return a pointer to the first occurence of ch in str, // or str's null-terminator if none is found // char *strchrnul(const char *str, int ch) { while ((*str && *str != (char)ch)) str++; return (char *)str; } // // Return a pointer to the first occurence of ch in str, // NULL if none is found // char *strchr(const char *str, int ch) { while ((*str && *str != (char)ch)) str++; return *str ? (char *)str : NULL; } // // Return a point to the last occurence of ch in str, // NULL if none is found // char *strrchr(const char *str, int ch) { char *ptr = NULL; while (*str) { if (*str == ch) { ptr = (char *)str; } str++; } return ptr; } // // Return the length of the longest inital segment of str // that only contains characters in acc // size_t strspn(const char *str, const char *acc) { const char *ptr = str; while (*ptr && strchr(acc, *ptr) != NULL) ptr++; return ptr - str; } // // Return the length of the longest initial segment of str // that does not contain any character in rej // size_t strcspn(const char *str, const char *rej) { const char *ptr = str; while (*ptr && strchr(rej, *ptr) == NULL) ptr++; return ptr - str; } // // Return the first occurence in str of any byte in acc // char *strpbrk(const char *str, const char *acc) { str += strcspn(str, acc); return *str ? (char *)str : NULL; } // // Return the first occurence of the substring needle // in the string haystack, NULL if none is found // Null-terminators aren't compared // char *strstr(const char *haystack, const char *needle) { const size_t needle_size = strlen(needle); // Moves haystack to first occurence of the needle's first byte while ((haystack = strchr(haystack, *needle)) != NULL) { if (strncmp(haystack, needle, needle_size) == 0) { return (char *)haystack; } } return NULL; } // // Tokenize a string, using saveptr as a savestate // We let a segmentation fault happen if *saveptr == NULL // char *strtok_r(char *restrict str, const char *restrict delim, char **restrict saveptr) { assert(*saveptr != NULL); if (str == NULL) str = *saveptr; // Skip initial segments composed only of delimiters str += strspn(str, delim); // If str is empty, store it in saveptr so that next call // still finds an empty strings and returns NULL if (*str == 0) { *saveptr = str; return NULL; } char *ptr = str, *tok_end = strpbrk(str, delim); // // If we found the last token, set *saveptr to a str's null-terminator // Otherwise, null-terminate token and save next byte // if (tok_end == NULL) { while (*ptr) ptr++; *saveptr = ptr; } else { *tok_end = 0; *saveptr = tok_end + 1; } return str; } // // Tokenize a string in a very thread-unsafe way // char *strtok(char *restrict str, const char *restrict delim) { static char *saveptr = NULL; // Avoid this function if possible KalAssert(FALSE); if (str) saveptr = str; return strtok_r(str, delim, &saveptr); } // // Copy the string src into dest // char *strcpy(char *restrict dest, const char *restrict src) { char *base = dest; while ((*dest++ = *src++)); return base; } // // strcpy() but always writes n bytes // Will not null-terminate for strings longer than n bytes // char *strncpy(char *restrict dest, const char *restrict src, size_t n) { size_t it; for (it = 0; it < n && src[it]; it++) { dest[it] = src[it]; } while (it < n) dest[it++] = 0; return dest; } // // Copies at most n-1 bytes from src to dest // Always null-terminates dest, but doesn't fill // dest's contents past the null-terminator // // Returns the number of bytes NOT written, not counting null-terminators // size_t strnzcpy(char *restrict dest, const char *restrict src, size_t n) { size_t it, loss; for (it = 0; it < n - 1 && src[it]; it++) { dest[it] = src[it]; } dest[it] = 0; // Compute how many bytes were not copied for (loss = it; src[loss]; loss++); return loss - it; } // // Appends a copy of src at the end of dest // char *strcat(char *restrict dest, const char *restrict src) { char *base = dest; while (*dest) dest++; while ((*dest++ = *src++)); return base; } // // Appends a copy of at most n bytes of src at the end of dest // char *strncat(char *restrict dest, const char *restrict src, size_t n) { size_t it, off = 0; while (dest[off]) off++; for (it = 0; it < n && src[it]; it++) { dest[it+off] = src[it]; } while (it++ < n) dest[it+off] = 0; return dest; } // // Appends at most n-1 bytes from src to dest // Always null-terminates dest, but doesn't fill // dest's contents past the null-terminator // // Returns the number of bytes NOT written, not counting null-terminators // size_t strnzcat(char *restrict dest, const char *restrict src, size_t n) { size_t it, loss, off = 0; while (dest[off]) off++; for (it = 0; it < n - 1 && src[it]; it++) { dest[it+off] = src[it]; } dest[it+off] = 0; // Compute how many bytes were not copied for (loss = it; src[loss+off]; loss++); return loss - it; } // // Reverses the string src, putting the result into dest // char *strrev(char *restrict dest, const char *restrict src) { char *orig = dest; size_t n = strlen(src); dest[n--] = '\0'; while ((*dest++ = src[n--])); return orig; } // // Reverses a string, modifying it // char *strrev2(char *str) { char ch, *orig = str; size_t n = strlen(str); char *temp = str + n - 1; while (temp > str) { ch = *temp; *temp-- = *str; *str++ = ch; } return orig; }