I've been writing with C for a couple days, so this is a relatively advanced function compared to the simple things I've been doing previously. It's written for the Lua API, but it's still C.
#include "lua.h"
#include "lauxlib.h"
#include <stdlib.h>
#include <string.h>
static int l_rtrim(lua_State *L) {
luaL_checktype(L, 1, LUA_TSTRING);
luaL_checktype(L, 2, LUA_TSTRING);
const char *string = lua_tostring(L, 1);
const char *delimiter = lua_tostring(L, 2);
if (*string == '\0') {
lua_rotate(L, -2, 1);
return 1;
}
size_t len = strlen(string);
size_t dlCnt = 0;
size_t tmpLen = len - 1;
if (tmpLen <= 0) {
lua_rotate(L, -2, 1);
return 1;
}
char *copy = malloc(len + 1);
if (copy == NULL) {
lua_pushstring(L, "out of memory");
lua_error(L);
return 1;
}
memcpy(copy, string, len + 1);
while (copy[tmpLen--] == *delimiter) dlCnt++;
if (dlCnt > 0) {
size_t location = len - dlCnt;
if (location > 0) {
copy[location] = '\0';
lua_pushstring(L, copy);
}
else { /* the entire string is composed of the delimiter */
lua_pushliteral(L, "");
}
}
free(copy);
return 1;
}
static const struct luaL_Reg exports[] = {
{"rtrim", l_rtrim},
{NULL, NULL}
};
extern __declspec(dllexport) int luaopen_MyModule(lua_State *L) {
luaL_newlib(L, exports);
return 1;
}
My function counts how many delimiters trail on the right side, so I can insert a null-terminator before any of those delimiters arrive. It's very inefficient (2.5x slower) compared to my implementation of left-trimming (leading spaces) because in that, I just perform a pointer increment.
My main interest is avoiding UB (because I'm not familiar for when it's invoked) and if there's a method I can use to avoid creating a new string & performing so many allocations & copying during benchmarking. I played around a lot with pointer decrementing but it's not working the way I hoped.
Some example inputs and outputs:
("??hello world??", "?") -> "??hello world"
(" hello world ", " ") -> " hello world"