guowenxue
2019-06-25 8b9d3681b4e6ccb248c8898101cb5b9740cfdf13
add LingYun basic library and update makefile
4 files modified
11 files added
3 files renamed
3696 ■■■■■ changed files
mqttd/hal/hal.c 28 ●●●●● patch | view | raw | blame | history
mqttd/hal/hal.h 25 ●●●●● patch | view | raw | blame | history
mqttd/hal/makefile 6 ●●●● patch | view | raw | blame | history
mqttd/hal/sht20.h 1 ●●●● patch | view | raw | blame | history
mqttd/lylib/cJSON.c patch | view | raw | blame | history
mqttd/lylib/cJSON.h patch | view | raw | blame | history
mqttd/lylib/comport.c 574 ●●●●● patch | view | raw | blame | history
mqttd/lylib/comport.h 106 ●●●●● patch | view | raw | blame | history
mqttd/lylib/ini_dictionary.c 398 ●●●●● patch | view | raw | blame | history
mqttd/lylib/ini_dictionary.h 165 ●●●●● patch | view | raw | blame | history
mqttd/lylib/iniparser.c 807 ●●●●● patch | view | raw | blame | history
mqttd/lylib/iniparser.h 308 ●●●●● patch | view | raw | blame | history
mqttd/lylib/klist.h 723 ●●●●● patch | view | raw | blame | history
mqttd/lylib/logger.c 364 ●●●●● patch | view | raw | blame | history
mqttd/lylib/logger.h 104 ●●●●● patch | view | raw | blame | history
mqttd/lylib/makefile 6 ●●●● patch | view | raw | blame | history
mqttd/main.c 73 ●●●● patch | view | raw | blame | history
mqttd/makefile 8 ●●●● patch | view | raw | blame | history
mqttd/hal/hal.c
New file
@@ -0,0 +1,28 @@
/*********************************************************************************
 *      Copyright:  (C) 2019 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  hal.c
 *    Description:  This file is HAL(Hardware Abstract Layer) initial functions
 *
 *        Version:  1.0.0(2019年06月24日)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "2019年06月24日 23时46分47秒"
 *
 ********************************************************************************/
#include "hal.h"
int hal_init(void)
{
    init_led();
    if( sht2x_init() < 0 )
    {
        log_err("Initialise SHT20 failure\n");
        return -2;
    }
    return 0;
}
mqttd/hal/hal.h
New file
@@ -0,0 +1,25 @@
/*********************************************************************************
 *      Copyright:  (C) 2019 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  hal.h
 *    Description:  This file is HAL(Hardware Abstract Layer) initial functions
 *
 *        Version:  1.0.0(2019年06月24日)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "2019年06月24日 23时46分47秒"
 *
 ********************************************************************************/
#ifndef  _HAL_H_
#define  _HAL_H_
#include "lylib/logger.h"
#include "led.h"
#include "ds18b20.h"
#include "sht20.h"
int hal_init(void);
#endif   /* ----- #ifndef _HAL_H_  ----- */
mqttd/hal/makefile
@@ -1,10 +1,14 @@
PWD=$(shell pwd )
LIBNAME=$(shell basename ${PWD} )
PROJPATH=$(shell dirname ${PWD} )
CFLAGS+=-I${PROJPATH}
all: clean
    @rm -f *.o
    @${CROSS_COMPILE}gcc -c *.c
    @${CROSS_COMPILE}gcc ${CFLAGS} -c *.c
    ${CROSS_COMPILE}ar -rcs  lib${LIBNAME}.a *.o
clean:
mqttd/hal/sht20.h
@@ -13,6 +13,7 @@
#ifndef __SHT20_H
#define __SHT20_H
#include <stdio.h>
#include <stdint.h>
#include <time.h>
mqttd/lylib/cJSON.c
mqttd/lylib/cJSON.h
mqttd/lylib/comport.c
New file
@@ -0,0 +1,574 @@
/*  ********************************************************************************
 *      Copyright:  (C) 2018 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  cp_comport.c
 *    Description:  It's the comport operate library.
 *
 *        Version:  2.0.0(10/17/2018~)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "10/17/2018 03:33:25 PM"
 *
 ********************************************************************************/
#include    "comport.h"
void set_settings(st_comport * comport, const char *settings);
/**************************************************************************************
 *  Description: Set the comport structure
 *   Input Args: dev_name:  The comport device name path, such as '/dev/ttyS3'
 *               baudrate:  The baudrate, such as 115200
 *               settings:  The databit,parity,stopbit,flowctrl settings, such as '8N1N'
 *  Output Args: NONE
 * Return Value: The st_comport structure pointer.
 *************************************************************************************/
st_comport *comport_init(const char *dev_name, int baudrate, const char *settings)
{
    st_comport *comport = NULL;
    if (NULL == (comport = (st_comport *) malloc(sizeof(st_comport))))
    {
        return NULL;
    }
    memset(comport, 0, sizeof(st_comport));
    comport->frag_size = 128;
    strncpy(comport->dev_name, dev_name, DEVNAME_LEN);
    comport->baudrate = baudrate;
    set_settings(comport, settings);
#ifdef  COM_DEBUG
    disp_settings(comport);
#endif
    return comport;
}
#ifdef  COM_DEBUG
void disp_settings(st_comport *comport)
{
    COM_PRINT("Device:\t\t\t\"%s\"\n", comport->dev_name);
    COM_PRINT("Baudrate:\t\t%ld\n", comport->baudrate);
    COM_PRINT("DataBit:\t\t\'%d\'\n", comport->databit);
    switch (comport->parity)
    {
      case 0:
          COM_PRINT("Parity:\t\t\t\'N\'\n");
          break;
      case 1:
          COM_PRINT("Parity:\t\t\t\'O\'\n");
          break;
      case 2:
          COM_PRINT("Parity:\t\t\t\'E\'\n");
          break;
      case 3:
          COM_PRINT("Parity:\t\t\t\'S\'\n");
          break;
    }
    COM_PRINT("StopBit:\t\t\'%ld\'\n", (long int)comport->stopbit);
    switch (comport->flowctrl)
    {
      case 0:
          COM_PRINT("FlowCtrl:\t\t\'N\'\n");
          break;
      case 1:
          COM_PRINT("FlowCtrl:\t\t\'S\'\n");
          break;
      case 2:
          COM_PRINT("FlowCtrl:\t\t\'H\'\n");
          break;
      case 3:
          COM_PRINT("FlowCtrl:\t\t\'B\'\n");
          break;
    }
    COM_PRINT("\n");
    return;
}
#endif
/**************************************************************************************
 *  Description: Set the comport databit,parity,stopbit,flowctrl into the comport structure
 *   Input Args: comport: the st_comport pointer
 *               settings: The databit/parity/stopbit/flowctrl settings as like "8N1N"
 *  Output Args: NONE
 * Return Value: NONE
 *************************************************************************************/
