Files
cmus/utils.h
2026-03-29 14:01:52 +03:00

356 lines
7.0 KiB
C

/*
* Copyright 2008-2013 Various Authors
* Copyright 2004 Timo Hirvonen
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CMUS_UTILS_H
#define CMUS_UTILS_H
#ifdef HAVE_CONFIG
#include "config/utils.h"
#endif
#include "compiler.h"
#include "debug.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#endif
#define N_ELEMENTS(array) (sizeof(array) / sizeof((array)[0]))
struct slice {
void *ptr;
size_t len;
};
#define TO_SLICE(type, ...) ((struct slice) { \
.ptr = ((type[]){__VA_ARGS__}), \
.len = N_ELEMENTS(((type[]){__VA_ARGS__})), \
})
#define STRINGIZE_HELPER(x) #x
#define STRINGIZE(x) STRINGIZE_HELPER(x)
#define CONCATENATE_HELPER(x,y) x##y
#define CONCATENATE(x,y) CONCATENATE_HELPER(x,y)
#define getentry(ptr, offset, type) (*((type *) ((void *) ((char *) (ptr) + (offset)))))
#define STATIC_ASSERT(cond) \
static uint8_t CONCATENATE(_cmus_unused_, __LINE__)[2*(cond) - 1] UNUSED
static inline long min_i(long a, long b)
{
return a < b ? a : b;
}
static inline unsigned long min_u(unsigned long a, unsigned long b)
{
return a < b ? a : b;
}
static inline long max_i(long a, long b)
{
return a > b ? a : b;
}
static inline unsigned long abs_delta(unsigned long a, unsigned long b)
{
return a > b ? a - b : b - a;
}
static inline int clamp(int val, int minval, int maxval)
{
if (val < minval)
return minval;
if (val > maxval)
return maxval;
return val;
}
static inline int scale_from_percentage(int val, int max_val)
{
if (val < 0)
return (val * max_val - 50) / 100;
return (val * max_val + 50) / 100;
}
static inline int scale_to_percentage(int val, int max_val)
{
int half = max_val / 2;
if (max_val <= 0)
return 100;
if (val < 0)
return (val * 100 - half) / max_val;
return (val * 100 + half) / max_val;
}
static inline int str_to_int(const char *str, long int *val)
{
char *end;
*val = strtol(str, &end, 10);
if (*str == 0 || *end != 0)
return -1;
return 0;
}
static inline int strcmp0(const char *str1, const char *str2)
{
if (!str1)
return str2 ? -1 : 0;
if (!str2)
return 1;
return strcmp(str1, str2);
}
static inline int is_space(const char ch)
{
return (ch == ' ' || ch == '\t');
}
static inline int ends_with(const char *str, const char *suffix)
{
return strstr(str, suffix) + strlen(suffix) == str + strlen(str);
}
static inline void strip_trailing_spaces(char *str)
{
char *end = str + strlen(str);
while (end > str && is_space(*(end-1))) {
end--;
}
*end = 0;
}
static inline uint32_t hash_str(const char *s)
{
const unsigned char *p = (const unsigned char *)s;
uint32_t h = 5381;
while (*p) {
h *= 33;
h ^= *p++;
}
return h ^ (h >> 16);
}
static inline time_t file_get_mtime(const char *filename)
{
struct stat s;
/* stat follows symlinks, lstat does not */
if (stat(filename, &s) == -1)
return -1;
return s.st_mtime;
}
static inline void ns_sleep(int ns)
{
struct timespec req;
req.tv_sec = 0;
req.tv_nsec = ns;
nanosleep(&req, NULL);
}
static inline void us_sleep(int us)
{
ns_sleep(us * 1e3);
}
static inline void ms_sleep(int ms)
{
ns_sleep(ms * 1e6);
}
static inline int is_http_url(const char *name)
{
return strncmp(name, "http://", 7) == 0;
}
static inline int is_cdda_url(const char *name)
{
return strncmp(name, "cdda://", 7) == 0;
}
static inline int is_cue_url(const char *name)
{
return strncmp(name, "cue://", 6) == 0;
}
static inline int is_url(const char *name)
{
return is_http_url(name) || is_cdda_url(name) || is_cue_url(name);
}
static inline int is_freeform_true(const char *c)
{
return c[0] == '1' ||
c[0] == 'y' || c[0] == 'Y' ||
c[0] == 't' || c[0] == 'T';
}
/* e.g. NetBSD */
#if defined(bswap16)
/* GNU libc */
#elif defined(bswap_16)
# define bswap16 bswap_16
/* e.g. OpenBSD */
#elif defined(swap16)
# define bswap16 swap16
#else
# define bswap16(x) \
((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
#endif
static inline uint16_t swap_uint16(uint16_t x)
{
return bswap16(x);
}
/* e.g. NetBSD */
#if defined(bswap32)
/* GNU libc */
#elif defined(bswap_32)
# define bswap32 bswap_32
/* e.g. OpenBSD */
#elif defined(swap32)
# define bswap32 swap32
#else
# define bswap32(x) \
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
#endif
static inline uint32_t swap_uint32(uint32_t x)
{
return bswap32(x);
}
static inline uint32_t read_le32(const char *buf)
{
const unsigned char *b = (const unsigned char *)buf;
return b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
}
static inline uint32_t read_le24(const char *buf)
{
const unsigned char *b = (const unsigned char *)buf;
return b[0] | (b[1] << 8) | (b[2] << 16);
}
static inline int32_t read_le24i(const char *buf)
{
uint32_t a = read_le24(buf);
return (a & 0x800000) ? 0xFF000000 | a : a;
}
static inline uint16_t read_le16(const char *buf)
{
const unsigned char *b = (const unsigned char *)buf;
return b[0] | (b[1] << 8);
}
static int _saved_stdout;
static int _saved_stderr;
static inline void disable_stdio(void)
{
_saved_stdout = dup(1);
_saved_stderr = dup(2);
if (_saved_stdout == -1 || _saved_stderr == -1) {
return;
}
int devnull = open("/dev/null", O_WRONLY);
dup2(devnull, 1);
dup2(devnull, 2);
close(devnull);
}
static inline void enable_stdio(void)
{
fflush(stdout);
fflush(stderr);
while (dup2(_saved_stdout, 1) == -1 && errno == EINTR) { }
while (dup2(_saved_stderr, 2) == -1 && errno == EINTR) { }
close(_saved_stdout);
close(_saved_stderr);
}
static inline void init_pipes(int *out, int *in)
{
int fds[2];
int rc = pipe(fds);
BUG_ON(rc);
*out = fds[0];
*in = fds[1];
int flags = fcntl(*out, F_GETFL);
rc = fcntl(*out, F_SETFL, flags | O_NONBLOCK);
BUG_ON(rc);
}
static inline void notify_via_pipe(int pipe)
{
char buf = 0;
if (write(pipe, &buf, 1) != 1) {
d_print("write to pipe failed. errno = %d\n", errno);
}
}
static inline void clear_pipe(int pipe, size_t bytes)
{
char buf[128];
size_t bytes_to_read = min_u(sizeof(buf), bytes);
if (read(pipe, buf, bytes_to_read) < 0) {
d_print("read from pipe failed. errno = %d\n", errno);
}
}
static inline ssize_t strscpy(char *dst, const char *src, size_t size)
{
for (size_t i = 0; i < size; i++) {
dst[i] = src[i];
if (src[i] == 0)
return i;
}
if (size > 0)
dst[size - 1] = 0;
return -1;
}
#endif