2021-09-24 21:45:48 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2024-02-18 12:23:14 -05:00
|
|
|
#include <assert.h>
|
2020-10-09 19:46:59 +01:00
|
|
|
#include <ctype.h>
|
2023-06-25 09:00:41 +01:00
|
|
|
#include <stdarg.h>
|
2020-10-09 19:46:59 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
2023-06-25 09:00:41 +01:00
|
|
|
#include "common/mem.h"
|
2023-01-31 03:35:13 +01:00
|
|
|
#include "common/string-helpers.h"
|
2020-10-09 19:46:59 +01:00
|
|
|
|
2024-01-19 19:06:07 +00:00
|
|
|
bool
|
|
|
|
|
string_null_or_empty(const char *s)
|
|
|
|
|
{
|
|
|
|
|
return !s || !*s;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-17 02:16:49 +01:00
|
|
|
void
|
|
|
|
|
trim_last_field(char *buf, char delim)
|
|
|
|
|
{
|
|
|
|
|
char *p = strrchr(buf, delim);
|
|
|
|
|
if (p) {
|
|
|
|
|
*p = '\0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-09 19:46:59 +01:00
|
|
|
static void
|
|
|
|
|
rtrim(char **s)
|
|
|
|
|
{
|
|
|
|
|
size_t len = strlen(*s);
|
|
|
|
|
if (!len) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
char *end = *s + len - 1;
|
|
|
|
|
while (end >= *s && isspace(*end)) {
|
|
|
|
|
end--;
|
|
|
|
|
}
|
|
|
|
|
*(end + 1) = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
string_strip(char *s)
|
|
|
|
|
{
|
|
|
|
|
rtrim(&s);
|
|
|
|
|
while (isspace(*s)) {
|
|
|
|
|
s++;
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
2021-02-16 21:03:38 +00:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
string_truncate_at_pattern(char *buf, const char *pattern)
|
|
|
|
|
{
|
|
|
|
|
char *p = strstr(buf, pattern);
|
|
|
|
|
if (!p) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
*p = '\0';
|
|
|
|
|
}
|
2023-06-25 09:00:41 +01:00
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
strdup_printf(const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
size_t size = 0;
|
|
|
|
|
char *p = NULL;
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
int n = vsnprintf(p, size, fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
|
|
if (n < 0) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = (size_t)n + 1;
|
|
|
|
|
p = xzalloc(size);
|
|
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
n = vsnprintf(p, size, fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
|
|
if (n < 0) {
|
|
|
|
|
free(p);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return p;
|
|
|
|
|
}
|
2024-02-18 12:23:14 -05:00
|
|
|
|
|
|
|
|
char *
|
2024-03-09 12:03:30 -05:00
|
|
|
str_join(const char *const parts[],
|
2024-02-18 12:23:14 -05:00
|
|
|
const char *restrict fmt, const char *restrict sep)
|
|
|
|
|
{
|
|
|
|
|
assert(parts);
|
|
|
|
|
|
|
|
|
|
if (!fmt) {
|
|
|
|
|
fmt = "%s";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sep) {
|
|
|
|
|
sep = " ";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t size = 0;
|
|
|
|
|
size_t n_parts = 0;
|
|
|
|
|
|
|
|
|
|
size_t sep_len = strlen(sep);
|
|
|
|
|
|
|
|
|
|
/* Count the length of each formatted string */
|
|
|
|
|
for (const char *const *s = parts; *s; ++s) {
|
|
|
|
|
int n = snprintf(NULL, 0, fmt, *s);
|
|
|
|
|
if (n < 0) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
size += (size_t)n;
|
|
|
|
|
++n_parts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n_parts < 1) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Need (n_parts - 1) separators, plus one NULL terminator */
|
|
|
|
|
size += (n_parts - 1) * sep_len + 1;
|
|
|
|
|
|
|
|
|
|
/* Concatenate the strings and separators */
|
|
|
|
|
char *buf = xzalloc(size);
|
|
|
|
|
char *p = buf;
|
|
|
|
|
for (const char *const *s = parts; *s; ++s) {
|
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
|
|
if (p != buf) {
|
|
|
|
|
n = snprintf(p, size, "%s", sep);
|
|
|
|
|
if (n < 0 || (size_t)n >= size) {
|
|
|
|
|
p = NULL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
size -= (size_t)n;
|
|
|
|
|
p += (size_t)n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = snprintf(p, size, fmt, *s);
|
|
|
|
|
if (n < 0 || (size_t)n >= size) {
|
|
|
|
|
p = NULL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
size -= (size_t)n;
|
|
|
|
|
p += (size_t)n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!p) {
|
|
|
|
|
free(buf);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 12:03:30 -05:00
|
|
|
bool
|
|
|
|
|
str_endswith(const char *const string, const char *const suffix)
|
|
|
|
|
{
|
|
|
|
|
size_t len_str = string ? strlen(string) : 0;
|
|
|
|
|
size_t len_sfx = suffix ? strlen(suffix) : 0;
|
|
|
|
|
|
|
|
|
|
if (len_str < len_sfx) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (len_sfx == 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return strcmp(string + len_str - len_sfx, suffix) == 0;
|
|
|
|
|
}
|