349 lines
10 KiB
C
349 lines
10 KiB
C
/*
|
|
* util.h - useful functions header
|
|
*
|
|
* Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
|
|
* Copyright © 2006 Pierre Habouzit <madcoder@debian.org>
|
|
*
|
|
* 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, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
*/
|
|
|
|
#ifndef AWESOME_COMMON_UTIL_H
|
|
#define AWESOME_COMMON_UTIL_H
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <stdarg.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
|
|
#if !(defined (__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__))
|
|
#include <alloca.h>
|
|
#endif
|
|
|
|
typedef enum
|
|
{
|
|
East = 0,
|
|
South,
|
|
North,
|
|
} orientation_t;
|
|
|
|
/** A list of possible position, not sex related */
|
|
typedef enum
|
|
{
|
|
Top = 0,
|
|
Bottom,
|
|
Right,
|
|
Left
|
|
} position_t;
|
|
|
|
/** \brief replace \c NULL strings with empty strings */
|
|
#define NONULL(x) (x ? x : "")
|
|
|
|
#define DO_NOTHING(...)
|
|
|
|
#undef MAX
|
|
#undef MIN
|
|
#define MAX(a,b) ((a) < (b) ? (b) : (a))
|
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
|
|
#define unsigned_subtract(a, b) \
|
|
do { \
|
|
if (b > a) \
|
|
a = 0; \
|
|
else \
|
|
a -= b; \
|
|
} while (0)
|
|
|
|
#define ssizeof(foo) (ssize_t)sizeof(foo)
|
|
#define countof(foo) (ssizeof(foo) / ssizeof(foo[0]))
|
|
#define fieldsizeof(type_t, m) sizeof(((type_t *)0)->m)
|
|
#define fieldtypeof(type_t, m) typeof(((type_t *)0)->m)
|
|
|
|
#define p_alloca(type, count) \
|
|
((type *)memset(alloca(sizeof(type) * (count)), \
|
|
0, sizeof(type) * (count)))
|
|
|
|
#define p_alloc_nr(x) (((x) + 16) * 3 / 2)
|
|
#define p_new(type, count) ((type *)xmalloc(sizeof(type) * (count)))
|
|
#define p_clear(p, count) ((void)memset((p), 0, sizeof(*(p)) * (count)))
|
|
#define p_realloc(pp, count) xrealloc((void*)(pp), sizeof(**(pp)) * (count))
|
|
#define p_dup(p, count) xmemdup((p), sizeof(*(p)) * (count))
|
|
#define p_grow(pp, goalnb, allocnb) \
|
|
do { \
|
|
if ((goalnb) > *(allocnb)) { \
|
|
if (p_alloc_nr(*(allocnb)) < (goalnb)) { \
|
|
*(allocnb) = (goalnb); \
|
|
} else { \
|
|
*(allocnb) = p_alloc_nr(*(allocnb)); \
|
|
} \
|
|
p_realloc(pp, *(allocnb)); \
|
|
} \
|
|
} while (0)
|
|
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#define p_delete(mem_pp) \
|
|
do { \
|
|
typeof(**(mem_pp)) **__ptr = (mem_pp); \
|
|
free(*__ptr); \
|
|
*__ptr = NULL; \
|
|
} while(0)
|
|
|
|
#define likely(expr) __builtin_expect(!!(expr), 1)
|
|
#define unlikely(expr) __builtin_expect((expr), 0)
|
|
|
|
#else
|
|
|
|
#define p_delete(mem_p) \
|
|
do { \
|
|
void *__ptr = (mem_p); \
|
|
free(*__ptr); \
|
|
*(void **)__ptr = NULL; \
|
|
} while (0)
|
|
|
|
#define likely(expr) expr
|
|
#define unlikely(expr) expr
|
|
|
|
#endif
|
|
|
|
static inline void * __attribute__ ((malloc)) xmalloc(ssize_t size)
|
|
{
|
|
void *ptr;
|
|
|
|
if(size <= 0)
|
|
return NULL;
|
|
|
|
ptr = calloc(1, size);
|
|
|
|
if(!ptr)
|
|
abort();
|
|
|
|
return ptr;
|
|
}
|
|
|
|
static inline void
|
|
xrealloc(void **ptr, ssize_t newsize)
|
|
{
|
|
if(newsize <= 0)
|
|
p_delete(ptr);
|
|
else
|
|
{
|
|
*ptr = realloc(*ptr, newsize);
|
|
if(!*ptr)
|
|
abort();
|
|
}
|
|
}
|
|
|
|
/** Duplicate a memory zone.
|
|
* \param src The source.
|
|
* \param size The source size.
|
|
* \return The memory address of the copy.
|
|
*/
|
|
static inline void *xmemdup(const void *src, ssize_t size)
|
|
{
|
|
return memcpy(xmalloc(size), src, size);
|
|
}
|
|
|
|
/** \brief \c NULL resistant strlen.
|
|
*
|
|
* Unlike it's libc sibling, a_strlen returns a ssize_t, and supports its
|
|
* argument being NULL.
|
|
*
|
|
* \param[in] s the string.
|
|
* \return the string length (or 0 if \c s is \c NULL).
|
|
*/
|
|
static inline ssize_t a_strlen(const char *s)
|
|
{
|
|
return s ? strlen(s) : 0;
|
|
}
|
|
|
|
/** \brief \c NULL resistant strnlen.
|
|
*
|
|
* Unlike it's GNU libc sibling, a_strnlen returns a ssize_t, and supports
|
|
* its argument being NULL.
|
|
*
|
|
* The a_strnlen() function returns the number of characters in the string
|
|
* pointed to by \c s, not including the terminating \c \\0 character, but at
|
|
* most \c n. In doing this, a_strnlen() looks only at the first \c n
|
|
* characters at \c s and never beyond \c s+n.
|
|
*
|
|
* \param[in] s the string.
|
|
* \param[in] n the maximum length to return.
|
|
* \return \c a_strlen(s) if less than \c n, else \c n.
|
|
*/
|
|
static inline ssize_t a_strnlen(const char *s, ssize_t n)
|
|
{
|
|
if (s)
|
|
{
|
|
const char *p = memchr(s, '\0', n);
|
|
return p ? p - s : n;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/** \brief \c NULL resistant strdup.
|
|
*
|
|
* The a_strdup() function returns a pointer to a new string, which is a
|
|
* duplicate of \c s. Memory should be freed using p_delete().
|
|
*
|
|
* \warning when s is \c "", it returns NULL !
|
|
*
|
|
* \param[in] s the string to duplicate.
|
|
* \return a pointer to the duplicated string.
|
|
*/
|
|
static inline
|
|
char *a_strdup(const char *s)
|
|
{
|
|
ssize_t len = a_strlen(s);
|
|
return len ? p_dup(s, len + 1) : NULL;
|
|
}
|
|
|
|
/** \brief safe limited strdup.
|
|
*
|
|
* Copies at most min(<tt>n-1</tt>, \c l) characters from \c src into a newly
|
|
* allocated buffer, always adding a final \c \\0, and returns that buffer.
|
|
*
|
|
* \warning when s is \c "" or l is 0, it returns NULL !
|
|
*
|
|
* \param[in] s source string.
|
|
* \param[in] l maximum number of chars to copy.
|
|
* \return a newly allocated buffer containing the first \c l chars of \c src.
|
|
*/
|
|
static inline
|
|
char * a_strndup(const char *s, ssize_t l)
|
|
{
|
|
ssize_t len = MIN(a_strlen(s), l);
|
|
if(len)
|
|
{
|
|
char *p = p_dup(s, len + 1);
|
|
p[len] = '\0';
|
|
return p;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/** \brief \c NULL resistant strcmp.
|
|
* \param[in] a the first string.
|
|
* \param[in] b the second string.
|
|
* \return <tt>strcmp(a, b)</tt>, and treats \c NULL strings like \c ""
|
|
* ones.
|
|
*/
|
|
static inline int a_strcmp(const char *a, const char *b)
|
|
{
|
|
return strcmp(NONULL(a), NONULL(b));
|
|
}
|
|
|
|
/** \brief \c NULL resistant strcasecmp.
|
|
* \param[in] a the first string.
|
|
* \param[in] b the second string.
|
|
* \return <tt>strcasecmp(a, b)</tt>, and treats \c NULL strings like \c ""
|
|
* ones.
|
|
*/
|
|
static inline int a_strcasecmp(const char *a, const char *b)
|
|
{
|
|
return strcasecmp(NONULL(a), NONULL(b));
|
|
}
|
|
|
|
/** \brief \c NULL resistant strncmp.
|
|
* \param[in] a the first string.
|
|
* \param[in] b the second string.
|
|
* \param[in] n the number of maximum chars to compare.
|
|
* \return <tt>strncmp(a, b, n)</tt>, and treats \c NULL strings like \c ""
|
|
* ones.
|
|
*/
|
|
static inline int a_strncmp(const char *a, const char *b, ssize_t n)
|
|
{
|
|
return strncmp(NONULL(a), NONULL(b), n);
|
|
}
|
|
|
|
ssize_t a_strncpy(char *dst, ssize_t n, const char *src, ssize_t l) __attribute__((nonnull(1)));
|
|
ssize_t a_strcpy(char *dst, ssize_t n, const char *src) __attribute__((nonnull(1)));
|
|
|
|
/** \brief safe strcat.
|
|
*
|
|
* The a_strcat() function appends the string \c src at the end of the buffer
|
|
* \c dst if space is available.
|
|
*
|
|
* \param[in] dst destination buffer.
|
|
* \param[in] n size of the buffer, Negative sizes are allowed.
|
|
* \param[in] src the string to append.
|
|
* \return <tt>a_strlen(dst) + a_strlen(src)</tt>
|
|
*/
|
|
static inline ssize_t a_strcat(char *dst, ssize_t n, const char *src)
|
|
{
|
|
ssize_t dlen = a_strnlen(dst, n - 1);
|
|
return dlen + a_strcpy(dst + dlen, n - dlen, src);
|
|
}
|
|
|
|
/** \brief safe strncat.
|
|
*
|
|
* The a_strncat() function appends at most \c n chars from the string \c src
|
|
* at the end of the buffer \c dst if space is available.
|
|
*
|
|
* \param[in] dst destination buffer.
|
|
* \param[in] n size of the buffer, Negative sizes are allowed.
|
|
* \param[in] src the string to append.
|
|
* \param[in] l maximum number of chars of src to consider.
|
|
* \return the smallest value between <tt>a_strlen(dst) + a_strlen(src)</tt>
|
|
* and <tt>a_strlen(dst) + l</tt>
|
|
*/
|
|
static inline ssize_t
|
|
a_strncat(char *dst, ssize_t n, const char *src, ssize_t l)
|
|
{
|
|
ssize_t dlen = a_strnlen(dst, n - 1);
|
|
return dlen + a_strncpy(dst + dlen, n - dlen, src, l);
|
|
}
|
|
|
|
/** Compute a hash for a string.
|
|
* This is based on 'djb2' algorithm.
|
|
*/
|
|
static inline unsigned long __attribute__ ((nonnull(1)))
|
|
a_strhash(const unsigned char *str)
|
|
{
|
|
unsigned long hash = 5381;
|
|
int c;
|
|
|
|
while((c = *str++))
|
|
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
|
|
|
return hash;
|
|
}
|
|
|
|
#define fatal(string, ...) _fatal(__LINE__, \
|
|
__FUNCTION__, \
|
|
string, ## __VA_ARGS__)
|
|
void _fatal(int, const char *, const char *, ...)
|
|
__attribute__ ((noreturn)) __attribute__ ((format(printf, 3, 4)));
|
|
|
|
#define warn(string, ...) _warn(__LINE__, \
|
|
__FUNCTION__, \
|
|
string, ## __VA_ARGS__)
|
|
void _warn(int, const char *, const char *, ...)
|
|
__attribute__ ((format(printf, 3, 4)));
|
|
|
|
position_t position_fromstr(const char *, ssize_t);
|
|
const char * position_tostr(position_t);
|
|
orientation_t orientation_fromstr(const char *, ssize_t);
|
|
const char * orientation_tostr(orientation_t);
|
|
void a_exec(const char *);
|
|
|
|
#endif
|
|
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|