void set_settings(st_comport * comport, const char *settings)
{
    if(NULL==settings || NULL==comport)
        return ;
    switch (settings[0])        /* data bit */
    {
      case '7':
          comport->databit = 7;
          break;
      case '8':
      default:
          comport->databit = 8;
          break;
    }
    switch (settings[1])        /* parity */
    {
      case 'O':
      case 'o':
          comport->parity = 1;
          break;
      case 'E':
      case 'e':
          comport->parity = 2;
          break;
      case 'S':
      case 's':
          comport->parity = 3;
          break;
      case 'N':
      case 'n':
      default:
          comport->parity = 0;
          break;
    }
    switch (settings[2])        /* stop bit */
    {
      case '0':
          comport->stopbit = 0;
          break;
      case '1':
      default:
          comport->stopbit = 1;
          break;
    }
    switch (settings[3])        /* flow control */
    {
      case 'S':
      case 's':
          comport->flowctrl = 1;
          break;
      case 'H':
      case 'h':
          comport->flowctrl = 2;
          break;
      case 'B':
      case 'b':
          comport->flowctrl = 3;
          break;
      case 'N':
      case 'n':
      default:
          comport->flowctrl = 0;
          break;
    }
}
void comport_close(st_comport * comport)
{
    if (0 != comport->fd)
    {
        COM_PRINT("Close device \"%s\"\n", comport->dev_name);
        close(comport->fd);
    }
    comport->fd = -1;
}
void comport_term(st_comport * comport)
{
    if(NULL == comport)
        return;
    if ( comport->fd > 0 )
    {
        comport_close(comport);
    }
    memset(comport, 0x00, sizeof(st_comport));
    free(comport);
    return;
}
int comport_open(st_comport * comport)
{
    int retval = -1;
    struct termios old_cfg, new_cfg;
    int old_flags;
    long tmp;
    if(NULL==comport)
        return -1;
    comport_close(comport);
    /* Not a TTY device */
    if( !strstr(comport->dev_name, "tty"))
    {
        COM_PRINT("Open Not tty device \"%s\"\n", comport->dev_name);
        comport->fd = open(comport->dev_name, O_RDWR);
        retval = comport->fd<0 ? -2 : comport->fd;
        goto CleanUp;
    }
    comport->fd = open(comport->dev_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (comport->fd < 0)
    {
        retval = -3;
        goto CleanUp;
    }
    COM_PRINT("Open device \"%s\"\n", comport->dev_name);
    if ((-1 != (old_flags = fcntl(comport->fd, F_GETFL, 0)))
        && (-1 != fcntl(comport->fd, F_SETFL, old_flags & ~O_NONBLOCK)))
    {
        // Flush input and output
        if (-1 == tcflush(comport->fd, TCIOFLUSH))
        {
            retval = -4;
            goto CleanUp;
        }
    }
    else                        // Failure
    {
        retval = -5;
        goto CleanUp;
    }
    if (0 != tcgetattr(comport->fd, &old_cfg))
    {
        retval = -6;          // Failed to get Com settings
        goto CleanUp;
    }
    memset(&new_cfg, 0, sizeof(new_cfg));
    /*=====================================*/
    /*       Configure comport         */
    /*=====================================*/
    new_cfg.c_cflag &= ~CSIZE;
    new_cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    new_cfg.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    new_cfg.c_oflag &= ~(OPOST);
    /* Set the data bit */
    switch (comport->databit)
    {
      case 0x07:
          new_cfg.c_cflag |= CS7;
          break;
      case 0x06:
          new_cfg.c_cflag |= CS6;
          break;
      case 0x05:
          new_cfg.c_cflag |= CS5;
          break;
      default:
          new_cfg.c_cflag |= CS8;
          break;
    }
    /* Set the parity */
    switch (comport->parity)
    {
      case 0x01:               // Odd
          new_cfg.c_cflag |= (PARENB | PARODD);
          new_cfg.c_cflag |= (INPCK | ISTRIP);
          break;
      case 0x02:               // Even
          new_cfg.c_cflag |= PARENB;
          new_cfg.c_cflag &= ~PARODD;;
          new_cfg.c_cflag |= (INPCK | ISTRIP);
          break;
      case 0x03:
          new_cfg.c_cflag &= ~PARENB;
          new_cfg.c_cflag &= ~CSTOPB;
          break;
      default:
          new_cfg.c_cflag &= ~PARENB;
    }
    /* Set Stop bit */
    if (0x01 != comport->stopbit)
    {
        new_cfg.c_cflag |= CSTOPB;
    }
    else
    {
        new_cfg.c_cflag &= ~CSTOPB;
    }
    /* Set flow control */
    switch (comport->flowctrl)
    {
      case 1:                  // Software control
      case 3:
          new_cfg.c_cflag &= ~(CRTSCTS);
          new_cfg.c_iflag |= (IXON | IXOFF);
          break;
      case 2:                  // Hardware control
          new_cfg.c_cflag |= CRTSCTS;   // Also called CRTSCTS
          new_cfg.c_iflag &= ~(IXON | IXOFF);
          break;
      default:                 // NONE
          new_cfg.c_cflag &= ~(CRTSCTS);
          new_cfg.c_iflag &= ~(IXON | IXOFF);
          break;
    }
    /* Set baudrate */
    switch (comport->baudrate)
    {
      case 115200:
          tmp = B115200;
          break;
      case 57600:
          tmp = B57600;
          break;
      case 38400:
          tmp = B38400;
          break;
      case 19200:
          tmp = B19200;
          break;
      case 9600:
          tmp = B9600;
          break;
      case 4800:
          tmp = B4800;
          break;
      case 2400:
          tmp = B2400;
          break;
      case 1800:
          tmp = B1800;
          break;
      case 1200:
          tmp = B1200;
          break;
      case 600:
          tmp = B600;
          break;
      case 300:
          tmp = B300;
          break;
      case 200:
          tmp = B200;
          break;
      case 150:
          tmp = B150;
          break;
      case 134:
          tmp = B134;
          break;
      case 110:
          tmp = B110;
          break;
      case 75:
          tmp = B75;
          break;
      case 50:
          tmp = B50;
          break;
      default:
          tmp = B115200;
    }
    cfsetispeed(&new_cfg, tmp);
    cfsetispeed(&new_cfg, tmp);
    /* Set the Com port timeout settings */
    new_cfg.c_cc[VMIN] = 0;
    new_cfg.c_cc[VTIME] = 0;
    tcflush(comport->fd, TCIFLUSH);
    if (0 != tcsetattr(comport->fd, TCSANOW, &new_cfg))
    {
        retval = -7;          // Failed to set device com port settings
        goto CleanUp;
    }
    COM_PRINT("Connected device \"%s\".\n", comport->dev_name);
    retval = comport->fd;
CleanUp:
    COM_PRINT("Open device \"%s\" %s.\n", comport->dev_name, retval>0 ? "successfully" : "failure");
    return retval;
}
int comport_recv(st_comport * comport, char *buf, int buf_size, unsigned long timeout)
{
    int retval = 0;             // Function return value
    int iRet;
    fd_set stReadFds, stExcpFds;
    struct timeval stTime;
    if (NULL == buf || 0 >= buf_size)
    {
        COM_PRINT("%s() usage error.\n", __FUNCTION__);
        retval = -1;
        goto CleanUp;
    }
    if ( comport->fd < 0 )
    {
        COM_PRINT("%s() comport not connected.\n", __FUNCTION__);
        retval = -2;
        goto CleanUp;
    }
    //printf("bufsize=%d timeout=%lu\n", buf_size, timeout);
    FD_ZERO(&stReadFds);
    FD_ZERO(&stExcpFds);
    FD_SET(comport->fd, &stReadFds);
    FD_SET(comport->fd, &stExcpFds);
    if (0xFFFFFFFF != timeout)
    {
        stTime.tv_sec = (time_t) (timeout / 1000);
        stTime.tv_usec = (long)(1000 * (timeout % 1000));
        iRet = select(comport->fd + 1, &stReadFds, 0, &stExcpFds, &stTime);
        if (0 == iRet)
        {
            retval = 0;         // No data in Com port buffer
            goto CleanUp;
        }
        else if (0 < iRet)
        {
            if (0 != FD_ISSET(comport->fd, &stExcpFds))
            {
                retval = -6;  // Error during checking recv status
                COM_PRINT("Error checking recv status.\n");
                goto CleanUp;
            }
            if (0 == FD_ISSET(comport->fd, &stReadFds))
            {
                retval = 0;  // No incoming data
                COM_PRINT("No incoming data.\n");
                goto CleanUp;
            }
        }
        else
        {
            if (EINTR == errno)
            {
                COM_PRINT("catch interrupt signal.\n");
                retval = 0;  // Interrupted signal catched
            }
            else
            {
                COM_PRINT("Check recv status failure.\n");
                retval = -7;  // Error during checking recv status
            }
            goto CleanUp;
        }
    }
    usleep(10000); /* sleep for 10ms for data incoming */
    // Get data from Com port
    iRet = read(comport->fd, buf, buf_size);
    if (0 > iRet)
    {
        if (EINTR == errno)
            retval = 0;      // Interrupted signal catched
        else
            retval = -3;      // Failed to read Com port
        goto CleanUp;
    }
#if 0
    {
        int   i=0;
        printf("Receive %d bytes data: \n", iRet);
        for(i=0; i<iRet; i++)
        {
            printf("0x%02x ", buf[i]);
        }
        printf("\n");
    }
#endif
    retval = iRet;
  CleanUp:
    return retval;
}
int comport_send(st_comport * comport, char *buf, int send_bytes)
{
    char *ptr, *end;
    int retval = 0;
    int send = 0;
    if (NULL == buf || 0 >= send_bytes)
    {
        COM_PRINT("%s() Usage error.\n", __FUNCTION__);
        retval = -1;
        goto CleanUp;
    }
    if ( comport->fd < 0 )    // Comport not opened ?
    {
        retval = -3;
        COM_PRINT("Serail not connected.\n");
        goto CleanUp;
    }
    //printf("Send %s with %d bytes.\n", buf, send_bytes);
    // Large data, then slice them and send
    if (comport->frag_size < send_bytes)
    {
        ptr = buf;
        end = buf + send_bytes;
        do
        {
            // Large than frag_size
            if (comport->frag_size < (end - ptr))
            {
                send = write(comport->fd, ptr, comport->frag_size);
                if (0 >= send || comport->frag_size != send)
                {
                    retval = -4;
                    goto CleanUp;
                }
                ptr += comport->frag_size;
            }
            else                // Less than frag_size, maybe last fragmention.
            {
                send = write(comport->fd, ptr, (end - ptr));
                if (0 >= send || (end - ptr) != send)
                {
                    retval = -4;
                    goto CleanUp;
                }
                ptr += (end - ptr);
            }
        }
        while (ptr < end);
    }
    else                        // The send data is not large than a fragmention.
    {
        send = write(comport->fd, buf, send_bytes);
        if (0 >= send || send_bytes != send)
        {
            retval = -5;
            goto CleanUp;
        }
    }
  CleanUp:
    return retval;
}
mqttd/lylib/comport.h
New file
@@ -0,0 +1,106 @@
/*********************************************************************************
 *      Copyright:  (C) 2018 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  comport.h
 *    Description:  This head file is for the common TTY/Serial port operator library
 *
 *        Version:  1.0.0(10/17/2018~)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "10/17/2018 03:33:25 PM"
 *
 ********************************************************************************/
#ifndef  __COMPORT_H_
#define  __COMPORT_H_
#include  <stdio.h>
#include  <stdlib.h>
#include  <unistd.h>
#include  <string.h>
#include  <getopt.h>
#include  <fcntl.h>
#include  <errno.h>
#include  <termios.h>
#include  <sys/stat.h>
#include  <sys/wait.h>
#include  <sys/types.h>
#include  <sys/stat.h>
#include  <sys/select.h>
#define BUF_64  64
#ifndef DEVNAME_LEN
#define DEVNAME_LEN          64
#endif
//#define COM_DEBUG
#ifdef  COM_DEBUG
#define COM_PRINT(format,args...) printf(format, ##args)
#else
#define COM_PRINT(format,args...) do{} while(0);
#endif
//#define msleep(m)               {struct timespec cSleep; cSleep.tv_sec = 0; cSleep.tv_nsec = m * 1000; nanosleep(&cSleep, 0);}
typedef struct _st_comport
{
    char           dev_name[DEVNAME_LEN];
    unsigned char  databit, parity, stopbit, flowctrl;
    long           baudrate;
    int            fd;
    int            frag_size;
} st_comport;
/*
 *  description: initialise the comport structure
 *
 *   input args: $dev_name:  The comport device name path, such as '/dev/ttyS3'
 *               $baudrate:  The baudrate, such as 115200
 *               $settings:  The databit,parity,stopbit,flowctrl settings, such as '8N1N'
 *
 * return value: The st_comport structure pointer, NULL means failure.
 */
st_comport *comport_init(const char *dev_name, int baudrate, const char *settings);
/*
 *  description: Open the comport specified by $comport
 *   input args: $comport:  corresponding comport point
 * return value: The comport opened file description, <0 means failure
 */
extern int  comport_open(st_comport * comport);
/*
 *  description: read data from $comport in $timeout <ms> to $buf no more than $buf_size bytes
 * return value: the actual read data bytes, <0: read failure
 */
extern int  comport_recv(st_comport * comport, char *buf, int buf_size, unsigned long timeout);
/*
 *  description: write $send_bytes bytes data from $buf to $comport
 * return value: 0: write ok  <0: write failure
 */
extern int  comport_send(st_comport * comport, char *buf, int send_bytes);
/*
 *  description: display current comport settings such as databit,parity,stopbit,flowctrl
 *   input args: $comport:  corresponding comport point
 */
//extern void disp_settings(st_comport * comport);
/*
 *  description: close comport
 *   input args: $comport:  corresponding comport point
 */
extern void comport_close(st_comport * comport);
/*
 *  description: terminat comport, close and free it
 *   input args: $comport:  corresponding comport point
 */
extern void comport_term(st_comport * comport);
#endif
mqttd/lylib/ini_dictionary.c
New file
@@ -0,0 +1,398 @@
/*-------------------------------------------------------------------------*/
/**
   @file    ini_dictionary.c
   @author  N. Devillard
   @brief   Implements a dictionary for string variables.
   This module implements a simple dictionary object, i.e. a list
   of string/string associations. This object is useful to store e.g.
   informations retrieved from a configuration file (ini files).
*/
/*--------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
                                Includes
 ---------------------------------------------------------------------------*/
#include "ini_dictionary.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/** Maximum value size for integers and doubles. */
#define MAXVALSZ    1024
/** Minimal allocated number of entries in a dictionary */
#define DICTMINSZ   128
/** Invalid key token */
#define DICT_INVALID_KEY    ((char*)-1)
/*---------------------------------------------------------------------------
                            Private functions
 ---------------------------------------------------------------------------*/
/* Doubles the allocated size associated to a pointer */
/* 'size' is the current allocated size. */
static void * mem_double(void * ptr, int size)
{
    void * newptr ;
    newptr = calloc(2*size, 1);
    if (newptr==NULL) {
        return NULL ;
    }
    memcpy(newptr, ptr, size);
    free(ptr);
    return newptr ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Duplicate a string
  @param    s String to duplicate
  @return   Pointer to a newly allocated string, to be freed with free()
  This is a replacement for strdup(). This implementation is provided
  for systems that do not have it.
 */
/*--------------------------------------------------------------------------*/
static char * xstrdup(const char * s)
{
    char * t ;
    if (!s)
        return NULL ;
    t = (char*)malloc(strlen(s)+1) ;
    if (t) {
        strcpy(t,s);
    }
    return t ;
}
/*---------------------------------------------------------------------------
                            Function codes
 ---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
  @brief    Compute the hash key for a string.
  @param    key     Character string to use for key.
  @return   1 unsigned int on at least 32 bits.
  This hash function has been taken from an Article in Dr Dobbs Journal.
  This is normally a collision-free function, distributing keys evenly.
  The key is stored anyway in the struct so that collision can be avoided
  by comparing the key itself in last resort.
 */
/*--------------------------------------------------------------------------*/
unsigned dictionary_hash(const char * key)
{
    int         len ;
    unsigned    hash ;
    int         i ;
    len = strlen(key);
    for (hash=0, i=0 ; i<len ; i++) {
        hash += (unsigned)key[i] ;
        hash += (hash<<10);
        hash ^= (hash>>6) ;
    }
    hash += (hash <<3);
    hash ^= (hash >>11);
    hash += (hash <<15);
    return hash ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Create a new dictionary object.
  @param    size    Optional initial size of the dictionary.
  @return   1 newly allocated dictionary objet.
  This function allocates a new dictionary object of given size and returns
  it. If you do not know in advance (roughly) the number of entries in the
  dictionary, give size=0.
 */
/*--------------------------------------------------------------------------*/
dictionary * dictionary_new(int size)
{
    dictionary  *   d ;
    /* If no size was specified, allocate space for DICTMINSZ */
    if (size<DICTMINSZ) size=DICTMINSZ ;
    if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
        return NULL;
    }
    d->size = size ;
    d->val  = (char **)calloc(size, sizeof(char*));
    d->key  = (char **)calloc(size, sizeof(char*));
    d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
    return d ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Delete a dictionary object
  @param    d   dictionary object to deallocate.
  @return   void
  Deallocate a dictionary object and all memory associated to it.
 */
/*--------------------------------------------------------------------------*/
void dictionary_del(dictionary * d)
{
    int     i ;
    if (d==NULL) return ;
    for (i=0 ; i<d->size ; i++) {
        if (d->key[i]!=NULL)
            free(d->key[i]);
        if (d->val[i]!=NULL)
            free(d->val[i]);
    }
    free(d->val);
    free(d->key);
    free(d->hash);
    free(d);
    return ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Get a value from a dictionary.
  @param    d       dictionary object to search.
  @param    key     Key to look for in the dictionary.
  @param    def     Default value to return if key not found.
  @return   1 pointer to internally allocated character string.
  This function locates a key in a dictionary and returns a pointer to its
  value, or the passed 'def' pointer if no such key can be found in
  dictionary. The returned character pointer points to data internal to the
  dictionary object, you should not try to free it or modify it.
 */
/*--------------------------------------------------------------------------*/
char * dictionary_get(dictionary * d, const char * key, char * def)
{
    unsigned    hash ;
    int         i ;
    hash = dictionary_hash(key);
    for (i=0 ; i<d->size ; i++) {
        if (d->key[i]==NULL)
            continue ;
        /* Compare hash */
        if (hash==d->hash[i]) {
            /* Compare string, to avoid hash collisions */
            if (!strcmp(key, d->key[i])) {
                return d->val[i] ;
            }
        }
    }
    return def ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Set a value in a dictionary.
  @param    d       dictionary object to modify.
  @param    key     Key to modify or add.
  @param    val     Value to add.
  @return   int     0 if Ok, anything else otherwise
  If the given key is found in the dictionary, the associated value is
  replaced by the provided one. If the key cannot be found in the
  dictionary, it is added to it.
  It is Ok to provide a NULL value for val, but NULL values for the dictionary
  or the key are considered as errors: the function will return immediately
  in such a case.
  Notice that if you dictionary_set a variable to NULL, a call to
  dictionary_get will return a NULL value: the variable will be found, and
  its value (NULL) is returned. In other words, setting the variable
  content to NULL is equivalent to deleting the variable from the
  dictionary. It is not possible (in this implementation) to have a key in
  the dictionary without value.
  This function returns non-zero in case of failure.
 */
/*--------------------------------------------------------------------------*/
int dictionary_set(dictionary * d, const char * key, const char * val)
{
    int         i ;
    unsigned    hash ;
    if (d==NULL || key==NULL) return -1 ;
    /* Compute hash for this key */
    hash = dictionary_hash(key) ;
    /* Find if value is already in dictionary */
    if (d->n>0) {
        for (i=0 ; i<d->size ; i++) {
            if (d->key[i]==NULL)
                continue ;
            if (hash==d->hash[i]) { /* Same hash value */
                if (!strcmp(key, d->key[i])) {   /* Same key */
                    /* Found a value: modify and return */
                    if (d->val[i]!=NULL)
                        free(d->val[i]);
                    d->val[i] = val ? xstrdup(val) : NULL ;
                    /* Value has been modified: return */
                    return 0 ;
                }
            }
        }
    }
    /* Add a new value */
    /* See if dictionary needs to grow */
    if (d->n==d->size) {
        /* Reached maximum size: reallocate dictionary */
        d->val  = (char **)mem_double(d->val,  d->size * sizeof(char*)) ;
        d->key  = (char **)mem_double(d->key,  d->size * sizeof(char*)) ;
        d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
        if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) {
            /* Cannot grow dictionary */
            return -1 ;
        }
        /* Double size */
        d->size *= 2 ;
    }
    /* Insert key in the first empty slot. Start at d->n and wrap at
       d->size. Because d->n < d->size this will necessarily
       terminate. */
    for (i=d->n ; d->key[i] ; ) {
        if(++i == d->size) i = 0;
    }
    /* Copy key */
    d->key[i]  = xstrdup(key);
    d->val[i]  = val ? xstrdup(val) : NULL ;
    d->hash[i] = hash;
    d->n ++ ;
    return 0 ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Delete a key in a dictionary
  @param    d       dictionary object to modify.
  @param    key     Key to remove.
  @return   void
  This function deletes a key in a dictionary. Nothing is done if the
  key cannot be found.
 */
/*--------------------------------------------------------------------------*/
void dictionary_unset(dictionary * d, const char * key)
{
    unsigned    hash ;
    int         i ;
    if (key == NULL) {
        return;
    }
    hash = dictionary_hash(key);
    for (i=0 ; i<d->size ; i++) {
        if (d->key[i]==NULL)
            continue ;
        /* Compare hash */
        if (hash==d->hash[i]) {
            /* Compare string, to avoid hash collisions */
            if (!strcmp(key, d->key[i])) {
                /* Found key */
                break ;
            }
        }
    }
    if (i>=d->size)
        /* Key not found */
        return ;
    free(d->key[i]);
    d->key[i] = NULL ;
    if (d->val[i]!=NULL) {
        free(d->val[i]);
        d->val[i] = NULL ;
    }
    d->hash[i] = 0 ;
    d->n -- ;
    return ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Dump a dictionary to an opened file pointer.
  @param    d   Dictionary to dump
  @param    f   Opened file pointer.
  @return   void
  Dumps a dictionary onto an opened file pointer. Key pairs are printed out
  as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
  output file pointers.
 */
/*--------------------------------------------------------------------------*/
void dictionary_dump(dictionary * d, FILE * out)
{
    int     i ;
    if (d==NULL || out==NULL) return ;
    if (d->n<1) {
        fprintf(out, "empty dictionary\n");
        return ;
    }
    for (i=0 ; i<d->size ; i++) {
        if (d->key[i]) {
            fprintf(out, "%20s\t[%s]\n",
                    d->key[i],
                    d->val[i] ? d->val[i] : "UNDEF");
        }
    }
    return ;
}
/* Test code */
#ifdef TESTDIC
#define NVALS 20000
int main(int argc, char *argv[])
{
    dictionary  *   d ;
    char    *   val ;
    int         i ;
    char        cval[90] ;
    /* Allocate dictionary */
    printf("allocating...\n");
    d = dictionary_new(0);
    /* Set values in dictionary */
    printf("setting %d values...\n", NVALS);
    for (i=0 ; i<NVALS ; i++) {
        sprintf(cval, "%04d", i);
        dictionary_set(d, cval, "salut");
    }
    printf("getting %d values...\n", NVALS);
    for (i=0 ; i<NVALS ; i++) {
        sprintf(cval, "%04d", i);
        val = dictionary_get(d, cval, DICT_INVALID_KEY);
        if (val==DICT_INVALID_KEY) {
            printf("cannot get value for key [%s]\n", cval);
        }
    }
    printf("unsetting %d values...\n", NVALS);
    for (i=0 ; i<NVALS ; i++) {
        sprintf(cval, "%04d", i);
        dictionary_unset(d, cval);
    }
    if (d->n != 0) {
        printf("error deleting values\n");
    }
    printf("deallocating...\n");
    dictionary_del(d);
    return 0 ;
}
#endif
/* vim: set ts=4 et sw=4 tw=75 */
mqttd/lylib/ini_dictionary.h
New file
@@ -0,0 +1,165 @@
/*-------------------------------------------------------------------------*/
/**
   @file    ini_dictionary.h
   @author  N. Devillard
   @brief   Implements a dictionary for string variables.
   This module implements a simple dictionary object, i.e. a list
   of string/string associations. This object is useful to store e.g.
   informations retrieved from a configuration file (ini files).
*/
/*--------------------------------------------------------------------------*/
#ifndef _INI_DICTIONARY_H_
#define _INI_DICTIONARY_H_
/*---------------------------------------------------------------------------
                                Includes
 ---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/*---------------------------------------------------------------------------
                                New types
 ---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
  @brief    Dictionary object
  This object contains a list of string/string associations. Each
  association is identified by a unique string key. Looking up values
  in the dictionary is speeded up by the use of a (hopefully collision-free)
  hash function.
 */
/*-------------------------------------------------------------------------*/
typedef struct _dictionary_ {
    int             n ;     /** Number of entries in dictionary */
    int             size ;  /** Storage size */
    char        **  val ;   /** List of string values */
    char        **  key ;   /** List of string keys */
    unsigned     *  hash ;  /** List of hash values for keys */
} dictionary ;
/*---------------------------------------------------------------------------
                            Function prototypes
 ---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
  @brief    Compute the hash key for a string.
  @param    key     Character string to use for key.
  @return   1 unsigned int on at least 32 bits.
  This hash function has been taken from an Article in Dr Dobbs Journal.
  This is normally a collision-free function, distributing keys evenly.
  The key is stored anyway in the struct so that collision can be avoided
  by comparing the key itself in last resort.
 */
/*--------------------------------------------------------------------------*/
unsigned dictionary_hash(const char * key);
/*-------------------------------------------------------------------------*/
/**
  @brief    Create a new dictionary object.
  @param    size    Optional initial size of the dictionary.
  @return   1 newly allocated dictionary objet.
  This function allocates a new dictionary object of given size and returns
  it. If you do not know in advance (roughly) the number of entries in the
  dictionary, give size=0.
 */
/*--------------------------------------------------------------------------*/
dictionary * dictionary_new(int size);
/*-------------------------------------------------------------------------*/
/**
  @brief    Delete a dictionary object
  @param    d   dictionary object to deallocate.
  @return   void
  Deallocate a dictionary object and all memory associated to it.
 */
/*--------------------------------------------------------------------------*/
void dictionary_del(dictionary * vd);
/*-------------------------------------------------------------------------*/
/**
  @brief    Get a value from a dictionary.
  @param    d       dictionary object to search.
  @param    key     Key to look for in the dictionary.
  @param    def     Default value to return if key not found.
  @return   1 pointer to internally allocated character string.
  This function locates a key in a dictionary and returns a pointer to its
  value, or the passed 'def' pointer if no such key can be found in
  dictionary. The returned character pointer points to data internal to the
  dictionary object, you should not try to free it or modify it.
 */
/*--------------------------------------------------------------------------*/
char * dictionary_get(dictionary * d, const char * key, char * def);
/*-------------------------------------------------------------------------*/
/**
  @brief    Set a value in a dictionary.
  @param    d       dictionary object to modify.
  @param    key     Key to modify or add.
  @param    val     Value to add.
  @return   int     0 if Ok, anything else otherwise
  If the given key is found in the dictionary, the associated value is
  replaced by the provided one. If the key cannot be found in the
  dictionary, it is added to it.
  It is Ok to provide a NULL value for val, but NULL values for the dictionary
  or the key are considered as errors: the function will return immediately
  in such a case.
  Notice that if you dictionary_set a variable to NULL, a call to
  dictionary_get will return a NULL value: the variable will be found, and
  its value (NULL) is returned. In other words, setting the variable
  content to NULL is equivalent to deleting the variable from the
  dictionary. It is not possible (in this implementation) to have a key in
  the dictionary without value.
  This function returns non-zero in case of failure.
 */
/*--------------------------------------------------------------------------*/
int dictionary_set(dictionary * vd, const char * key, const char * val);
/*-------------------------------------------------------------------------*/
/**
  @brief    Delete a key in a dictionary
  @param    d       dictionary object to modify.
  @param    key     Key to remove.
  @return   void
  This function deletes a key in a dictionary. Nothing is done if the
  key cannot be found.
 */
/*--------------------------------------------------------------------------*/
void dictionary_unset(dictionary * d, const char * key);
/*-------------------------------------------------------------------------*/
/**
  @brief    Dump a dictionary to an opened file pointer.
  @param    d   Dictionary to dump
  @param    f   Opened file pointer.
  @return   void
  Dumps a dictionary onto an opened file pointer. Key pairs are printed out
  as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
  output file pointers.
 */
/*--------------------------------------------------------------------------*/
void dictionary_dump(dictionary * d, FILE * out);
#endif
mqttd/lylib/iniparser.c
New file
@@ -0,0 +1,807 @@
/*-------------------------------------------------------------------------*/
/**
   @file    iniparser.c
   @author  N. Devillard
   @brief   Parser for ini files.
*/
/*--------------------------------------------------------------------------*/
/*---------------------------- Includes ------------------------------------*/
#include <ctype.h>
#include "iniparser.h"
/*---------------------------- Defines -------------------------------------*/
#define ASCIILINESZ         (1024)
#define INI_INVALID_KEY     ((char*)-1)
/*---------------------------------------------------------------------------
                        Private to this module
 ---------------------------------------------------------------------------*/
/**
 * This enum stores the status for each parsed line (internal use only).
 */
typedef enum _line_status_ {
    LINE_UNPROCESSED,
    LINE_ERROR,
    LINE_EMPTY,
    LINE_COMMENT,
    LINE_SECTION,
    LINE_VALUE
} line_status ;
/*-------------------------------------------------------------------------*/
/**
  @brief    Convert a string to lowercase.
  @param    s   String to convert.
  @return   ptr to statically allocated string.
  This function returns a pointer to a statically allocated string
  containing a lowercased version of the input string. Do not free
  or modify the returned string! Since the returned string is statically
  allocated, it will be modified at each function call (not re-entrant).
 */
/*--------------------------------------------------------------------------*/
static char * strlwc(const char * s)
{
    static char l[ASCIILINESZ+1];
    int i ;
    if (s==NULL) return NULL ;
    memset(l, 0, ASCIILINESZ+1);
    i=0 ;
    while (s[i] && i<ASCIILINESZ) {
        l[i] = (char)tolower((int)s[i]);
        i++ ;
    }
    l[ASCIILINESZ]=(char)0;
    return l ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Remove blanks at the beginning and the end of a string.
  @param    s   String to parse.
  @return   ptr to statically allocated string.
  This function returns a pointer to a statically allocated string,
  which is identical to the input string, except that all blank
  characters at the end and the beg. of the string have been removed.
  Do not free or modify the returned string! Since the returned string
  is statically allocated, it will be modified at each function call
  (not re-entrant).
 */
/*--------------------------------------------------------------------------*/
static char * strstrip(const char * s)
{
    static char l[ASCIILINESZ+1];
    char * last ;
    if (s==NULL) return NULL ;
    while (isspace((int)*s) && *s) s++;
    memset(l, 0, ASCIILINESZ+1);
    strcpy(l, s);
    last = l + strlen(l);
    while (last > l) {
        if (!isspace((int)*(last-1)))
            break ;
        last -- ;
    }
    *last = (char)0;
    return (char*)l ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Get number of sections in a dictionary
  @param    d   Dictionary to examine
  @return   int Number of sections found in dictionary
  This function returns the number of sections found in a dictionary.
  The test to recognize sections is done on the string stored in the
  dictionary: a section name is given as "section" whereas a key is
  stored as "section:key", thus the test looks for entries that do not
  contain a colon.
  This clearly fails in the case a section name contains a colon, but
  this should simply be avoided.
  This function returns -1 in case of error.
 */
/*--------------------------------------------------------------------------*/
int iniparser_getnsec(dictionary * d)
{
    int i ;
    int nsec ;
    if (d==NULL) return -1 ;
    nsec=0 ;
    for (i=0 ; i<d->size ; i++) {
        if (d->key[i]==NULL)
            continue ;
        if (strchr(d->key[i], ':')==NULL) {
            nsec ++ ;
        }
    }
    return nsec ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Get name for section n in a dictionary.
  @param    d   Dictionary to examine
  @param    n   Section number (from 0 to nsec-1).
  @return   Pointer to char string
  This function locates the n-th section in a dictionary and returns
  its name as a pointer to a string statically allocated inside the
  dictionary. Do not free or modify the returned string!
  This function returns NULL in case of error.
 */
/*--------------------------------------------------------------------------*/
char * iniparser_getsecname(dictionary * d, int n)
{
    int i ;
    int foundsec ;
    if (d==NULL || n<0) return NULL ;
    foundsec=0 ;
    for (i=0 ; i<d->size ; i++) {
        if (d->key[i]==NULL)
            continue ;
        if (strchr(d->key[i], ':')==NULL) {
            foundsec++ ;
            if (foundsec>n)
                break ;
        }
    }
    if (foundsec<=n) {
        return NULL ;
    }
    return d->key[i] ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Dump a dictionary to an opened file pointer.
  @param    d   Dictionary to dump.
  @param    f   Opened file pointer to dump to.
  @return   void
  This function prints out the contents of a dictionary, one element by
  line, onto the provided file pointer. It is OK to specify @c stderr
  or @c stdout as output files. This function is meant for debugging
  purposes mostly.
 */
/*--------------------------------------------------------------------------*/
void iniparser_dump(dictionary * d, FILE * f)
{
    int     i ;
    if (d==NULL || f==NULL) return ;
    for (i=0 ; i<d->size ; i++) {
        if (d->key[i]==NULL)
            continue ;
        if (d->val[i]!=NULL) {
            fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
        } else {
            fprintf(f, "[%s]=UNDEF\n", d->key[i]);
        }
    }
    return ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Save a dictionary to a loadable ini file
  @param    d   Dictionary to dump
  @param    f   Opened file pointer to dump to
  @return   void
  This function dumps a given dictionary into a loadable ini file.
  It is Ok to specify @c stderr or @c stdout as output files.
 */
/*--------------------------------------------------------------------------*/
void iniparser_dump_ini(dictionary * d, FILE * f)
{
    int     i ;
    int     nsec ;
    char *  secname ;
    if (d==NULL || f==NULL) return ;
    nsec = iniparser_getnsec(d);
    if (nsec<1) {
        /* No section in file: dump all keys as they are */
        for (i=0 ; i<d->size ; i++) {
            if (d->key[i]==NULL)
                continue ;
            fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
        }
        return ;
    }
    for (i=0 ; i<nsec ; i++) {
        secname = iniparser_getsecname(d, i) ;
        iniparser_dumpsection_ini(d, secname, f) ;
    }
    fprintf(f, "\n");
    return ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Save a dictionary section to a loadable ini file
  @param    d   Dictionary to dump
  @param    s   Section name of dictionary to dump
  @param    f   Opened file pointer to dump to
  @return   void
  This function dumps a given section of a given dictionary into a loadable ini
  file.  It is Ok to specify @c stderr or @c stdout as output files.
 */
/*--------------------------------------------------------------------------*/
void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f)
{
    int     j ;
    char    keym[ASCIILINESZ+1];
    int     seclen ;
    if (d==NULL || f==NULL) return ;
    if (! iniparser_find_entry(d, s)) return ;
    seclen  = (int)strlen(s);
    fprintf(f, "\n[%s]\n", s);
    sprintf(keym, "%s:", s);
    for (j=0 ; j<d->size ; j++) {
        if (d->key[j]==NULL)
            continue ;
        if (!strncmp(d->key[j], keym, seclen+1)) {
            fprintf(f,
                    "%-30s = %s\n",
                    d->key[j]+seclen+1,
                    d->val[j] ? d->val[j] : "");
        }
    }
    fprintf(f, "\n");
    return ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the number of keys in a section of a dictionary.
  @param    d   Dictionary to examine
  @param    s   Section name of dictionary to examine
  @return   Number of keys in section
 */
/*--------------------------------------------------------------------------*/
int iniparser_getsecnkeys(dictionary * d, char * s)
{
    int     seclen, nkeys ;
    char    keym[ASCIILINESZ+1];
    int j ;
    nkeys = 0;
    if (d==NULL) return nkeys;
    if (! iniparser_find_entry(d, s)) return nkeys;
    seclen  = (int)strlen(s);
    sprintf(keym, "%s:", s);
    for (j=0 ; j<d->size ; j++) {
        if (d->key[j]==NULL)
            continue ;
        if (!strncmp(d->key[j], keym, seclen+1))
            nkeys++;
    }
    return nkeys;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the number of keys in a section of a dictionary.
  @param    d   Dictionary to examine
  @param    s   Section name of dictionary to examine
  @return   pointer to statically allocated character strings
  This function queries a dictionary and finds all keys in a given section.
  Each pointer in the returned char pointer-to-pointer is pointing to
  a string allocated in the dictionary; do not free or modify them.
  This function returns NULL in case of error.
 */
/*--------------------------------------------------------------------------*/
char ** iniparser_getseckeys(dictionary * d, char * s)
{
    char **keys;
    int i, j ;
    char    keym[ASCIILINESZ+1];
    int     seclen, nkeys ;
    keys = NULL;
    if (d==NULL) return keys;
    if (! iniparser_find_entry(d, s)) return keys;
    nkeys = iniparser_getsecnkeys(d, s);
    keys = (char**) malloc(nkeys*sizeof(char*));
    seclen  = (int)strlen(s);
    sprintf(keym, "%s:", s);
    i = 0;
    for (j=0 ; j<d->size ; j++) {
        if (d->key[j]==NULL)
            continue ;
        if (!strncmp(d->key[j], keym, seclen+1)) {
            keys[i] = d->key[j];
            i++;
        }
    }
    return keys;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key
  @param    d       Dictionary to search
  @param    key     Key string to look for
  @param    def     Default value to return if key not found.
  @return   pointer to statically allocated character string
  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the pointer passed as 'def' is returned.
  The returned char pointer is pointing to a string allocated in
  the dictionary, do not free or modify it.
 */
/*--------------------------------------------------------------------------*/
char * iniparser_getstring(dictionary * d, const char * key, char * def)
{
    char * lc_key ;
    char * sval ;
    if (d==NULL || key==NULL)
        return def ;
    lc_key = strlwc(key);
    sval = dictionary_get(d, lc_key, def);
    return sval ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key, convert to an int
  @param    d Dictionary to search
  @param    key Key string to look for
  @param    notfound Value to return in case of error
  @return   integer
  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the notfound value is returned.
  Supported values for integers include the usual C notation
  so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
  are supported. Examples:
  "42"      ->  42
  "042"     ->  34 (octal -> decimal)
  "0x42"    ->  66 (hexa  -> decimal)
  Warning: the conversion may overflow in various ways. Conversion is
  totally outsourced to strtol(), see the associated man page for overflow
  handling.
  Credits: Thanks to A. Becker for suggesting strtol()
 */
/*--------------------------------------------------------------------------*/
int iniparser_getint(dictionary * d, const char * key, int notfound)
{
    char    *   str ;
    str = iniparser_getstring(d, key, INI_INVALID_KEY);
    if (str==INI_INVALID_KEY) return notfound ;
    return (int)strtol(str, NULL, 0);
}
int iniparser_getlong(dictionary * d, const char * key, int notfound)
{
    char    *   str ;
    str = iniparser_getstring(d, key, INI_INVALID_KEY);
    if (str==INI_INVALID_KEY) return notfound ;
    return strtol(str, NULL, 0);
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key, convert to a double
  @param    d Dictionary to search
  @param    key Key string to look for
  @param    notfound Value to return in case of error
  @return   double
  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the notfound value is returned.
 */
/*--------------------------------------------------------------------------*/
double iniparser_getdouble(dictionary * d, const char * key, double notfound)
{
    char    *   str ;
    str = iniparser_getstring(d, key, INI_INVALID_KEY);
    if (str==INI_INVALID_KEY) return notfound ;
    return atof(str);
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key, convert to a boolean
  @param    d Dictionary to search
  @param    key Key string to look for
  @param    notfound Value to return in case of error
  @return   integer
  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the notfound value is returned.
  A true boolean is found if one of the following is matched:
  - A string starting with 'y'
  - A string starting with 'Y'
  - A string starting with 't'
  - A string starting with 'T'
  - A string starting with '1'
  A false boolean is found if one of the following is matched:
  - A string starting with 'n'
  - A string starting with 'N'
  - A string starting with 'f'
  - A string starting with 'F'
  - A string starting with '0'
  The notfound value returned if no boolean is identified, does not
  necessarily have to be 0 or 1.
 */
/*--------------------------------------------------------------------------*/
int iniparser_getboolean(dictionary * d, const char * key, int notfound)
{
    char    *   c ;
    int         ret ;
    c = iniparser_getstring(d, key, INI_INVALID_KEY);
    if (c==INI_INVALID_KEY) return notfound ;
    if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
        ret = 1 ;
    } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
        ret = 0 ;
    } else {
        ret = notfound ;
    }
    return ret;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Finds out if a given entry exists in a dictionary
  @param    ini     Dictionary to search
  @param    entry   Name of the entry to look for
  @return   integer 1 if entry exists, 0 otherwise
  Finds out if a given entry exists in the dictionary. Since sections
  are stored as keys with NULL associated values, this is the only way
  of querying for the presence of sections in a dictionary.
 */
/*--------------------------------------------------------------------------*/
int iniparser_find_entry(
    dictionary  *   ini,
    const char  *   entry
)
{
    int found=0 ;
    if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
        found = 1 ;
    }
    return found ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Set an entry in a dictionary.
  @param    ini     Dictionary to modify.
  @param    entry   Entry to modify (entry name)
  @param    val     New value to associate to the entry.
  @return   int 0 if Ok, -1 otherwise.
  If the given entry can be found in the dictionary, it is modified to
  contain the provided value. If it cannot be found, -1 is returned.
  It is Ok to set val to NULL.
 */
/*--------------------------------------------------------------------------*/
int iniparser_set(dictionary * ini, const char * entry, const char * val)
{
    return dictionary_set(ini, strlwc(entry), val) ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Delete an entry in a dictionary
  @param    ini     Dictionary to modify
  @param    entry   Entry to delete (entry name)
  @return   void
  If the given entry can be found, it is deleted from the dictionary.
 */
/*--------------------------------------------------------------------------*/
void iniparser_unset(dictionary * ini, const char * entry)
{
    dictionary_unset(ini, strlwc(entry));
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Load a single line from an INI file
  @param    input_line  Input line, may be concatenated multi-line input
  @param    section     Output space to store section
  @param    key         Output space to store key
  @param    value       Output space to store value
  @return   line_status value
 */
/*--------------------------------------------------------------------------*/
static line_status iniparser_line(
    char * input_line,
    char * section,
    char * key,
    char * value)
{
    line_status sta ;
    char        line[ASCIILINESZ+1];
    static char left_line[ASCIILINESZ+1];
    int         len, offset ;
    strcpy(line, strstrip(input_line));
    len = (int)strlen(line);
    sta = LINE_UNPROCESSED ;
    if (len<1) {
        /* Empty line */
        sta = LINE_EMPTY ;
        memset(input_line, 0, len);
    } else if (line[0]=='#' || line[0]==';') {
        /* Comment line */
        sta = LINE_COMMENT ;
        memset(input_line, 0, len);
    } else if (line[0]=='[') {
        /* Section name */
        sscanf(line, "[%[^]]", section);
        strcpy(section, strstrip(section));
        strcpy(section, strlwc(section));
        /* Left configure will go to next time to parser */
        offset = strlen(section) + 2;
        strcpy( left_line, strstrip(&(line[offset])) );
        strcpy( left_line, strstrip(left_line));
        if( strlen(left_line) > 0)
        {
            strcpy(input_line, left_line);
            strcat(input_line, "\n");
        }
        else
        {
            memset(input_line, 0, len);
        }
        sta = LINE_SECTION ;
    } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
           ||  sscanf (line, "%[^=] = '%[^\']'",   key, value) == 2
           ||  sscanf (line, "%[^=] = %[^;#]",     key, value) == 2) {
        char      *ptr = NULL;
        /* Usual key=value, with or without comments */
        strcpy(key, strstrip(key));
        strcpy(key, strlwc(key));
        strcpy(value, strstrip(value));
        /*
         * sscanf cannot handle '' or "" as empty values
         * this is done here
         */
        if (!strncmp(value, "\"\"", 2) || (!strncmp(value, "''", 2)) ) {
            value[0]=0 ;
        }
        ptr = strchr(line, '=');
        if('\''==*(ptr+1) || '\"'==*(ptr+1))
        {
            offset = strlen(key)+strlen(value) + 1 + 2; /* Skip $key='$val' */
        }
        else
        {
            offset = strlen(key)+strlen(value) + 1; /* Skip $key=$val */
        }
        strcpy( left_line, strstrip(&(line[offset])) );
        if( strlen(left_line) > 0)
        {
            strcpy(input_line, left_line);
            strcat(input_line, "\n");
        }
        else
        {
            memset(input_line, 0, len);
        }
        sta = LINE_VALUE ;
    } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
           ||  sscanf(line, "%[^=] %[=]", key, value) == 2) {
        /*
         * Special cases:
         * key=
         * key=;
         * key=#
         */
        strcpy(key, strstrip(key));
        strcpy(key, strlwc(key));
        value[0]=0 ;
        sta = LINE_VALUE ;
    } else {
        /* Generate syntax error */
        sta = LINE_ERROR ;
        memset(input_line, 0, len);
    }
    return sta ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Parse an ini file and return an allocated dictionary object
  @param    ininame Name of the ini file to read.
  @return   Pointer to newly allocated dictionary
  This is the parser for ini files. This function is called, providing
  the name of the file to be read. It returns a dictionary object that
  should not be accessed directly, but through accessor functions
  instead.
  The returned dictionary must be freed using iniparser_freedict().
 */
/*--------------------------------------------------------------------------*/
dictionary * iniparser_load(const char * ininame)
{
    FILE * in ;
    char line    [ASCIILINESZ+1] ;
    char section [ASCIILINESZ+1] ;
    char key     [ASCIILINESZ+1] ;
    char tmp     [ASCIILINESZ+1] ;
    char val     [ASCIILINESZ+1] ;
    int  last=0 ;
    int  len ;
    int  lineno=0 ;
    int  errs=0;
    dictionary * dict ;
    if ((in=fopen(ininame, "r"))==NULL) {
        fprintf(stderr, "iniparser: cannot open %s\n", ininame);
        return NULL ;
    }
    dict = dictionary_new(0) ;
    if (!dict) {
        fclose(in);
        return NULL ;
    }
    memset(line,    0, ASCIILINESZ);
    memset(section, 0, ASCIILINESZ);
    memset(key,     0, ASCIILINESZ);
    memset(val,     0, ASCIILINESZ);
    last=0 ;
    while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
        lineno++ ;
CONTINUE_PARSER:
        len = (int)strlen(line)-1;
        if (len==0)
            continue;
        /* Safety check against buffer overflows */
        if (line[len]!='\n') {
            fprintf(stderr,
                    "iniparser: input line too long in %s (%d)\n",
                    ininame,
                    lineno);
            dictionary_del(dict);
            fclose(in);
            return NULL ;
        }
        /* Get rid of \n and spaces at end of line */
        while ((len>=0) &&
                ((line[len]=='\n') || (isspace(line[len])))) {
            line[len]=0 ;
            len-- ;
        }
        /* Detect multi-line */
        if (line[len]=='\\') {
            /* Multi-line value */
            last=len ;
            continue ;
        } else {
            last=0 ;
        }
        switch ( iniparser_line(line, section, key, val) ) {
            case LINE_EMPTY:
            case LINE_COMMENT:
            break ;
            case LINE_SECTION:
            errs = dictionary_set(dict, section, NULL);
            break ;
            case LINE_VALUE:
            sprintf(tmp, "%s:%s", section, key);
            errs = dictionary_set(dict, tmp, val) ;
            break ;
            case LINE_ERROR:
            fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
                    ininame,
                    lineno);
            fprintf(stderr, "-> %s\n", line);
            errs++ ;
            break;
            default:
            break ;
        }
        if( strlen(line) > 0)
        {
            goto CONTINUE_PARSER;
        }
        memset(line, 0, ASCIILINESZ);
        last=0;
        if (errs<0) {
            fprintf(stderr, "iniparser: memory allocation failure\n");
            break ;
        }
    }
    if (errs) {
        dictionary_del(dict);
        dict = NULL ;
    }
    fclose(in);
    return dict ;
}
/*-------------------------------------------------------------------------*/
/**
  @brief    Free all memory associated to an ini dictionary
  @param    d Dictionary to free
  @return   void
  Free all memory associated to an ini dictionary.
  It is mandatory to call this function before the dictionary object
  gets out of the current context.
 */
/*--------------------------------------------------------------------------*/
void iniparser_freedict(dictionary * d)
{
    dictionary_del(d);
}
/* vim: set ts=4 et sw=4 tw=75 */
mqttd/lylib/iniparser.h
New file
@@ -0,0 +1,308 @@
/*-------------------------------------------------------------------------*/
/**
   @file    cp_iniparser.h
   @author  N. Devillard
   @brief   Parser for ini files.
*/
/*--------------------------------------------------------------------------*/
#ifndef _INIPARSER_H_
#define _INIPARSER_H_
/*---------------------------------------------------------------------------
                                Includes
 ---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
 * The following #include is necessary on many Unixes but not Linux.
 * It is not needed for Windows platforms.
 * Uncomment it if needed.
 */
/* #include <unistd.h> */
#include "ini_dictionary.h"
/*-------------------------------------------------------------------------*/
/**
  @brief    Get number of sections in a dictionary
  @param    d   Dictionary to examine
  @return   int Number of sections found in dictionary
  This function returns the number of sections found in a dictionary.
  The test to recognize sections is done on the string stored in the
  dictionary: a section name is given as "section" whereas a key is
  stored as "section:key", thus the test looks for entries that do not
  contain a colon.
  This clearly fails in the case a section name contains a colon, but
  this should simply be avoided.
  This function returns -1 in case of error.
 */
/*--------------------------------------------------------------------------*/
int iniparser_getnsec(dictionary * d);
/*-------------------------------------------------------------------------*/
/**
  @brief    Get name for section n in a dictionary.
  @param    d   Dictionary to examine
  @param    n   Section number (from 0 to nsec-1).
  @return   Pointer to char string
  This function locates the n-th section in a dictionary and returns
  its name as a pointer to a string statically allocated inside the
  dictionary. Do not free or modify the returned string!
  This function returns NULL in case of error.
 */
/*--------------------------------------------------------------------------*/
char * iniparser_getsecname(dictionary * d, int n);
/*-------------------------------------------------------------------------*/
/**
  @brief    Save a dictionary to a loadable ini file
  @param    d   Dictionary to dump
  @param    f   Opened file pointer to dump to
  @return   void
  This function dumps a given dictionary into a loadable ini file.
  It is Ok to specify @c stderr or @c stdout as output files.
 */
/*--------------------------------------------------------------------------*/
void iniparser_dump_ini(dictionary * d, FILE * f);
/*-------------------------------------------------------------------------*/
/**
  @brief    Save a dictionary section to a loadable ini file
  @param    d   Dictionary to dump
  @param    s   Section name of dictionary to dump
  @param    f   Opened file pointer to dump to
  @return   void
  This function dumps a given section of a given dictionary into a loadable ini
  file.  It is Ok to specify @c stderr or @c stdout as output files.
 */
/*--------------------------------------------------------------------------*/
void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f);
/*-------------------------------------------------------------------------*/
/**
  @brief    Dump a dictionary to an opened file pointer.
  @param    d   Dictionary to dump.
  @param    f   Opened file pointer to dump to.
  @return   void
  This function prints out the contents of a dictionary, one element by
  line, onto the provided file pointer. It is OK to specify @c stderr
  or @c stdout as output files. This function is meant for debugging
  purposes mostly.
 */
/*--------------------------------------------------------------------------*/
void iniparser_dump(dictionary * d, FILE * f);
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the number of keys in a section of a dictionary.
  @param    d   Dictionary to examine
  @param    s   Section name of dictionary to examine
  @return   Number of keys in section
 */
/*--------------------------------------------------------------------------*/
int iniparser_getsecnkeys(dictionary * d, char * s);
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the number of keys in a section of a dictionary.
  @param    d   Dictionary to examine
  @param    s   Section name of dictionary to examine
  @return   pointer to statically allocated character strings
  This function queries a dictionary and finds all keys in a given section.
  Each pointer in the returned char pointer-to-pointer is pointing to
  a string allocated in the dictionary; do not free or modify them.
  This function returns NULL in case of error.
 */
/*--------------------------------------------------------------------------*/
char ** iniparser_getseckeys(dictionary * d, char * s);
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key
  @param    d       Dictionary to search
  @param    key     Key string to look for
  @param    def     Default value to return if key not found.
  @return   pointer to statically allocated character string
  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the pointer passed as 'def' is returned.
  The returned char pointer is pointing to a string allocated in
  the dictionary, do not free or modify it.
 */
/*--------------------------------------------------------------------------*/
char * iniparser_getstring(dictionary * d, const char * key, char * def);
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key, convert to an int
  @param    d Dictionary to search
  @param    key Key string to look for
  @param    notfound Value to return in case of error
  @return   integer
  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the notfound value is returned.
  Supported values for integers include the usual C notation
  so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
  are supported. Examples:
  - "42"      ->  42
  - "042"     ->  34 (octal -> decimal)
  - "0x42"    ->  66 (hexa  -> decimal)
  Warning: the conversion may overflow in various ways. Conversion is
  totally outsourced to strtol(), see the associated man page for overflow
  handling.
  Credits: Thanks to A. Becker for suggesting strtol()
 */
/*--------------------------------------------------------------------------*/
int iniparser_getint(dictionary * d, const char * key, int notfound);
int iniparser_getlong(dictionary * d, const char * key, int notfound);
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key, convert to a double
  @param    d Dictionary to search
  @param    key Key string to look for
  @param    notfound Value to return in case of error
  @return   double
  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the notfound value is returned.
 */
/*--------------------------------------------------------------------------*/
double iniparser_getdouble(dictionary * d, const char * key, double notfound);
/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key, convert to a boolean
  @param    d Dictionary to search
  @param    key Key string to look for
  @param    notfound Value to return in case of error
  @return   integer
  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the notfound value is returned.
  A true boolean is found if one of the following is matched:
  - A string starting with 'y'
  - A string starting with 'Y'
  - A string starting with 't'
  - A string starting with 'T'
  - A string starting with '1'
  A false boolean is found if one of the following is matched:
  - A string starting with 'n'
  - A string starting with 'N'
  - A string starting with 'f'
  - A string starting with 'F'
  - A string starting with '0'
  The notfound value returned if no boolean is identified, does not
  necessarily have to be 0 or 1.
 */
/*--------------------------------------------------------------------------*/
int iniparser_getboolean(dictionary * d, const char * key, int notfound);
/*-------------------------------------------------------------------------*/
/**
  @brief    Set an entry in a dictionary.
  @param    ini     Dictionary to modify.
  @param    entry   Entry to modify (entry name)
  @param    val     New value to associate to the entry.
  @return   int 0 if Ok, -1 otherwise.
  If the given entry can be found in the dictionary, it is modified to
  contain the provided value. If it cannot be found, -1 is returned.
  It is Ok to set val to NULL.
 */
/*--------------------------------------------------------------------------*/
int iniparser_set(dictionary * ini, const char * entry, const char * val);
/*-------------------------------------------------------------------------*/
/**
  @brief    Delete an entry in a dictionary
  @param    ini     Dictionary to modify
  @param    entry   Entry to delete (entry name)
  @return   void
  If the given entry can be found, it is deleted from the dictionary.
 */
/*--------------------------------------------------------------------------*/
void iniparser_unset(dictionary * ini, const char * entry);
/*-------------------------------------------------------------------------*/
/**
  @brief    Finds out if a given entry exists in a dictionary
  @param    ini     Dictionary to search
  @param    entry   Name of the entry to look for
  @return   integer 1 if entry exists, 0 otherwise
  Finds out if a given entry exists in the dictionary. Since sections
  are stored as keys with NULL associated values, this is the only way
  of querying for the presence of sections in a dictionary.
 */
/*--------------------------------------------------------------------------*/
int iniparser_find_entry(dictionary * ini, const char * entry) ;
/*-------------------------------------------------------------------------*/
/**
  @brief    Parse an ini file and return an allocated dictionary object
  @param    ininame Name of the ini file to read.
  @return   Pointer to newly allocated dictionary
  This is the parser for ini files. This function is called, providing
  the name of the file to be read. It returns a dictionary object that
  should not be accessed directly, but through accessor functions
  instead.
  The returned dictionary must be freed using iniparser_freedict().
 */
/*--------------------------------------------------------------------------*/
dictionary * iniparser_load(const char * ininame);
/*-------------------------------------------------------------------------*/
/**
  @brief    Free all memory associated to an ini dictionary
  @param    d Dictionary to free
  @return   void
  Free all memory associated to an ini dictionary.
  It is mandatory to call this function before the dictionary object
  gets out of the current context.
 */
/*--------------------------------------------------------------------------*/
void iniparser_freedict(dictionary * d);
#endif
mqttd/lylib/klist.h
New file
@@ -0,0 +1,723 @@
/*********************************************************************************
 *      Copyright:  (C) 2012 Guo Wenxue <guowenxue@gmail.com>
 *                  All rights reserved.
 *
 *       Filename:  cp_list.h
 *    Description:  This file is copied from Linux kernel, which provide link list API.
 *
 *        Version:  1.0.0(08/09/2012~)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "08/09/2012 02:24:34 AM"
 *
 ********************************************************************************/
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
#include <linux/stddef.h>
/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:    the pointer to the member.
 * @type:   the type of the container struct this is embedded in.
 * @member: the name of the member within the struct.
 *
 */
#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({          \
    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    (type *)( (char *)__mptr - offsetof(type,member) );})
/*
 * Architectures might want to move the poison pointer offset
 * into some well-recognized area such as 0xdead000000000000,
 * that is also not mappable by user-space exploits:
 */
#ifdef CONFIG_ILLEGAL_POINTER_VALUE
# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL)
#else
# define POISON_POINTER_DELTA 0
#endif
/*
 * These are non-NULL pointers that will result in page faults
 * under normal circumstances, used to verify that nobody uses
 * non-initialized list entries.
 */
#define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)
#define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA)
#ifndef ARCH_HAS_PREFETCH
#define ARCH_HAS_PREFETCH
static inline void prefetch(const void *x) {;}
#endif
/*
 * Simple doubly linked list implementation.
 *
 * Some of the internal functions ("__xxx") are useful when
 * manipulating whole lists rather than single entries, as
 * sometimes we already know the next/prev entries and we can
 * generate better code by using them directly rather than
 * using the generic single-entry routines.
 */
struct list_head {
    struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
    struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
    list->next = list;
    list->prev = list;
}
/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_add(struct list_head *new,
                  struct list_head *prev,
                  struct list_head *next)
{
    next->prev = new;
    new->next = next;
    new->prev = prev;
    prev->next = new;
}
/**
 * list_add - add a new entry
 * @new: new entry to be added
 * @head: list head to add it after
 *
 * Insert a new entry after the specified head.
 * This is good for implementing stacks.
 */
static inline void list_add(struct list_head *new, struct list_head *head)
{
    __list_add(new, head, head->next);
}
/**
 * list_add_tail - add a new entry
 * @new: new entry to be added
 * @head: list head to add it before
 *
 * Insert a new entry before the specified head.
 * This is useful for implementing queues.
 */
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
    __list_add(new, head->prev, head);
}
/*
 * Delete a list entry by making the prev/next entries
 * point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
    next->prev = prev;
    prev->next = next;
}
/**
 * list_del - deletes entry from list.
 * @entry: the element to delete from the list.
 * Note: list_empty() on entry does not return true after this, the entry is
 * in an undefined state.
 */
static inline void list_del(struct list_head *entry)
{
    __list_del(entry->prev, entry->next);
    entry->next = LIST_POISON1;
    entry->prev = LIST_POISON2;
}
/**
 * list_replace - replace old entry by new one
 * @old : the element to be replaced
 * @new : the new element to insert
 *
 * If @old was empty, it will be overwritten.
 */
static inline void list_replace(struct list_head *old,
                struct list_head *new)
{
    new->next = old->next;
    new->next->prev = new;
    new->prev = old->prev;
    new->prev->next = new;
}
static inline void list_replace_init(struct list_head *old,
                    struct list_head *new)
{
    list_replace(old, new);
    INIT_LIST_HEAD(old);
}
/**
 * list_del_init - deletes entry from list and reinitialize it.
 * @entry: the element to delete from the list.
 */
static inline void list_del_init(struct list_head *entry)
{
    __list_del(entry->prev, entry->next);
    INIT_LIST_HEAD(entry);
}
/**
 * list_move - delete from one list and add as another's head
 * @list: the entry to move
 * @head: the head that will precede our entry
 */
static inline void list_move(struct list_head *list, struct list_head *head)
{
    __list_del(list->prev, list->next);
    list_add(list, head);
}
/**
 * list_move_tail - delete from one list and add as another's tail
 * @list: the entry to move
 * @head: the head that will follow our entry
 */
static inline void list_move_tail(struct list_head *list,
                  struct list_head *head)
{
    __list_del(list->prev, list->next);
    list_add_tail(list, head);
}
/**
 * list_is_last - tests whether @list is the last entry in list @head
 * @list: the entry to test
 * @head: the head of the list
 */
static inline int list_is_last(const struct list_head *list,
                const struct list_head *head)
{
    return list->next == head;
}
/**
 * list_empty - tests whether a list is empty
 * @head: the list to test.
 */
static inline int list_empty(const struct list_head *head)
{
    return head->next == head;
}
/**
 * list_empty_careful - tests whether a list is empty and not being modified
 * @head: the list to test
 *
 * Description:
 * tests whether a list is empty _and_ checks that no other CPU might be
 * in the process of modifying either member (next or prev)
 *
 * NOTE: using list_empty_careful() without synchronization
 * can only be safe if the only activity that can happen
 * to the list entry is list_del_init(). Eg. it cannot be used
 * if another CPU could re-list_add() it.
 */
static inline int list_empty_careful(const struct list_head *head)
{
    struct list_head *next = head->next;
    return (next == head) && (next == head->prev);
}
/**
 * list_is_singular - tests whether a list has just one entry.
 * @head: the list to test.
 */
static inline int list_is_singular(const struct list_head *head)
{
    return !list_empty(head) && (head->next == head->prev);
}
static inline void __list_cut_position(struct list_head *list,
        struct list_head *head, struct list_head *entry)
{
    struct list_head *new_first = entry->next;
    list->next = head->next;
    list->next->prev = list;
    list->prev = entry;
    entry->next = list;
    head->next = new_first;
    new_first->prev = head;
}
/**
 * list_cut_position - cut a list into two
 * @list: a new list to add all removed entries
 * @head: a list with entries
 * @entry: an entry within head, could be the head itself
 *    and if so we won't cut the list
 *
 * This helper moves the initial part of @head, up to and
 * including @entry, from @head to @list. You should
 * pass on @entry an element you know is on @head. @list
 * should be an empty list or a list you do not care about
 * losing its data.
 *
 */
static inline void list_cut_position(struct list_head *list,
        struct list_head *head, struct list_head *entry)
{
    if (list_empty(head))
        return;
    if (list_is_singular(head) &&
        (head->next != entry && head != entry))
        return;
    if (entry == head)
        INIT_LIST_HEAD(list);
    else
        __list_cut_position(list, head, entry);
}
static inline void __list_splice(const struct list_head *list,
                 struct list_head *prev,
                 struct list_head *next)
{
    struct list_head *first = list->next;
    struct list_head *last = list->prev;
    first->prev = prev;
    prev->next = first;
    last->next = next;
    next->prev = last;
}
/**
 * list_splice - join two lists, this is designed for stacks
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 */
static inline void list_splice(const struct list_head *list,
                struct list_head *head)
{
    if (!list_empty(list))
        __list_splice(list, head, head->next);
}
/**
 * list_splice_tail - join two lists, each list being a queue
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 */
static inline void list_splice_tail(struct list_head *list,
                struct list_head *head)
{
    if (!list_empty(list))
        __list_splice(list, head->prev, head);
}
/**
 * list_splice_init - join two lists and reinitialise the emptied list.
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 *
 * The list at @list is reinitialised
 */
static inline void list_splice_init(struct list_head *list,
                    struct list_head *head)
{
    if (!list_empty(list)) {
        __list_splice(list, head, head->next);
        INIT_LIST_HEAD(list);
    }
}
/**
 * list_splice_tail_init - join two lists and reinitialise the emptied list
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 *
 * Each of the lists is a queue.
 * The list at @list is reinitialised
 */
static inline void list_splice_tail_init(struct list_head *list,
                     struct list_head *head)
{
    if (!list_empty(list)) {
        __list_splice(list, head->prev, head);
        INIT_LIST_HEAD(list);
    }
}
/**
 * list_entry - get the struct for this entry
 * @ptr:    the &struct list_head pointer.
 * @type:    the type of the struct this is embedded in.
 * @member:    the name of the list_struct within the struct.
 */
#define list_entry(ptr, type, member) \
    container_of(ptr, type, member)
/**
 * list_first_entry - get the first element from a list
 * @ptr:    the list head to take the element from.
 * @type:    the type of the struct this is embedded in.
 * @member:    the name of the list_struct within the struct.
 *
 * Note, that list is expected to be not empty.
 */
#define list_first_entry(ptr, type, member) \
    list_entry((ptr)->next, type, member)
/**
 * list_for_each    -    iterate over a list
 * @pos:    the &struct list_head to use as a loop cursor.
 * @head:    the head for your list.
 */
#define list_for_each(pos, head) \
    for (pos = (head)->next; prefetch(pos->next), pos != (head); \
        pos = pos->next)
/**
 * __list_for_each    -    iterate over a list
 * @pos:    the &struct list_head to use as a loop cursor.
 * @head:    the head for your list.
 *
 * This variant differs from list_for_each() in that it's the
 * simplest possible list iteration code, no prefetching is done.
 * Use this for code that knows the list to be very short (empty
 * or 1 entry) most of the time.
 */
#define __list_for_each(pos, head) \
    for (pos = (head)->next; pos != (head); pos = pos->next)
/**
 * list_for_each_prev    -    iterate over a list backwards
 * @pos:    the &struct list_head to use as a loop cursor.
 * @head:    the head for your list.
 */
#define list_for_each_prev(pos, head) \
    for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
        pos = pos->prev)
/**
 * list_for_each_safe - iterate over a list safe against removal of list entry
 * @pos:    the &struct list_head to use as a loop cursor.
 * @n:        another &struct list_head to use as temporary storage
 * @head:    the head for your list.
 */
#define list_for_each_safe(pos, n, head) \
    for (pos = (head)->next, n = pos->next; pos != (head); \
        pos = n, n = pos->next)
/**
 * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
 * @pos:    the &struct list_head to use as a loop cursor.
 * @n:        another &struct list_head to use as temporary storage
 * @head:    the head for your list.
 */
#define list_for_each_prev_safe(pos, n, head) \
    for (pos = (head)->prev, n = pos->prev; \
         prefetch(pos->prev), pos != (head); \
         pos = n, n = pos->prev)
/**
 * list_for_each_entry    -    iterate over list of given type
 * @pos:    the type * to use as a loop cursor.
 * @head:    the head for your list.
 * @member:    the name of the list_struct within the struct.
 */
#define list_for_each_entry(pos, head, member)                \
    for (pos = list_entry((head)->next, typeof(*pos), member);    \
         prefetch(pos->member.next), &pos->member != (head);    \
         pos = list_entry(pos->member.next, typeof(*pos), member))
/**
 * list_for_each_entry_reverse - iterate backwards over list of given type.
 * @pos:    the type * to use as a loop cursor.
 * @head:    the head for your list.
 * @member:    the name of the list_struct within the struct.
 */
#define list_for_each_entry_reverse(pos, head, member)            \
    for (pos = list_entry((head)->prev, typeof(*pos), member);    \
         prefetch(pos->member.prev), &pos->member != (head);    \
         pos = list_entry(pos->member.prev, typeof(*pos), member))
/**
 * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
 * @pos:    the type * to use as a start point
 * @head:    the head of the list
 * @member:    the name of the list_struct within the struct.
 *
 * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
 */
#define list_prepare_entry(pos, head, member) \
    ((pos) ? : list_entry(head, typeof(*pos), member))
/**
 * list_for_each_entry_continue - continue iteration over list of given type
 * @pos:    the type * to use as a loop cursor.
 * @head:    the head for your list.
 * @member:    the name of the list_struct within the struct.
 *
 * Continue to iterate over list of given type, continuing after
 * the current position.
 */
#define list_for_each_entry_continue(pos, head, member)         \
    for (pos = list_entry(pos->member.next, typeof(*pos), member);    \
         prefetch(pos->member.next), &pos->member != (head);    \
         pos = list_entry(pos->member.next, typeof(*pos), member))
/**
 * list_for_each_entry_continue_reverse - iterate backwards from the given point
 * @pos:    the type * to use as a loop cursor.
 * @head:    the head for your list.
 * @member:    the name of the list_struct within the struct.
 *
 * Start to iterate over list of given type backwards, continuing after
 * the current position.
 */
#define list_for_each_entry_continue_reverse(pos, head, member)        \
    for (pos = list_entry(pos->member.prev, typeof(*pos), member);    \
         prefetch(pos->member.prev), &pos->member != (head);    \
         pos = list_entry(pos->member.prev, typeof(*pos), member))
/**
 * list_for_each_entry_from - iterate over list of given type from the current point
 * @pos:    the type * to use as a loop cursor.
 * @head:    the head for your list.
 * @member:    the name of the list_struct within the struct.
 *
 * Iterate over list of given type, continuing from current position.
 */
#define list_for_each_entry_from(pos, head, member)            \
    for (; prefetch(pos->member.next), &pos->member != (head);    \
         pos = list_entry(pos->member.next, typeof(*pos), member))
/**
 * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
 * @pos:    the type * to use as a loop cursor.
 * @n:        another type * to use as temporary storage
 * @head:    the head for your list.
 * @member:    the name of the list_struct within the struct.
 */
#define list_for_each_entry_safe(pos, n, head, member)            \
    for (pos = list_entry((head)->next, typeof(*pos), member),    \
        n = list_entry(pos->member.next, typeof(*pos), member);    \
         &pos->member != (head);                    \
         pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
 * list_for_each_entry_safe_continue
 * @pos:    the type * to use as a loop cursor.
 * @n:        another type * to use as temporary storage
 * @head:    the head for your list.
 * @member:    the name of the list_struct within the struct.
 *
 * Iterate over list of given type, continuing after current point,
 * safe against removal of list entry.
 */
#define list_for_each_entry_safe_continue(pos, n, head, member)         \
    for (pos = list_entry(pos->member.next, typeof(*pos), member),        \
        n = list_entry(pos->member.next, typeof(*pos), member);        \
         &pos->member != (head);                        \
         pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
 * list_for_each_entry_safe_from
 * @pos:    the type * to use as a loop cursor.
 * @n:        another type * to use as temporary storage
 * @head:    the head for your list.
 * @member:    the name of the list_struct within the struct.
 *
 * Iterate over list of given type from current point, safe against
 * removal of list entry.
 */
#define list_for_each_entry_safe_from(pos, n, head, member)            \
    for (n = list_entry(pos->member.next, typeof(*pos), member);        \
         &pos->member != (head);                        \
         pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
 * list_for_each_entry_safe_reverse
 * @pos:    the type * to use as a loop cursor.
 * @n:        another type * to use as temporary storage
 * @head:    the head for your list.
 * @member:    the name of the list_struct within the struct.
 *
 * Iterate backwards over list of given type, safe against removal
 * of list entry.
 */
#define list_for_each_entry_safe_reverse(pos, n, head, member)        \
    for (pos = list_entry((head)->prev, typeof(*pos), member),    \
        n = list_entry(pos->member.prev, typeof(*pos), member);    \
         &pos->member != (head);                    \
         pos = n, n = list_entry(n->member.prev, typeof(*n), member))
/*
 * Double linked lists with a single pointer list head.
 * Mostly useful for hash tables where the two pointer list head is
 * too wasteful.
 * You lose the ability to access the tail in O(1).
 */
struct hlist_head {
    struct hlist_node *first;
};
struct hlist_node {
    struct hlist_node *next, **pprev;
};
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
    h->next = NULL;
    h->pprev = NULL;
}
static inline int hlist_unhashed(const struct hlist_node *h)
{
    return !h->pprev;
}
static inline int hlist_empty(const struct hlist_head *h)
{
    return !h->first;
}
static inline void __hlist_del(struct hlist_node *n)
{
    struct hlist_node *next = n->next;
    struct hlist_node **pprev = n->pprev;
    *pprev = next;
    if (next)
        next->pprev = pprev;
}
static inline void hlist_del(struct hlist_node *n)
{
    __hlist_del(n);
    n->next = LIST_POISON1;
    n->pprev = LIST_POISON2;
}
static inline void hlist_del_init(struct hlist_node *n)
{
    if (!hlist_unhashed(n)) {
        __hlist_del(n);
        INIT_HLIST_NODE(n);
    }
}
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
    struct hlist_node *first = h->first;
    n->next = first;
    if (first)
        first->pprev = &n->next;
    h->first = n;
    n->pprev = &h->first;
}
/* next must be != NULL */
static inline void hlist_add_before(struct hlist_node *n,
                    struct hlist_node *next)
{
    n->pprev = next->pprev;
    n->next = next;
    next->pprev = &n->next;
    *(n->pprev) = n;
}
static inline void hlist_add_after(struct hlist_node *n,
                    struct hlist_node *next)
{
    next->next = n->next;
    n->next = next;
    next->pprev = &n->next;
    if(next->next)
        next->next->pprev  = &next->next;
}
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_for_each(pos, head) \
    for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
         pos = pos->next)
#define hlist_for_each_safe(pos, n, head) \
    for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
         pos = n)
/**
 * hlist_for_each_entry    - iterate over list of given type
 * @tpos:    the type * to use as a loop cursor.
 * @pos:    the &struct hlist_node to use as a loop cursor.
 * @head:    the head for your list.
 * @member:    the name of the hlist_node within the struct.
 */
#define hlist_for_each_entry(tpos, pos, head, member)             \
    for (pos = (head)->first;                     \
         pos && ({ prefetch(pos->next); 1;}) &&             \
        ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
         pos = pos->next)
/**
 * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
 * @tpos:    the type * to use as a loop cursor.
 * @pos:    the &struct hlist_node to use as a loop cursor.
 * @member:    the name of the hlist_node within the struct.
 */
#define hlist_for_each_entry_continue(tpos, pos, member)         \
    for (pos = (pos)->next;                         \
         pos && ({ prefetch(pos->next); 1;}) &&             \
        ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
         pos = pos->next)
/**
 * hlist_for_each_entry_from - iterate over a hlist continuing from current point
 * @tpos:    the type * to use as a loop cursor.
 * @pos:    the &struct hlist_node to use as a loop cursor.
 * @member:    the name of the hlist_node within the struct.
 */
#define hlist_for_each_entry_from(tpos, pos, member)             \
    for (; pos && ({ prefetch(pos->next); 1;}) &&             \
        ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
         pos = pos->next)
/**
 * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
 * @tpos:    the type * to use as a loop cursor.
 * @pos:    the &struct hlist_node to use as a loop cursor.
 * @n:        another &struct hlist_node to use as temporary storage
 * @head:    the head for your list.
 * @member:    the name of the hlist_node within the struct.
 */
#define hlist_for_each_entry_safe(tpos, pos, n, head, member)         \
    for (pos = (head)->first;                     \
         pos && ({ n = pos->next; 1; }) &&                 \
        ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
         pos = n)
#endif
mqttd/lylib/logger.c
New file
@@ -0,0 +1,364 @@
/*********************************************************************************
 *      Copyright:  (C) 2018 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  logger.c
 *    Description:  This file is the linux infrastructural logger system library, which
 *                  is not thread safe.
 *
 *        Version:  1.0.0(08/08/2012~)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "08/08/2018 04:24:01 PM"
 *
 ********************************************************************************/
#include "logger.h"
#define PRECISE_TIME_FACTOR 1000
static unsigned long log_rollback_size = LOG_ROLLBACK_NONE;
static st_logger _g_logger;
static st_logger *g_logger = &_g_logger;
char *log_str[LOG_LEVEL_MAX + 1] = { "", "F", "E", "W", "N", "D", "I", "T", "M" };
static char *log_time_format = "%Y-%m-%d %H:%M:%S";
static void logger_default_signal_handler(int sig)
{
    if (sig == SIGHUP)
    {
        signal(SIGHUP, logger_default_signal_handler);
        log_fatal("SIGHUP received - reopenning log file [%s]", g_logger->file);
        logger_reopen();
    }
}
static void logger_banner(char *prefix)
{
    fprintf(g_logger->fp, "%s log \"%s\" on level [%s] size [%lu], log system version %s\n",
            prefix, g_logger->file, log_str[g_logger->level], log_rollback_size / 1024, LOG_VERSION_STR);
#if 0
#ifdef LOG_FILE_LINE
    fprintf(g_logger->fp, " [Date]    [Time]   [Level] [PID/TID] [File/Line]  [Content]\n");
#else
    fprintf(g_logger->fp, " [Date]    [Time]   [Level] [PID/TID] [Content]\n");
#endif
#endif
    fprintf(g_logger->fp, "-----------------------------------------------------------------------------\n");
}
static void check_and_rollback(void)
{
    if (log_rollback_size != LOG_ROLLBACK_NONE)
    {
        long _curOffset = ftell(g_logger->fp);
        if ((_curOffset != -1) && (_curOffset >= log_rollback_size))
        {
            char cmd[512];
            snprintf(cmd, sizeof(cmd), "cp -f %s %s.roll", g_logger->file, g_logger->file);
            system(cmd);
            if (-1 == fseek(g_logger->fp, 0L, SEEK_SET))
                fprintf(g_logger->fp, "log rollback fseek failed \n");
            rewind(g_logger->fp);
            truncate(g_logger->file, 0);
            logger_banner("Already rollback");
        }
    }
}
int logger_init(char *filename, int level, int log_size)
{
    struct sigaction act;
    if( !filename || strlen(filename)<=0 )
    {
        fprintf(stderr, "%s() invalid input arguments\n", __FUNCTION__);
        return -1;
    }
    memset(g_logger, 0, sizeof(st_logger));
    strncpy(g_logger->file, filename, FILENAME_LEN);
    g_logger->level = level;
    g_logger->size = log_size;
    log_rollback_size = g_logger->size <= 0 ? LOG_ROLLBACK_NONE : g_logger->size*1024;    /* Unit KiB */
    /* logger to console, just need point to standard error */
    if (!strcmp(g_logger->file, DBG_LOG_FILE))
    {
        g_logger->fp = stderr;
        log_rollback_size = LOG_ROLLBACK_NONE;
        g_logger->flag |= LOGGER_CONSOLE;
        goto OUT;
    }
    g_logger->fp = fopen(g_logger->file, "a+");
    if ( !g_logger->fp )
    {
        fprintf(stderr, "Open log file \"%s\" failure\n", g_logger->file);
        return -2;
    }
OUT:
    act.sa_handler = logger_default_signal_handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGHUP, &act, NULL);
    logger_banner("\nInitialize");
    return 0;
}
void logger_raw(const char *fmt, ...)
{
    va_list argp;
    if ( !g_logger->fp )
        return;
    check_and_rollback();
    va_start(argp, fmt);
    vfprintf(g_logger->fp, fmt, argp);
    va_end(argp);
}
void logger_term(void)
{
    if ( !g_logger->fp )
        return;
    logger_banner("\nTerminate");
    logger_raw("\n\n");
    fflush(g_logger->fp);
    fclose(g_logger->fp);
    g_logger->fp = NULL;
    memset(g_logger, 0, sizeof(*g_logger));
    return ;
}
int logger_reopen(void)
{
    int rc = 0;
    if (g_logger->flag & LOGGER_CONSOLE )
    {
        fflush(g_logger->fp);
        g_logger->fp = stderr;
        return 0;
    }
    if( g_logger->fp )
    {
        logger_banner("\nClose");
        fflush(g_logger->fp);
        g_logger->fp = fopen(g_logger->file, "a+");
        if ( !g_logger->fp )
            rc = -2;
    }
    else
    {
        rc = -3;
    }
    if (!rc)
    {
        logger_banner("\nReopen");
    }
    return rc;
}
static void logger_printout(char *level, char *fmt, va_list argp)
{
    char buf[MAX_LOG_MESSAGE_LEN];
    struct tm *local;
    struct timeval now;
    char timestr[256];
    pthread_t tid;
    check_and_rollback();
#ifdef MULTHREADS
    tid = pthread_self();
#else
    tid = getpid();
#endif
    gettimeofday(&now, NULL);
    local = localtime(&now.tv_sec);
    strftime(timestr, 256, log_time_format, local);
    vsnprintf(buf, MAX_LOG_MESSAGE_LEN, fmt, argp);
#ifdef DUMPLICATE_OUTPUT
    printf("%s.%03ld [%s] [%06lu]: %s",
           timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, buf);
#endif
    if (g_logger->fp)
        fprintf(g_logger->fp, "%s.%03ld [%s] [%06lu]: %s", timestr, now.tv_usec / PRECISE_TIME_FACTOR,
                level, tid, buf);
    if (g_logger->fp)
        fflush(g_logger->fp);
}
static void logger_printout_line(char *level, char *fmt, char *file, int line, va_list argp)
{
    char buf[MAX_LOG_MESSAGE_LEN];
    struct tm *local;
    struct timeval now;
    char timestr[256];
    pthread_t tid;
    check_and_rollback();
#ifdef MULTHREADS
    tid = pthread_self();
#else
    tid = getpid();
#endif
    gettimeofday(&now, NULL);
    local = localtime(&now.tv_sec);
    strftime(timestr, 256, log_time_format, local);
    vsnprintf(buf, MAX_LOG_MESSAGE_LEN, fmt, argp);
#ifdef DUMPLICATE_OUTPUT
    printf("%s.%03ld [%s] [%06lu] (%s [%04d]) : %s",
           timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, file, line, buf);
#endif
    if (g_logger->fp)
        fprintf(g_logger->fp, "%s.%03ld [%s] [%06lu] (%s [%04d]) : %s",
                timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, file, line, buf);
    if (g_logger->fp)
        fflush(g_logger->fp);
}
void logger_comm(int level, char *fmt, ...)
{
    va_list argp;
    if ( level > g_logger->level )
        return;
    va_start(argp, fmt);
    logger_printout(log_str[level], fmt, argp);
    va_end(argp);
}
void logger_line(int level, char *file, int line, char *fmt, ...)
{
    va_list argp;
    if ( level > g_logger->level )
        return;
    va_start(argp, fmt);
    logger_printout_line(log_str[level], fmt, file, line, argp);
    va_end(argp);
}
#define LINELEN 81
#define CHARS_PER_LINE 16
static char *print_char =
    "                "
    "                "
    " !\"#$%&'()*+,-./"
    "0123456789:;<=>?"
    "@ABCDEFGHIJKLMNO"
    "PQRSTUVWXYZ[\\]^_"
    "`abcdefghijklmno"
    "pqrstuvwxyz{|}~ "
    "                "
    "                "
    " ???????????????"
    "????????????????"
    "????????????????"
    "????????????????"
    "????????????????"
    "????????????????";
void logger_dump(int level, char *buf, int len)
{
    int rc;
    int idx;
    char prn[LINELEN];
    char lit[CHARS_PER_LINE + 2];
    char hc[4];
    short line_done = 1;
    if ( level > g_logger->level )
        return;
    rc = len;
    idx = 0;
    lit[CHARS_PER_LINE] = '\0';
    while (rc > 0)
    {
        if (line_done)
            snprintf(prn, LINELEN, "%08X: ", idx);
        do
        {
            unsigned char c = buf[idx];
            snprintf(hc, 4, "%02X ", c);
            strncat(prn, hc, LINELEN);
            lit[idx % CHARS_PER_LINE] = print_char[c];
        }
        while (--rc > 0 && (++idx % CHARS_PER_LINE != 0));
        line_done = (idx % CHARS_PER_LINE) == 0;
        if (line_done)
        {
#ifdef DUMPLICATE_OUTPUT
            printf("%s  %s\n", prn, lit);
#endif
            if (g_logger->fp)
                fprintf(g_logger->fp, "%s  %s\n", prn, lit);
        }
    }
    if (!line_done)
    {
        int ldx = idx % CHARS_PER_LINE;
        lit[ldx++] = print_char[(int)buf[idx]];
        lit[ldx] = '\0';
        while ((++idx % CHARS_PER_LINE) != 0)
            strncat(prn, "   ", LINELEN);
#ifdef DUMPLICATE_OUTPUT
        printf("%s  %s\n", prn, lit);
#endif
        if (g_logger->fp)
            fprintf(g_logger->fp, "%s  %s\n", prn, lit);
    }
}
mqttd/lylib/logger.h
New file
@@ -0,0 +1,104 @@
/********************************************************************************
 *      Copyright:  (C) 2018 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  logger.h
 *    Description:  This file is the linux infrastructural logger system library
 *
 *        Version:  1.0.0(08/08/2018~)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "08/08/2018 05:16:56 PM"
 *
 ********************************************************************************/
#ifndef __LOGGER_H_
#define __LOGGER_H_
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/time.h>
#define LOG_VERSION_STR             "2.0.0"
#ifndef FILENAME_LEN
#define FILENAME_LEN                64
#endif
#define DEFAULT_LOGFILE             "logger.log"
#define DBG_LOG_FILE                "console"  /*  Debug mode log file is console */
#define LOG_ROLLBACK_SIZE           512    /* Default rollback log size  */
#define LOG_ROLLBACK_NONE           0      /* Set rollback size to 0 will not rollback  */
#define MAX_LOG_MESSAGE_LEN         0x1000
//#define DUMPLICATE_OUTPUT  /* Log to file and printf on console  */
#define LOG_FILE_LINE      /* Log the file and line */
enum
{
    LOG_LEVEL_DISB = 0,               /*  Disable "Debug" */
    LOG_LEVEL_FATAL,                  /*  Debug Level "Fatal" */
    LOG_LEVEL_ERROR,                  /*  Debug Level "ERROR" */
    LOG_LEVEL_WARN,                   /*  Debug Level "warnning" */
    LOG_LEVEL_NRML,                   /*  Debug Level "Normal" */
    LOG_LEVEL_DEBUG,                  /*  Debug Level "Debug" */
    LOG_LEVEL_INFO,                   /*  Debug Level "Information" */
    LOG_LEVEL_TRACE,                  /*  Debug Level "Trace" */
    LOG_LEVEL_MAX,
};
#define LOGGER_CONSOLE             1<<1
#define LOGGER_FILE                0<<1
#define LOGGER_LEVEL_OPT           1<<2 /*  The log level is sepcified by the command option */
typedef struct _st_logger
{
    unsigned char      flag;  /* This logger pointer is malloc() or passed by argument */
    char               file[FILENAME_LEN];
    int                level;
    int                size;
    FILE               *fp;
} st_logger;
extern int  logger_init(char *filename, int level, int log_size);
extern int  logger_reopen(void);
extern void logger_term(void);
extern void logger_comm(int level, char *fmt, ...);
extern void logger_line(int level, char *file, int line, char *fmt, ...);
extern void logger_dump(int level, char *buf, int len);
#ifdef LOG_FILE_LINE
#define log_trace(fmt, ...) logger_line(LOG_LEVEL_TRACE, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define log_info(fmt, ...)  logger_line(LOG_LEVEL_INFO,  __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define log_dbg(fmt, ...)   logger_line(LOG_LEVEL_DEBUG, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define log_nrml(fmt, ...)  logger_line(LOG_LEVEL_NRML,  __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define log_warn(fmt, ...)  logger_line(LOG_LEVEL_WARN,  __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define log_err(fmt, ...)   logger_line(LOG_LEVEL_ERROR, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define log_fatal(fmt, ...) logger_line(LOG_LEVEL_FATAL, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#else
#define log_trace(fmt, ...) logger_comm(LOG_LEVEL_TRACE, fmt, ##__VA_ARGS__)
#define log_info(fmt, ...)  logger_comm(tLOG_LEVEL_INFO,  fmt, ##__VA_ARGS__)
#define log_dbg(fmt, ...)   logger_comm(LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__)
#define log_nrml(fmt, ...)  logger_comm(LOG_LEVEL_NRML,  fmt, ##__VA_ARGS__)
#define log_warn(fmt, ...)  logger_comm(LOG_LEVEL_WARN,  fmt, ##__VA_ARGS__)
#define log_err(fmt, ...)   logger_comm(LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__)
#define log_fatal(fmt, ...) logger_comm(LOG_LEVEL_FATAL, fmt, ##__VA_ARGS__)
#endif
#endif /* __LOGGER_H_ */
mqttd/lylib/makefile
File was renamed from mqttd/cJSON/makefile
@@ -1,10 +1,14 @@
PWD=$(shell pwd )
LIBNAME=$(shell basename ${PWD} )
PROJPATH=$(shell dirname ${PWD} )
CFLAGS+=-I${PROJPATH}
all: clean
    @rm -f *.o
    @${CROSS_COMPILE}gcc -c *.c
    @${CROSS_COMPILE}gcc ${CFLAGS} -c *.c
    ${CROSS_COMPILE}ar -rcs  lib${LIBNAME}.a *.o
clean:
mqttd/main.c
@@ -14,11 +14,8 @@
#include <time.h>
#include <unistd.h>
#include "led.h"
#include "ds18b20.h"
#include "sht20.h"
int hal_init(void);
#include "logger.h"
#include "hal.h"
/********************************************************************************
 *  Description:
@@ -31,62 +28,30 @@
    float              temp;
    float              rh;
    if( hal_init() < 0 )
    //if( logger_init("mqttd.log", LOG_LEVEL_DEBUG, 1024) < 0 )
    if( logger_init(DBG_LOG_FILE, LOG_LEVEL_DEBUG, 1024) < 0 )
    {
        printf("Initialise hardware failure\n");
        fprintf(stderr, "Logger system initialise failure\n");
        return -1;
    }
    while(1)
    log_dbg("Logger system initialise ok\n");
#if 0
    if( hal_init() < 0 )
    {
        turn_led(LED_R, ON);
        sleep(1);
        turn_led(LED_R, OFF);
        sleep(1);
        turn_led(LED_G, ON);
        sleep(1);
        turn_led(LED_G, OFF);
        sleep(1);
        turn_led(LED_B, ON);
        sleep(1);
        turn_led(LED_B, OFF);
        sleep(1);
        if(sht2x_get_temp_humidity(&temp, &rh) < 0)
        {
            printf("SHT2X get temperature and relative humidity failure\n");
        }
        else
        {
            printf("SHT2X Temperature=%lfC, Relative humidity=%lf%% \n", temp, rh);
        }
        if( ds18b20_get_temperature(&temp) < 0)
        {
            printf("DS18B20 get temperature failure\n");
        }
        else
        {
            printf("DS18B20 get temperature=%lf ℃ \n", temp);
        }
        log_err("Initialise hardware failure\n");
        return -1;
    }
#endif
    log_nrml("HAL initialise ok\n");
    logger_term();
    return 0;
} /* ----- End of main() ----- */
int hal_init(void)
{
    init_led();
    if( sht2x_init() < 0 )
    {
        printf("Initialise SHT20 failure\n");
        return -2;
    }
    return 0;
}
mqttd/makefile
@@ -37,8 +37,8 @@
export CFLAGS
export LDFLAGS
CFLAGS+=-Ihal -IcJSON
LDFLAGS+=-L hal -lhal -LcJSON -lcJSON
CFLAGS+=-Ihal -Ilylib
LDFLAGS+=-L hal -lhal -Llylib -llylib
SRCFILES = $(wildcard *.c)
IMAGE_NAME=$(shell basename ${PWD})
@@ -52,7 +52,7 @@
modules:
    make -C hal
    make -C cJSON
    make -C lylib
    cd ${MQTT_LIBPATH} && bash build.sh
binary:  ${SRCFILES}
@@ -68,7 +68,7 @@
clean: 
    @make clean -C hal
    @make clean -C cJSON
    @make clean -C lylib
    @rm -f version.h 
    @rm -f *.o $(IMAGE_NAME) 
    @rm -rf *.gdb *.a *.so *.elf*