commits
tags
#include "util.h"
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <time.h>
#include <unistd.h>
void fmt_size(int64_t bytes, char *buf, size_t n)
{
static const char *units[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB"};
double v = (double)bytes;
size_t u = 0;
while (v >= 1024.0 && u < 5) {
v /= 1024.0;
u++;
}
if (u == 0)
snprintf(buf, n, "%.0f %s", v, units[u]);
else
snprintf(buf, n, "%.2f %s", v, units[u]);
}
void fmt_speed(int64_t bytes_per_sec, char *buf, size_t n)
{
char tmp[32];
fmt_size(bytes_per_sec, tmp, sizeof(tmp));
snprintf(buf, n, "%s/s", tmp);
}
void fmt_eta(int seconds, char *buf, size_t n)
{
if (seconds < 0) {
snprintf(buf, n, "\xe2\x88\x9e"); /* infinity, unknown */
return;
}
if (seconds == 0) {
snprintf(buf, n, "klar");
return;
}
int days = seconds / 86400;
int hours = (seconds % 86400) / 3600;
int mins = (seconds % 3600) / 60;
int secs = seconds % 60;
if (days > 0)
snprintf(buf, n, "%dd %dh", days, hours);
else if (hours > 0)
snprintf(buf, n, "%dh %dm", hours, mins);
else if (mins > 0)
snprintf(buf, n, "%dm %ds", mins, secs);
else
snprintf(buf, n, "%ds", secs);
}
void fmt_ratio(double ratio, char *buf, size_t n)
{
if (ratio < 0)
snprintf(buf, n, "\xe2\x88\x9e");
else
snprintf(buf, n, "%.2f", ratio);
}
void fmt_time(long unix_time, char *buf, size_t n)
{
if (unix_time <= 0) {
snprintf(buf, n, "-");
return;
}
time_t t = (time_t)unix_time;
struct tm tmv;
localtime_r(&t, &tmv);
strftime(buf, n, "%Y-%m-%d %H:%M", &tmv);
}
static const char b64tab[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
size_t base64_encoded_size(size_t len)
{
return ((len + 2) / 3) * 4;
}
long base64_encode(const unsigned char *data, size_t len, char *out, size_t outsize)
{
size_t needed = base64_encoded_size(len);
if (outsize < needed + 1)
return -1;
size_t i, o = 0;
for (i = 0; i + 2 < len; i += 3) {
uint32_t n = ((uint32_t)data[i] << 16) | ((uint32_t)data[i + 1] << 8) | data[i + 2];
out[o++] = b64tab[(n >> 18) & 0x3F];
out[o++] = b64tab[(n >> 12) & 0x3F];
out[o++] = b64tab[(n >> 6) & 0x3F];
out[o++] = b64tab[n & 0x3F];
}
size_t rem = len - i;
if (rem == 1) {
uint32_t n = (uint32_t)data[i] << 16;
out[o++] = b64tab[(n >> 18) & 0x3F];
out[o++] = b64tab[(n >> 12) & 0x3F];
out[o++] = '=';
out[o++] = '=';
} else if (rem == 2) {
uint32_t n = ((uint32_t)data[i] << 16) | ((uint32_t)data[i + 1] << 8);
out[o++] = b64tab[(n >> 18) & 0x3F];
out[o++] = b64tab[(n >> 12) & 0x3F];
out[o++] = b64tab[(n >> 6) & 0x3F];
out[o++] = '=';
}
out[o] = '\0';
return (long)o;
}
unsigned char *read_file_all(const char *path, size_t *out_len)
{
FILE *f = fopen(path, "rb");
if (!f)
return NULL;
if (fseek(f, 0, SEEK_END) != 0) {
fclose(f);
return NULL;
}
long sz = ftell(f);
if (sz < 0) {
fclose(f);
return NULL;
}
rewind(f);
unsigned char *buf = malloc((size_t)sz > 0 ? (size_t)sz : 1);
if (!buf) {
fclose(f);
return NULL;
}
size_t rd = fread(buf, 1, (size_t)sz, f);
fclose(f);
if (rd != (size_t)sz) {
free(buf);
return NULL;
}
if (out_len)
*out_len = rd;
return buf;
}
int str_ends_with(const char *s, const char *suffix)
{
size_t ls = strlen(s), lsuf = strlen(suffix);
if (lsuf > ls)
return 0;
return strcmp(s + (ls - lsuf), suffix) == 0;
}
int str_starts_with(const char *s, const char *prefix)
{
return strncmp(s, prefix, strlen(prefix)) == 0;
}
int single_instance_lock(void)
{
char path[512];
const char *rundir = getenv("XDG_RUNTIME_DIR");
if (rundir && rundir[0])
snprintf(path, sizeof(path), "%s/transtui.lock", rundir);
else
snprintf(path, sizeof(path), "/tmp/transtui-%d.lock", (int)getuid());
int fd = open(path, O_CREAT | O_RDWR, 0600);
if (fd < 0)
return -1;
if (flock(fd, LOCK_EX | LOCK_NB) != 0) {
close(fd);
return 0;
}
/* fd is deliberately leaked - it must stay open for the process's
* lifetime for the lock to hold, and is closed by the kernel on exit
* (normal or crash) either way. */
return 1;
}
int str_ci_contains(const char *haystack, const char *needle)
{
size_t nlen = strlen(needle);
if (nlen == 0)
return 1;
size_t hlen = strlen(haystack);
if (nlen > hlen)
return 0;
for (size_t i = 0; i + nlen <= hlen; i++) {
size_t j = 0;
for (; j < nlen; j++) {
unsigned char a = (unsigned char)haystack[i + j];
unsigned char b = (unsigned char)needle[j];
if (tolower(a) != tolower(b))
break;
}
if (j == nlen)
return 1;
}
return 0;
}