/* 
 | 
 * BlueALSA - log.c 
 | 
 * Copyright (c) 2016-2018 Arkadiusz Bokowy 
 | 
 * 
 | 
 * This file is a part of bluez-alsa. 
 | 
 * 
 | 
 * This project is licensed under the terms of the MIT license. 
 | 
 * 
 | 
 */ 
 | 
  
 | 
#include "shared/log.h" 
 | 
  
 | 
#include <pthread.h> 
 | 
#include <stdarg.h> 
 | 
#include <stdio.h> 
 | 
#include <stdlib.h> 
 | 
#include <string.h> 
 | 
#include <syslog.h> 
 | 
  
 | 
#include "shared/rt.h" 
 | 
  
 | 
  
 | 
/* internal logging identifier */ 
 | 
static char *_ident = NULL; 
 | 
/* if true, system logging is enabled */ 
 | 
static bool _syslog = false; 
 | 
/* if true, print logging time */ 
 | 
static bool _time = BLUEALSA_LOGTIME; 
 | 
  
 | 
  
 | 
void log_open(const char *ident, bool syslog, bool time) { 
 | 
  
 | 
    free(_ident); 
 | 
    _ident = strdup(ident); 
 | 
  
 | 
    if ((_syslog = syslog) == true) 
 | 
        openlog(ident, 0, LOG_USER); 
 | 
  
 | 
    _time = time; 
 | 
  
 | 
} 
 | 
  
 | 
static void vlog(int priority, const char *format, va_list ap) { 
 | 
  
 | 
    int oldstate; 
 | 
  
 | 
    /* Threads cancellation is used extensively in the BlueALSA code. In order 
 | 
     * to prevent termination within the logging function (which might provide 
 | 
     * important information about what has happened), the thread cancellation 
 | 
     * has to be temporally disabled. */ 
 | 
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); 
 | 
  
 | 
    //if (_syslog) { 
 | 
        va_list ap_syslog; 
 | 
        va_copy(ap_syslog, ap); 
 | 
        vsyslog(priority, format, ap_syslog); 
 | 
        va_end(ap_syslog); 
 | 
    //} 
 | 
  
 | 
    flockfile(stderr); 
 | 
  
 | 
    if (_ident != NULL) 
 | 
        fprintf(stderr, "%s: ", _ident); 
 | 
    if (_time) { 
 | 
        struct timespec ts; 
 | 
        gettimestamp(&ts); 
 | 
        fprintf(stderr, "%lu.%.9lu: ", (long int)ts.tv_sec, ts.tv_nsec); 
 | 
    } 
 | 
    vfprintf(stderr, format, ap); 
 | 
    fputs("\n", stderr); 
 | 
  
 | 
    funlockfile(stderr); 
 | 
  
 | 
    pthread_setcancelstate(oldstate, NULL); 
 | 
  
 | 
} 
 | 
  
 | 
void error(const char *format, ...) { 
 | 
    va_list ap; 
 | 
    va_start(ap, format); 
 | 
    vlog(LOG_ERR, format, ap); 
 | 
    va_end(ap); 
 | 
} 
 | 
  
 | 
void warn(const char *format, ...) { 
 | 
    va_list ap; 
 | 
    va_start(ap, format); 
 | 
    vlog(LOG_WARNING, format, ap); 
 | 
    va_end(ap); 
 | 
} 
 | 
  
 | 
void info(const char *format, ...) { 
 | 
    va_list ap; 
 | 
    va_start(ap, format); 
 | 
    vlog(LOG_INFO, format, ap); 
 | 
    va_end(ap); 
 | 
} 
 | 
  
 | 
#if DEBUG 
 | 
void _debug(const char *format, ...) { 
 | 
    va_list ap; 
 | 
    va_start(ap, format); 
 | 
    vlog(LOG_DEBUG, format, ap); 
 | 
    va_end(ap); 
 | 
} 
 | 
#endif 
 | 
  
 | 
#if DEBUG 
 | 
/** 
 | 
 * Dump memory using hexadecimal representation. 
 | 
 * 
 | 
 * @param label Label printed before the memory block output. 
 | 
 * @param mem Address of the memory block. 
 | 
 * @param len Number of bytes which should be printed. */ 
 | 
void hexdump(const char *label, const void *mem, size_t len) { 
 | 
  
 | 
    char *buf = malloc(len * 3 + 1); 
 | 
    char *p = buf; 
 | 
  
 | 
    while (len--) { 
 | 
        p += sprintf(p, " %02x", *(unsigned char *)mem & 0xFF); 
 | 
        mem += 1; 
 | 
    } 
 | 
  
 | 
    fprintf(stderr, "%s:%s\n", label, buf); 
 | 
    free(buf); 
 | 
} 
 | 
#endif 
 | 
  
 | 
#if DEBUG && HAVE_REGISTER_PRINTF_SPECIFIER 
 | 
/* Register 'B' specifier for printf() function family, so it can 
 | 
 * be used to print integer values in a binary representation. */ 
 | 
  
 | 
#include <printf.h> 
 | 
  
 | 
static int printf_arginfo(const struct printf_info *info, size_t n, int *argtypes, int *size) { 
 | 
    (void)info; 
 | 
    if (n >= 1) 
 | 
        argtypes[0] = PA_INT; 
 | 
    return *size = 1; 
 | 
} 
 | 
  
 | 
static int printf_output(FILE *stream, const struct printf_info *info, const void * const *args) { 
 | 
  
 | 
    unsigned int v = *(unsigned int *)(args[0]); 
 | 
    bool output = false; 
 | 
    int len = 0; 
 | 
    int i; 
 | 
  
 | 
    if (info->alt) 
 | 
        fputs("0b", stream); 
 | 
  
 | 
    for (i = (sizeof(v) * 8) - 1; i >= 0; i--) { 
 | 
        char c = '0' + ((v >> i) & 1); 
 | 
        if (output || c == '1') { 
 | 
            fputc(c, stream); 
 | 
            output = true; 
 | 
            len++; 
 | 
        } 
 | 
        else if (i == info->width) 
 | 
            output = true; 
 | 
    } 
 | 
  
 | 
    return len; 
 | 
} 
 | 
  
 | 
void __attribute__ ((constructor)) _register_binary_specifier() { 
 | 
    register_printf_specifier('B', printf_output, printf_arginfo); 
 | 
} 
 | 
#endif 
 |