9 n__common_8h
gullradriel edited this page 2026-10-29 20:54:40 +01:00

include/nilorea/n_common.h

Common headers and low-level functions & define. More...

Detailed Description

Common headers and low-level functions & define.

Author: Castagnier Mickael

Version: 1.0

Date: 24/03/05

Source code

/*
 * Nilorea Library
 * Copyright (C) 2005-2026 Castagnier Mickael
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#ifndef __NILOREA_COMMONS__
#define __NILOREA_COMMONS__

#ifdef __cplusplus
extern "C" {
#endif


#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <malloc.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <stdint.h>
#include <nilorea/n_log.h>
#include <nilorea/n_enum.h>

#if defined(_WIN32) || defined(_WIN64)
#ifndef __windows__
#define __windows__
#endif
#ifndef WEXITSTATUS
#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
#endif
#ifndef WIFEXITED
#define WIFEXITED(w) (((w) & 0xff) == 0)
#endif
#else
#include <alloca.h>
#include <signal.h>
#endif

#if defined(__GNUC__) && __GNUC__ >= 7
#define FALL_THROUGH __attribute__((fallthrough))
#else
#define FALL_THROUGH /* fall through */ \
    ((void)0)
#endif /* __GNUC__ >= 7 */

#if defined(_WIN32) || defined(_WIN64)
#if defined(_WIN64)
#define ENV_64BITS
#else
#define ENV_32BITS
#endif
#endif

#if !defined(ENV_32BITS) || !defined(ENV_64BITS)
#if defined(__GNUC__)
#if defined(__x86_64__) || defined(__ppc64__)
#define __ENVBITS __ENV_64BITS
#else
#define __ENVBITS __ENV_32BITS
#endif
#endif
#endif

#define BYTEORDER_LITTLE_ENDIAN 0  // Little endian machine.
#define BYTEORDER_BIG_ENDIAN 1  // Big endian machine.

#ifndef BYTEORDER_ENDIAN
// Detect with GCC 4.6's macro.
#if defined(__BYTE_ORDER__)
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define BYTEORDER_ENDIAN BYTEORDER_BIG_ENDIAN
#else
#define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#warning "Unknown machine byteorder endianness detected. User needs to define BYTEORDER_ENDIAN."
#warning "Setting default to BYTEORDER_LITTLE_ENDIAN"
#endif
// Detect with GLIBC's endian.h.
#elif defined(__GLIBC__)
#include <endian.h>
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
#define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#elif (__BYTE_ORDER == __BIG_ENDIAN)
#define BYTEORDER_ENDIAN BYTEORDER_BIG_ENDIAN
#else
#define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#warning "Unknown machine byteorder endianness detected. User needs to define BYTEORDER_ENDIAN."
#warning "Setting default to BYTEORDER_LITTLE_ENDIAN"
#endif
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro.
#elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
#define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
#define BYTEORDER_ENDIAN BYTEORDER_BIG_ENDIAN
// Detect with architecture macros.
#elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
#define BYTEORDER_ENDIAN BYTEORDER_BIG_ENDIAN
#elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
#define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
#define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#else
#define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#warning "Unknown machine byteorder endianness detected. User needs to define BYTEORDER_ENDIAN."
#warning "Setting default to BYTEORDER_LITTLE_ENDIAN"
#endif
#endif

#if defined(__windows__)
/* typedefine for unsigned category for basic native types */
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned short ushort;
typedef unsigned char uchar;
#endif

#ifdef _MSVC_VER
#define FORCE_INLINE __forceinline
#elif defined(__linux__) || defined(__windows__)
#define FORCE_INLINE static inline __attribute__((always_inline))
#else
#define FORCE_INLINE static inline __attribute__((always_inline))
#endif

#ifndef true
#define true (1 == 1)
#endif

#ifndef TRUE
#define TRUE true
#endif

#ifndef false
#define false (1 == 0)
#endif

#ifndef FALSE
#define FALSE false
#endif

#ifndef EMPTY
#define EMPTY 2
#endif

#define _str(__PTR) ((__PTR) ? (__PTR) : "NULL")
#define _strp(__PTR) ((__PTR) ? (__PTR) : NULL)
#define _strw(__PTR) ((__PTR) ? (__PTR) : " ")
#define _nstr(__PTR) ((__PTR && __PTR->data) ? (__PTR->data) : "NULL")
#define _nstrp(__PTR) ((__PTR && __PTR->data) ? (__PTR->data) : NULL)

