//----------------------------------------------------------------------------// // 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; 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, then fills // the rest with 0; dest[n] is guanranteed to be '\0' // // Returns TRUE if dest would have been null-terminated // by ordinary strncpy(), and FALSE otherwise // int strnzcpy(char *restrict dest, const char *restrict src, size_t n) { size_t it; for (it = 0; it < n - 1 && src[it]; it++) { dest[it] = src[it]; } // Was the copy complete? if (it == n) { if (dest[n] == 0) { return TRUE; } dest[n] = 0; return FALSE; } while (it < n) dest[it++] = 0; return TRUE; } // // 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 a copy of at most n bytes of src at the end of dest // Always null-terminates, and returne TRUE or FALSE depending on whether // regular strcat() would have null-terminated this string, or not // int strnzcat(char *restrict dest, const char *restrict src, size_t n) { size_t it, off = 0; while (dest[off]) off++; for (it = 0; it < n - 1 && src[it]; it++) { dest[it+off] = src[it]; } // Was the copy complete? if (it == n) { if (dest[n+off] == 0) { return TRUE; } dest[n+off] = 0; return FALSE; } while (it++ < n) dest[it+off] = 0; return TRUE; } // // 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; }