interp/include/simple_strlib.h
2025-08-19 07:49:22 -07:00

266 lines
6.3 KiB
C

#pragma once
#ifdef _MSVC_VER
#include <winunistd.h>
#endif
#include "support.h"
/**
* @file simple_strlib.h
* @brief Some additions that seem to be missing or
* are missing from the clib port.
*
* @details We've rolled our own string functions, they
* were either missing or I didn't like the way
* they worked. (I tend to favor in-place string
* manips for embedded work.) Needs to be tested
* for thread safety.
*
* @author t.o.
* @bug
*/
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <stdlib.h>
#ifndef _WIN32
#include <sys/param.h>
#endif
#ifdef __cplusplus
extern "C"{
#endif
/**
* @brief strlwr
*
* @details My own version of strlwr, becuase clib
* doesn't appear to have one.
*
* @param s The string to convert
* @return pointer to the modified string
*/
inline char*
strlwr(char* s)
{
char* p = s;
while(*p) {
*p = tolower((uint32_t)*p);
p++;
}
return s;
}
/**
* @brief countc
*
* @details Count the number of occurrences of c in s
*
* @param s The target string
* @param c The character to count
* @return the count
*/
static inline int
countc(const char* s, char c)
{
int n = 0;
while(*s++ != '\0') {
if(*s == c)
n++;
}
return n;
}
/**
* @brief Strip trailing whitespace from s inplace
*
* @param s The string to trim
* @return the modified string
*/
inline const char*
strstrip(char* s)
{
size_t size = strlen(s);
if (!size)
return s;
char* end;
end = s + size - 1;
while(end >= s && isspace(*end))
end--;
*(end + 1) = '\0';
while(*s && isspace(*s))
s++;
return s;
}
/**
* @brief Split the string at delimiters using a zero-copy in-place algorithm
*
* @param s The string to split (every delimiter will be replaced by NULL)
* @param delimiter The delimiter character to split at
* @param size The size of the return array w
* @return A list of char* (size stored in *size), pointing to all split results in order
* Don't forget to free the returned array in the caller
*/
static inline char**
split(char* s, char delimiter, int* size)
{
int numdelimiters = countc(s, delimiter);
char** splitresult = malloc((numdelimiters + 2) * sizeof(char*)); // +2 for the last substring and NULL terminator
if (splitresult == NULL) {
*size = 0;
return NULL; // Memory allocation failed
}
splitresult[0] = s;
int i = 1;
char* hit = s;
while ((hit = strchr(hit, delimiter)) != NULL) {
*hit++ = '\0';
splitresult[i++] = hit;
}
splitresult[i] = NULL; // Mark the end of the splitresult array with NULL
*size = numdelimiters + 1;
return splitresult;
}
/**
* @breif Remove the substring matched. Operates
* in-place.
*
* @param the string to operate on
* @param the character sequence to remove
*/
static inline void
remove_first(char* str, const char* str_remove)
{
size_t j;
size_t len;
size_t remove_len;
int found = 0;
len = strlen(str);
remove_len = strlen(str_remove);
for(size_t i = 0; i < len; i++) {
found = 1;
for(j = 0; j < remove_len; j++) {
if(*(str + i + j) != *(str_remove + j)) {
found = 0;
break;
}
}
// If word has been found then remove it by shifting characters
if(found == 1) {
for(j = i; j <= len - remove_len; j++)
*(str + j) = *(str + j + remove_len);
// Terminate from loop so only first occurrence is removed
break;
}
}
}
/**
* @brief find first index of character in string
*
* @param string string to operate on
* @param char char to find index of
* @return integer index of the first occurance of char
*/
static inline int
find_ch_index(const char* string, char ch)
{
int i = 0;
while(*(string + i) && *(string + i) != ch) i++;
return *(string + i) == ch ? -1 : i;
}
/**
* @brief pass a substring of the source string through an i/o parameter
*
* @param char pointer source string
* @param start index of starting character for subsctring in source
* @param length of source string
* @param char pointer to destination string buffer
* @param length of destination string buffer
*/
static inline void
mid(const char* src, size_t start, size_t length, char* dst, size_t dstlen)
{
size_t len = MIN(dstlen, length);
strncpy(dst, src + start, len);
// zero terminate because strncpy() didn't ?
if(len < length)
dst[dstlen - 1] = 0;
}
static char*
right(char* string, int size)
{
while(*string++);
return(string - size - 2);
}
static char*
replace_char(char* str, char find, char replace){
char *current_pos = strchr(str,find);
while (current_pos) {
*current_pos = replace;
current_pos = strchr(current_pos,find);
}
return str;
}
static void
substr(const char* inputString, char delimiter, char** resultBuffer) {
// Find the first occurrence of the delimiter
const char* firstOccurrence = strchr(inputString, delimiter);
if (firstOccurrence == NULL) {
// Delimiter not found
*resultBuffer = NULL;
return;
}
// Find the second occurrence of the delimiter
const char* secondOccurrence = strchr(firstOccurrence + 1, delimiter);
if (secondOccurrence == NULL) {
// Second occurrence not found
*resultBuffer = NULL;
return;
}
// Calculate the length of the substring
size_t substringLength = secondOccurrence - (firstOccurrence + 1);
// Allocate memory for the result buffer
*resultBuffer = (char*)malloc(substringLength + 1);
if (*resultBuffer == NULL) {
// Memory allocation failed
fprintf(stderr, "Memory allocation failed\n");
exit(EXIT_FAILURE);
}
// Copy the substring into the result buffer
strncpy(*resultBuffer, firstOccurrence + 1, substringLength);
(*resultBuffer)[substringLength] = '\0'; // Null-terminate the string
}
#ifdef __cplusplus
}
#endif