#define Malloc(__ptr, __struct, __size)                                                                                                                                                                  \
    {                                                                                                                                                                                                    \
        int __n_errno = 0;                                                                                                                                                                               \
        errno = 0;                                                                                                                                                                                       \
        __ptr = (__struct*)calloc(__size, sizeof(__struct));                                                                                                                                             \
        __n_errno = errno;                                                                                                                                                                               \
        if (!__ptr) {                                                                                                                                                                                    \
            n_log(LOG_ERR, "( %s *)calloc( %zu , sizeof( %s ) ) %s at line %d of %s", #__ptr, (size_t)(__size), #__struct, (__n_errno == 0) ? "malloc error" : strerror(__n_errno), __LINE__, __FILE__); \
        }                                                                                                                                                                                                \
    }

#define Alloca(__ptr, __size)                                                                                                                                              \
    {                                                                                                                                                                      \
        int __n_errno = 0;                                                                                                                                                 \
        errno = 0;                                                                                                                                                         \
        __ptr = alloca(__size);                                                                                                                                            \
        __n_errno = errno;                                                                                                                                                 \
        if (!__ptr) {                                                                                                                                                      \
            n_log(LOG_ERR, "%s=alloca( %zu ) %s at line %d of %s", #__ptr, (size_t)(__size), (__n_errno == 0) ? "alloca error" : strerror(__n_errno), __LINE__, __FILE__); \
        } else {                                                                                                                                                           \
            memset(__ptr, 0, __size);                                                                                                                                      \
        }                                                                                                                                                                  \
    }

#define Realloc(__ptr, __struct, __size)                                                                                                                                                                   \
    ({                                                                                                                                                                                                     \
        int __n_errno = 0;                                                                                                                                                                                 \
        errno = 0;                                                                                                                                                                                         \
        void* __new_ptr = ((__size) && (sizeof(__struct)) && ((__size) > SIZE_MAX / sizeof(__struct))) ? NULL : (__struct*)realloc(__ptr, (__size) * sizeof(__struct));                                    \
        __n_errno = errno;                                                                                                                                                                                 \
        if (!__new_ptr) {                                                                                                                                                                                  \
            n_log(LOG_ERR, "( %s *)realloc( %s * sizeof( %zu ) ) %s at line %d of %s", #__ptr, #__struct, (size_t)(__size), (__n_errno == 0) ? "realloc error" : strerror(__n_errno), __LINE__, __FILE__); \
        } else {                                                                                                                                                                                           \
            __ptr = __new_ptr;                                                                                                                                                                             \
        }                                                                                                                                                                                                  \
        (__new_ptr != NULL) ? TRUE : FALSE;                                                                                                                                                                \
    })

#define Reallocz(__ptr, __struct, __old_size, __size)                                                                                                                                                      \
    ({                                                                                                                                                                                                     \
        int __n_errno = 0;                                                                                                                                                                                 \
        errno = 0;                                                                                                                                                                                         \
        void* __new_ptr = ((__size) && (sizeof(__struct)) && ((__size) > SIZE_MAX / sizeof(__struct))) ? NULL : (__struct*)realloc(__ptr, __size);                                                         \
        __n_errno = errno;                                                                                                                                                                                 \
        if (!__new_ptr) {                                                                                                                                                                                  \
            n_log(LOG_ERR, "( %s *)realloc( %s * sizeof( %zu ) ) %s at line %d of %s", #__ptr, #__struct, (size_t)(__size), (__n_errno == 0) ? "realloc error" : strerror(__n_errno), __LINE__, __FILE__); \
        } else {                                                                                                                                                                                           \
            __ptr = __new_ptr;                                                                                                                                                                             \
            if (__size > __old_size) memset(((char*)__ptr + __old_size), 0, __size - __old_size);                                                                                                          \
        }                                                                                                                                                                                                  \
        (__new_ptr != NULL) ? TRUE : FALSE;                                                                                                                                                                \
    })

#define Free(__ptr)                                                                                       \
    if (__ptr) {                                                                                          \
        free(__ptr);                                                                                      \
        __ptr = NULL;                                                                                     \
    } else {                                                                                              \
        n_log(LOG_DEBUG, "Free( %s ) already done or NULL at line %d of %s", #__ptr, __LINE__, __FILE__); \
    }

#define FreeNoLog(__ptr) \
    if (__ptr) {         \
        free(__ptr);     \
        __ptr = NULL;    \
    }

#define __n_assert(__ptr, __ret)                                                             \
    if (!(__ptr)) {                                                                          \
        n_log(LOG_DEBUG, "if( !(%s) ) assert at line %d of %s", #__ptr, __LINE__, __FILE__); \
        __ret;                                                                               \
    }

#define CALL_RETRY(__retvar, __expression, __max_tries)                             \
    do {                                                                            \
        int __nb_retries = 0;                                                       \
        do {                                                                        \
            __retvar = (__expression);                                              \
            __nb_retries++;                                                         \
        } while (__retvar == -1 && errno == EINTR && __nb_retries < (__max_tries)); \
    } while (0)

#define next_odd(__val) (((__val) % 2 == 0) ? ((__val) + 1) : (__val))

#define next_even(__val) (((__val) % 2 == 0) ? (__val) : ((__val) + 1))

#define init_error_check() \
    static int ___error__check_flag = FALSE;

#define ifnull if( !

#define ifzero if( 0 ==

#define iffalse if( FALSE ==

#define iftrue if( TRUE ==

#define checkerror()                                                                    \
    if (___error__check_flag == TRUE) {                                                 \
        n_log(LOG_ERR, "checkerror return false at line %d of %s", __LINE__, __FILE__); \
        goto error;                                                                     \
    }

#define endif ){                                                              \
        ___error__check_flag = TRUE;                                          \
        n_log(LOG_ERR, "First err was at line %d of %s", __LINE__, __FILE__); \
    }

#define get_error() \
    (___error__check_flag == TRUE)

#define equal_if(__a, __cond, __b) \
    if ((__a)__cond(__b)) {        \
        __a = __b;                 \
    }

// #define RWLOCK_DEBUG 1
#ifdef RWLOCK_DEBUG
#define RWLOCK_LOGLEVEL LOG_DEBUG
#else
#define RWLOCK_LOGLEVEL LOG_NULL
#endif

#define init_lock(__rwlock_mutex)                                                                                                             \
    ({                                                                                                                                        \
        pthread_rwlockattr_t __attr;                                                                                                          \
        pthread_rwlockattr_init(&__attr);                                                                                                     \
        int __ret = 0;                                                                                                                        \
        do {                                                                                                                                  \
            n_log(RWLOCK_LOGLEVEL, "init_lock %s", #__rwlock_mutex);                                                                          \
            __rwlock_mutex = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER;                                                                    \
            __ret = pthread_rwlock_init(&(__rwlock_mutex), &__attr);                                                                          \
            if (__ret != 0) {                                                                                                                 \
                n_log(LOG_ERR, "Error %s while initializing %s at %s:%s:%d", strerror(__ret), #__rwlock_mutex, __FILE__, __func__, __LINE__); \
            }                                                                                                                                 \
            pthread_rwlockattr_destroy(&__attr);                                                                                              \
        } while (0);                                                                                                                          \
        __ret;                                                                                                                                \
    })

#define read_lock(__rwlock_mutex)                                                                                                             \
    ({                                                                                                                                        \
        int __ret = 0;                                                                                                                        \
        do {                                                                                                                                  \
            n_log(RWLOCK_LOGLEVEL, "read lock %s", #__rwlock_mutex);                                                                          \
            __ret = pthread_rwlock_rdlock(&(__rwlock_mutex));                                                                                 \
            if (__ret != 0) {                                                                                                                 \
                n_log(LOG_ERR, "Error %s while read locking %s at %s:%s:%d", strerror(__ret), #__rwlock_mutex, __FILE__, __func__, __LINE__); \
            }                                                                                                                                 \
        } while (0);                                                                                                                          \
        __ret;                                                                                                                                \
    })

#define write_lock(__rwlock_mutex)                                                                                                             \
    ({                                                                                                                                         \
        int __ret = 0;                                                                                                                         \
        do {                                                                                                                                   \
            n_log(RWLOCK_LOGLEVEL, "write lock %s", #__rwlock_mutex);                                                                          \
            __ret = pthread_rwlock_wrlock(&(__rwlock_mutex));                                                                                  \
            if (__ret != 0) {                                                                                                                  \
                n_log(LOG_ERR, "Error %s while write locking %s at %s:%s:%d", strerror(__ret), #__rwlock_mutex, __FILE__, __func__, __LINE__); \
            }                                                                                                                                  \
        } while (0);                                                                                                                           \
        __ret;                                                                                                                                 \
    })

#define unlock(__rwlock_mutex)                                                                                                             \
    ({                                                                                                                                     \
        int __ret = 0;                                                                                                                     \
        do {                                                                                                                               \
            n_log(RWLOCK_LOGLEVEL, "unlock lock %s", #__rwlock_mutex);                                                                     \
            __ret = pthread_rwlock_unlock(&(__rwlock_mutex));                                                                              \
            if (__ret != 0) {                                                                                                              \
                n_log(LOG_ERR, "Error %s while unlocking %s at %s:%s:%d", strerror(__ret), #__rwlock_mutex, __FILE__, __func__, __LINE__); \
            }                                                                                                                              \
        } while (0);                                                                                                                       \
        __ret;                                                                                                                             \
    })
#define rw_lock_destroy(__rwlock_mutex)                                                                                                     \
    ({                                                                                                                                      \
        int __ret = 0;                                                                                                                      \
        do {                                                                                                                                \
            n_log(RWLOCK_LOGLEVEL, "destroy lock %s", #__rwlock_mutex);                                                                     \
            __ret = pthread_rwlock_destroy(&(__rwlock_mutex));                                                                              \
            if (__ret != 0) {                                                                                                               \
                n_log(LOG_ERR, "Error %s while destroying %s at %s:%s:%d", strerror(__ret), #__rwlock_mutex, __FILE__, __func__, __LINE__); \
            }                                                                                                                               \
        } while (0);                                                                                                                        \
        __ret;                                                                                                                              \
    })

#define SET 1234
#define GET 4321
#define DEFAULT 1000
#define RUNNING 1001
#define STOPWANTED 1002
#define STOPPED 1003
#define PAUSED 1004

#define randomize()                  \
    {                                \
        srand((unsigned)time(NULL)); \
        rand();                      \
    }

#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif

#define CONCAT_BUILDER(a, b) a##b
#define CONCAT(a, b) CONCAT_BUILDER(a, b)

/* On Windows, Winsock (winsock2.h) already declares htonll/ntohll as functions.
   Defining them as macros here makes those later function declarations fail to parse
   (the macro expands inside the prototype), so the 64-bit byte-order fallbacks are only
   defined on non-Windows platforms; Windows code uses Winsock's htonll/ntohll. */
#ifndef __windows__
#if (BYTEORDER_ENDIAN == BYTEORDER_BIG_ENDIAN)
#ifndef htonll
#define htonll(x) (x)
#endif
#ifndef ntohll
#define ntohll(x) (x)
#endif
#else
#ifndef htonll
#define htonll(x) (((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
#endif
#ifndef ntohll
#define ntohll(x) (((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
#endif
#endif
#endif /* __windows__ */

void n_abort(char const* format, ...) N_PRINTF_FORMAT(1, 2);

int get_computer_name(char* computer_name, size_t len);

char* get_prog_name(void);

char* get_prog_dir(void);

int file_exist(const char* filename);

int n_popen(char* cmd, size_t read_buf_size, void** nstr_output, int* ret);

int n_spawn_detached(const char* program, const char* const* args);

int n_spawn_wait(const char* program, const char* const* args, int* exit_code);

int n_spawn_wait_cancel(const char* program, const char* const* args, int* exit_code, const volatile int* cancel);

typedef struct N_SPAWN_PIPE N_SPAWN_PIPE;

N_SPAWN_PIPE* n_spawn_pipe_open(const char* program, const char* const* args, const char* log_path);

N_SPAWN_PIPE* n_spawn_pipe_open_read(const char* program, const char* const* args, const char* log_path);

size_t n_spawn_pipe_read(N_SPAWN_PIPE* pipe, void* data, size_t len);

int n_spawn_pipe_write(N_SPAWN_PIPE* pipe, const void* data, size_t len);

int n_spawn_pipe_close(N_SPAWN_PIPE** pipe, int stop, int* exit_code);

int n_open_with_default(const char* path);

void log_environment(int loglevel);

#ifndef __windows__
void sigchld_handler(int sig);
int sigchld_handler_installer(void);
#define N_DAEMON_NO_CLOSE 2
#define N_DAEMON_NO_STD_REDIRECT 4
#define N_DAEMON_NO_DOUBLE_FORK 8
#define N_DAEMON_NO_SETSID 16
#define N_DAEMON_NO_UMASK 32
#define N_DAEMON_NO_CHDIR 64
#define N_DAEMON_NO_SIGCHLD_IGN 128
#define N_DAEMON_NO_SIGCHLD_HANDLER 256
int n_daemonize(void);
int n_daemonize_ex(int mode);
pid_t system_nb(const char* command, int* infp, int* outfp);
#endif

void N_HIDE_STR(char* buf, ...);

char* n_get_file_extension(char path[]);

#ifdef __cplusplus
}
#endif

#endif  // header guard