#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "string.h"
#include "math.h"
#include "sys.h"
#include <ucs/config/parser.h>
#include <ucs/arch/bitops.h>
#include <ucs/sys/math.h>
#include <ucs/debug/log.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <time.h>
#include <libgen.h>
const char *ucs_memunits_suffixes[] = {"", "K", "M", "G", "T", "P", "E", NULL};
void ucs_fill_filename_template(const char *tmpl, char *buf, size_t max)
{
char *p, *end;
const char *pf, *pp;
size_t length;
time_t t;
p = buf;
end = buf + max - 1;
*end = 0;
pf = tmpl;
while (*pf != 0 && p < end) {
pp = strchr(pf, '%');
if (pp == NULL) {
strncpy(p, pf, end - p);
p = end;
break;
}
length = ucs_min(pp - pf, end - p);
strncpy(p, pf, length);
p += length;
switch (*(pp + 1)) {
case 'p':
snprintf(p, end - p, "%d", getpid());
pf = pp + 2;
p += strlen(p);
break;
case 'h':
snprintf(p, end - p, "%s", ucs_get_host_name());
pf = pp + 2;
p += strlen(p);
break;
case 'c':
snprintf(p, end - p, "%02d", ucs_get_first_cpu());
pf = pp + 2;
p += strlen(p);
break;
case 't':
t = time(NULL);
strftime(p, end - p, "%Y-%m-%d-%H-%M-%S", localtime(&t));
pf = pp + 2;
p += strlen(p);
break;
case 'u':
snprintf(p, end - p, "%s", ucs_basename(ucs_get_user_name()));
pf = pp + 2;
p += strlen(p);
break;
case 'e':
snprintf(p, end - p, "%s", ucs_basename(ucs_get_exe()));
pf = pp + 2;
p += strlen(p);
break;
default:
*(p++) = *pp;
pf = pp + 1;
break;
}
p += strlen(p);
}
*p = 0;
}
void ucs_snprintf_zero(char *buf, size_t size, const char *fmt, ...)
{
va_list ap;
memset(buf, 0, size);
va_start(ap, fmt);
vsnprintf(buf, size, fmt, ap);
va_end(ap);
}
void ucs_strncpy_zero(char *dest, const char *src, size_t max)
{
if (max) {
strncpy(dest, src, max - 1);
dest[max - 1] = '\0';
}
}
uint64_t ucs_string_to_id(const char* str)
{
uint64_t id = 0;
strncpy((char*)&id, str, sizeof(id) - 1);
return id;
}
size_t ucs_string_quantity_prefix_value(char prefix)
{
switch (prefix) {
case 'B':
return 1;
case 'K':
return UCS_KBYTE;
case 'M':
return UCS_MBYTE;
case 'G':
return UCS_GBYTE;
case 'T':
return UCS_TBYTE;
default:
return 0;
}
}
char *ucs_memunits_to_str(size_t value, char *buf, size_t max)
{
const char **suffix;
if (value == UCS_MEMUNITS_INF) {
ucs_strncpy_safe(buf, UCS_NUMERIC_INF_STR, max);
} else if (value == UCS_MEMUNITS_AUTO) {
ucs_strncpy_safe(buf, UCS_VALUE_AUTO_STR, max);
} else {
suffix = &ucs_memunits_suffixes[0];
while ((value >= 1024) && ((value % 1024) == 0) && *(suffix + 1)) {
value /= 1024;
++suffix;
}
ucs_snprintf_safe(buf, max, "%zu%s", value, *suffix);
}
return buf;
}
const char *ucs_memunits_range_str(size_t range_start, size_t range_end,
char *buf, size_t max)
{
char buf_start[64], buf_end[64];
if (range_start == range_end) {
snprintf(buf, max, "%s",
ucs_memunits_to_str(range_start, buf_start,
sizeof(buf_start)));
} else {
snprintf(buf, max, "%s..%s",
ucs_memunits_to_str(range_start, buf_start, sizeof(buf_start)),
ucs_memunits_to_str(range_end, buf_end, sizeof(buf_end)));
}
return buf;
}
ucs_status_t ucs_str_to_memunits(const char *buf, void *dest)
{
char units[3];
int num_fields;
size_t value;
size_t bytes;
if (!strcasecmp(buf, UCS_NUMERIC_INF_STR)) {
*(size_t*)dest = UCS_MEMUNITS_INF;
return UCS_OK;
}
if (!strcasecmp(buf, UCS_VALUE_AUTO_STR)) {
*(size_t*)dest = UCS_MEMUNITS_AUTO;
return UCS_OK;
}
memset(units, 0, sizeof(units));
num_fields = sscanf(buf, "%ld%c%c", &value, &units[0], &units[1]);
if (num_fields == 1) {
bytes = 1;
} else if ((num_fields == 2) || (num_fields == 3)) {
bytes = ucs_string_quantity_prefix_value(toupper(units[0]));
if (!bytes || ((num_fields == 3) && tolower(units[1]) != 'b')) {
return UCS_ERR_INVALID_PARAM;
}
} else {
return UCS_ERR_INVALID_PARAM;
}
*(size_t*)dest = value * bytes;
return UCS_OK;
}
char *ucs_dirname(char *path, int num_layers)
{
while (num_layers-- > 0) {
path = dirname(path);
if (path == NULL) {
return NULL;
}
}
return path;
}
void ucs_vsnprintf_safe(char *buf, size_t size, const char *fmt, va_list ap)
{
if (size == 0) {
return;
}
vsnprintf(buf, size, fmt, ap);
buf[size - 1] = '\0';
}
void ucs_snprintf_safe(char *buf, size_t size, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
ucs_vsnprintf_safe(buf, size, fmt, ap);
va_end(ap);
}
char* ucs_strncpy_safe(char *dst, const char *src, size_t len)
{
size_t length;
if (!len) {
return dst;
}
length = ucs_min(len, strnlen(src, len) + 1);
memcpy(dst, src, length);
dst[length - 1] = '\0';
return dst;
}
char *ucs_strtrim(char *str)
{
char *start, *end;
start = str;
while (isspace(*start)) {
++start;
}
if (*start) {
end = start + strlen(start) - 1;
while (isspace(*end)) {
--end;
}
*(end + 1) = '\0';
}
return start;
}
const char * ucs_str_dump_hex(const void* data, size_t length, char *buf,
size_t max, size_t per_line)
{
static const char hexchars[] = "0123456789abcdef";
char *p, *endp;
uint8_t value;
size_t i;
p = buf;
endp = buf + max - 2;
i = 0;
while ((p < endp) && (i < length)) {
if (i > 0) {
if ((i % per_line) == 0) {
*(p++) = '\n';
} else if ((i % 4) == 0) {
*(p++) = ':';
}
if (p == endp) {
break;
}
}
value = *(const uint8_t*)(UCS_PTR_BYTE_OFFSET(data, i));
p[0] = hexchars[value / 16];
p[1] = hexchars[value % 16];
p += 2;
++i;
}
*p = 0;
return buf;
}
const char* ucs_flags_str(char *buf, size_t max,
uint64_t flags, const char **str_table)
{
size_t i, len = 0;
for (i = 0; *str_table; ++str_table, ++i) {
if (flags & UCS_BIT(i)) {
snprintf(buf + len, max - len, "%s,", *str_table);
len = strlen(buf);
}
}
if (len > 0) {
buf[len - 1] = '\0';
} else {
buf[0] = '\0';
}
return buf;
}
size_t ucs_string_count_char(const char *str, char c)
{
size_t count = 0;
const char *p;
for (p = str; *p != '\0'; ++p) {
if (*p == c) {
count++;
}
}
return count;
}
size_t ucs_string_common_prefix_len(const char *str1, const char *str2)
{
const char *p1 = str1;
const char *p2 = str2;
while ((*p1 != '\0') && (*p1 == *p2)) {
p1++;
p2++;
}
return (p1 - str1);
}
static size_t
ucs_path_common_parent_length(const char *path1, const char *path2)
{
size_t offset, parent_length;
offset = 0;
parent_length = 0;
do {
if (((path1[offset] == '/') || (path1[offset] == '\0')) &&
((path2[offset] == '/') || (path2[offset] == '\0'))) {
parent_length = offset;
}
} while ((path1[offset] == path2[offset]) && (path1[offset++] != '\0'));
return parent_length;
}
void ucs_path_get_common_parent(const char *path1, const char *path2,
char *common_path)
{
size_t parent_length;
parent_length = ucs_path_common_parent_length(path1, path2);
memcpy(common_path, path1, parent_length);
common_path[parent_length] = '\0';
}
size_t ucs_path_calc_distance(const char *path1, const char *path2)
{
size_t common_length = ucs_path_common_parent_length(path1, path2);
return ucs_string_count_char(path1 + common_length, '/') +
ucs_string_count_char(path2 + common_length, '/');
}
const char* ucs_mask_str(uint64_t mask, ucs_string_buffer_t *strb)
{
uint8_t bit;
if (mask == 0) {
ucs_string_buffer_appendf(strb, "<none>");
goto out;
}
ucs_for_each_bit(bit, mask) {
ucs_string_buffer_appendf(strb, "%u, ", bit);
}
ucs_string_buffer_rtrim(strb, ", ");
out:
return ucs_string_buffer_cstr(strb);
}
ssize_t ucs_string_find_in_list(const char *str, const char **string_list,
int case_sensitive)
{
size_t i;
for (i = 0; string_list[i] != NULL; ++i) {
if ((case_sensitive && (strcmp(string_list[i], str) == 0)) ||
(!case_sensitive && (strcasecmp(string_list[i], str) == 0))) {
return i;
}
}
return -1;
}
char* ucs_string_split(char *str, const char *delim, int count, ...)
{
char *p = str;
size_t length;
va_list ap;
int i;
va_start(ap, count);
for (i = 0; i < count; ++i) {
*va_arg(ap, char**) = p;
if (p == NULL) {
continue;
}
length = strcspn(p, delim);
if (p[length] == '\0') {
p = NULL;
} else {
p[length] = '\0';
p += length + 1;
}
}
va_end(ap);
return p;
}