356 lines
7.0 KiB
C
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
|