/* * 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 . */ #ifndef CMUS_UTILS_H #define CMUS_UTILS_H #ifdef HAVE_CONFIG #include "config/utils.h" #endif #include "compiler.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_BYTESWAP_H #include #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