code hierarchy refactoring

This commit is contained in:
2020-02-05 09:41:22 +04:00
parent c21c623be4
commit 3c7105eb97
35 changed files with 145 additions and 113 deletions
+76
View File
@@ -0,0 +1,76 @@
/*
* allocator.cpp
*
* Created on: Jan 28, 2020
* Author: nnosov
*/
#include "../src/utils/allocator.h"
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include "common.h"
void heap_free(pst_allocator* alloc, void* buff)
{
pthread_mutex_lock(&alloc->lock);
alloc->size -= malloc_usable_size(buff);
pthread_mutex_unlock(&alloc->lock);
free(buff);
}
void* heap_alloc(pst_allocator* alloc, uint32_t size)
{
void* buff = malloc(size);
pthread_mutex_lock(&alloc->lock);
alloc->size += malloc_usable_size(buff);
pthread_mutex_unlock(&alloc->lock);
return buff;
}
void* heap_realloc(pst_allocator* alloc, void* buff, uint32_t new_size)
{
pthread_mutex_lock(&alloc->lock);
alloc->size -= malloc_usable_size(buff);
void* new_buff = realloc(buff, new_size);
alloc->size += malloc_usable_size(new_buff);
pthread_mutex_unlock(&alloc->lock);
return new_buff;
}
void pst_alloc_init(pst_allocator* alloc)
{
alloc->type = ALLOC_HEAP;
alloc->base = NULL;
alloc->size = 0;
alloc->alloc = heap_alloc;
alloc->free = heap_free;
alloc->realloc = heap_realloc;
pthread_mutex_init(&alloc->lock, NULL);
return;
}
void pst_alloc_init_custom(pst_allocator* alloc, void* buff, uint32_t size)
{
// TBD to implement custom allocator
pst_alloc_init(alloc);
return;
}
void pst_alloc_fini(pst_allocator* alloc)
{
if(alloc->type == ALLOC_HEAP || alloc->type == ALLOC_CUSTOM) {
alloc->type = ALLOC_NONE;
alloc->base = NULL;
alloc->size = 0;
}
pthread_mutex_destroy(&alloc->lock);
}
+59
View File
@@ -0,0 +1,59 @@
/*
* allocator.h
*
* Created on: Jan 28, 2020
* Author: nnosov
*/
#ifndef PST_ALLOCATOR_H_
#define PST_ALLOCATOR_H_
#include <stdint.h>
#include <assert.h>
#include <pthread.h>
// concatenation
#define CAT(a, ...) CAT2(a, __VA_ARGS__)
#define CAT2(a, ...) a ## __VA_ARGS__
// declaration with initialization and parameters of initialization
#define pst_decl(TYPE, NAME, ...) \
TYPE NAME; CAT2(TYPE, _init) (&NAME, __VA_ARGS__);
// declaration with initialization
#define pst_decl0(TYPE, NAME) \
TYPE NAME; CAT2(TYPE, _init) (&NAME);
// allocation with initialization
#define pst_new(TYPE, NAME, ...) \
TYPE* NAME; NAME = CAT2(TYPE, _new) (__VA_ARGS__);
// de-initialization and deletion if was previously allocated
#define pst_fini(TYPE, NAME) \
CAT2(TYPE, _fini) (NAME);
typedef enum {
ALLOC_NONE = 0, // not initialized
ALLOC_HEAP = 1, // use libc memory allocator
ALLOC_CUSTOM = 2 // use custom allocator in predefined range of memory
} pst_alloc_type;
typedef struct pst_allocator {
// methods
void* (*alloc)(pst_allocator* alloc, uint32_t size);
void (*free)(pst_allocator* alloc, void* buff);
void* (*realloc)(pst_allocator* alloc, void* buff, uint32_t new_size);
// fields
int type;
void* base;
uint32_t size;
pthread_mutex_t lock;
} pst_allocator;
void pst_alloc_init(pst_allocator* alloc);
void pst_alloc_init_custom(pst_allocator* alloc, void* buff, uint32_t size);
void pst_alloc_fini(pst_allocator* alloc);
#endif /* PST_ALLOCATOR_H_ */
+328
View File
@@ -0,0 +1,328 @@
/* =============================================================================
* CDL (Configuration Definition Language) validator $Revision: 1.4 $
* (C)2004-2007 Nikolay Nosov. All rights reserved.
*
* File: $RCSfile: hash_multimap.c,v $
* Purpose: Hash Multimap implementation
* Written by: Nikolay Nosov
* Last modified: $Date: 2008/06/21 12:15:53 $ by $Author: nnosov $.
*
* For more information please visit
* http://nsoft.volgocity.ru/cdl or
* http://cdl.sourceforge.net
* ===========================================================================*/
#include "../src/utils/hash_multimap.h"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
/* Default hash function
@param key hash key
@param size hash key size in bytes
@return hash value, depends of the hash key
*/
static unsigned int default_hash_fn(const void *key, int size)
{
register int i, j;
unsigned int cs = 0;
unsigned int ps = 0;
if(key)
{
for(i = 0, j = 0; i < size; i++, j++)
{
ps |= ((unsigned int)((const char*)key)[i]) << (j * 8);
if(j == 3 || j == (size - 1))
{
cs ^= ps;
ps = 0;
j = 0;
}
}
}
return cs;
}
static int default_compare_fn(const void *key1, const void *key2, const int size)
{
return !memcmp(key1, key2, size);
}
/** Initialize hash node. Must be called before first usage of the node.
@param node pointer to the hash node descriptor
*/
void hash_node_init(struct hash_node *node)
{
node->key = NULL;
node->key_size = 0;
list_node_init(&node->node);
}
/** Cleanup hash node
@param node pointer to the hash node descriptor
*/
void hash_node_cleanup(struct hash_node *node)
{
if(node->key) free(node->key);
list_node_init(&node->node);
node->key = NULL;
node->key_size = 0;
}
/** Initialize hash table
@param map pointer to the hash table descriptor
@param hash_shift size of the hash table in bits. Should be greater than
HASH_MIN_SHIFT and less than HASH_MAX_SHIFT. In case of less than HASH_MIN_SHIFT,
will be followed by HASH_MIN_SHIFT, in case of greater HASH_MAX_SHIFT will be
followed by HASH_MAX_SHIFT
@param hf pointer to the user defined hash function. If NULL, then default hash
function will be used
@param cf pointer to the user defined compare function. if NULL, then the default
compare function will be used
*/
int hash_head_init(struct hash_head *map, unsigned int hash_shift, _hash_fn hf, _compare_fn cf)
{
int i;
if(map)
{
if(hash_shift <= HASH_MIN_SHIFT) {
map->hash_shift = HASH_MIN_SHIFT;
} else if(hash_shift >= HASH_MAX_SHIFT) {
map->hash_shift = HASH_MAX_SHIFT;
} else {
map->hash_shift = hash_shift;
}
map->hash_size = 1UL << map->hash_shift;
map->hash_mask = (map->hash_size - 1);
map->bucket = (struct list_head *)malloc(sizeof(struct list_head) * map->hash_size);
if(map->bucket)
{
for(i = 0; i < map->hash_size; i++)
{
list_head_init(map->bucket + i);
}
if(hf) {
map->hash_fn = hf;
} else {
map->hash_fn = default_hash_fn;
}
if(cf) {
map->compare_fn = cf;
} else {
map->compare_fn = default_compare_fn;
}
}
else
return ENOMEM;
}
else
return ENODEV;
return 0;
}
/** Cleanup hash table descriptor
@param map pointer to the hash table descriptor
*/
void hash_head_cleanup(struct hash_head *map)
{
struct list_node *p, *n;
struct hash_node *node;
int i;
if(map)
{
if(map->bucket)
{
for(i = 0; i < map->hash_size; i++)
{
list_for_each_safe(p, n, map->bucket + i)
{
node = list_entry(p, struct hash_node, node);
hash_node_cleanup(node);
}
}
free(map->bucket);
}
}
}
/** Find first node which key is equal to the key represented
@param map pointer to the hash table descriptor
@param key pointer to the hash key
@param key_size size of the hash key
@return pointer to the key found, or NULL in case of hash table have not nodes
with the key equals to the key represented
*/
struct hash_node* hash_find(struct hash_head *map, const void *key, int key_size)
{
struct list_head *list;
struct list_node *n;
struct hash_node *node;
list = map->bucket + (map->hash_fn(key, key_size) & map->hash_mask);
list_for_each(n, list)
{
node = list_entry(n, struct hash_node, node);
if(key_size == node->key_size)
{
if(map->compare_fn(key, node->key, key_size)) return node;
}
}
return NULL;
}
/** Find next node, which key is equal to the key represented
@param hn1 pointer to the previous node found.
@return pointer to the next node with the same key, or NULL in case of the current
node is the last node with appropriate key
*/
struct hash_node* hash_find_next(struct hash_head *map, struct hash_node *hn1)
{
struct list_node *n = &hn1->node;
struct hash_node *hn2;
while((n = list_next(n)) != NULL)
{
hn2 = list_entry(n, struct hash_node, node);
if(hn1->key_size == hn2->key_size)
{
if(map->compare_fn(hn1->key, hn2->key, hn2->key_size)) return hn2;
}
}
return NULL;
}
/** Add node to the hash table
@param map pointer to the hash table
@param node pointer to the node, which will be added to the table
@param key pointer to the hash key
@param key_size size of the hash key
@return zero in case of success, ENOMEM in case of error
*/
int hash_add(struct hash_head *map, struct hash_node *node, const void *key, int key_size)
{
node->key = (char*)malloc(key_size);
if(node->key)
{
memcpy(node->key, key, key_size);
node->key_size = key_size;
list_add_bottom(map->bucket + (map->hash_fn(key, key_size) & map->hash_mask), &node->node);
return 0;
}
return ENOMEM;
}
/** Remove node from the hash table
@param node pointer to the node descriptor
*/
void hash_del(struct hash_node *node)
{
list_del_init(&node->node);
hash_node_cleanup(node);
}
/** Initialize iterator for usage. Must be called before first iterator usage.
@param map pointer to the hash table descriptor
@param iter pointer to the iterator descriptor
*/
void hash_iterator_init(struct hash_head *map, struct hash_iterator *iter)
{
iter->map = map;
iter->map_idx = 0;
iter->current = NULL;
}
/** Move iterator to the first node in the table, and return pointer to the node
@param iter pointer to the iterator descriptor
@return pointer to the first node in the table, or NULL in case of error
*/
struct hash_node * hash_node_first(struct hash_iterator *iter)
{
iter->current = list_first(iter->map->bucket);
iter->map_idx = 0;
if (iter->current)
{
return list_entry(iter->current, struct hash_node, node);
}
return NULL;
}
/** Move iterator to the next node in the table and return pointer to the node
@param iter pointer to the iterator descriptor
@return pointer to the next node in the table, or NULL in case of error
*/
struct hash_node * hash_node_next(struct hash_iterator *iter)
{
if(iter->map_idx >= iter->map->hash_size) return NULL;
if(iter->current) {
iter->current = list_next(iter->current);
}
if(iter->current) {
return list_entry(iter->current, struct hash_node, node);
}
while(iter->map_idx < iter->map->hash_size) {
iter->current = list_first(iter->map->bucket + iter->map_idx);
iter->map_idx++;
if(iter->current) {
return list_entry(iter->current, struct hash_node, node);
}
}
return NULL;
}
/** Remove current node, pointed by iterator, and move iterator to the next node
@param iter pointer to the iterator descriptor
*/
void hash_node_del(struct hash_iterator *iter)
{
struct list_node *tmp;
tmp = iter->current;
hash_node_next(iter);
list_del_init(tmp);
}
/** Return total count of elements in the hash table
@param head pointer to the hash table descriptor
*/
int hash_count(struct hash_head *head)
{
int i;
int count = 0;
for(i = 0; i < head->hash_size; i++) count += list_count(head->bucket + i);
return count;
}
+94
View File
@@ -0,0 +1,94 @@
#ifndef HASH_MULTIMAP_H
#define HASH_MULTIMAP_H
#include "../src/utils/list_head.h"
#define HASH_MIN_SHIFT (8)
#define HASH_MAX_SHIFT (15)
#define hash_entry(ptr, type, member) container_of(ptr, type, member)
/** Hash multimap node descriptor
@param key hash key value
@param key_size hash key size in bytes
@param node uplink to hash multimap table
*/
struct hash_node
{
char *key;
int key_size;
struct list_node node;
};
/** Hash function prototype
@param key hash key value
@param key_size hash key size in bytes
@return hash value
*/
typedef unsigned int (* _hash_fn)(const void *key, int key_size);
/** Compare function prototype
*
* @param key1 pointer to the first key for comparison
* @param key2 pointer to the second key for comparison
* @param size size of compared part of the keys in bytes
*
* @return zero if keys equals each other, othervize 1
*/
typedef int (*_compare_fn)(const void *key1, const void *key2, int size);
/** Hash multimap table descriptor
@param hash_shift size of hash table as power of 2
@param hash_size size of the hash table
@param hash_mask mask for the hash value
@param bucket pointer to the array of linked lists. in other words, pointer to
hash multimap table
@param count count of the nodes in the hash table
*/
struct hash_head
{
unsigned char hash_shift;
unsigned short hash_size;
unsigned int hash_mask;
struct list_head *bucket;
//int count;
_hash_fn hash_fn;
_compare_fn compare_fn;
};
/** Hash table iterator
@param map pointer to the hash table descriptor, used for iteration
@param current pointer to the current list node (bucket[map_idx])
@param map_idx current bucket index
*/
struct hash_iterator
{
struct hash_head *map; // pointer to the hash map header
struct list_node *current; // pointer to current list node in the bucket[map_idx] list
unsigned int map_idx; // index of current list in the hash map bucket
};
void hash_node_init(struct hash_node *node);
void hash_node_cleanup(struct hash_node *node);
int hash_head_init(struct hash_head *map, unsigned int hash_shift = HASH_MIN_SHIFT, _hash_fn hf = 0, _compare_fn cf = 0);
void hash_head_cleanup(struct hash_head *map);
struct hash_node* hash_find(struct hash_head *map, const void *key, int key_size);
struct hash_node* hash_find_next(struct hash_head *map, struct hash_node *node);
int hash_add(struct hash_head *map, struct hash_node *node, const void *key, int key_size);
void hash_del(struct hash_node *node);
void hash_iterator_init(struct hash_head *map, struct hash_iterator *iter);
struct hash_node * hash_node_first(struct hash_iterator *iter);
struct hash_node * hash_node_next(struct hash_iterator *iter);
void hash_node_del(struct hash_iterator *iter);
int hash_count(struct hash_head *head);
#endif // HASH_MULTIMAP_H
+338
View File
@@ -0,0 +1,338 @@
/*******************************************************************************
Copyright (c) 2006, Nikolay Nosov
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef __LIST_HEAD_H__
#define __LIST_HEAD_H__
/**
Double linked list for user space implementation
*/
#include <stddef.h> /* for NULL declaration */
/** Get offset of a member
@param TYPE the type of the struct
@param MEMBER the name of the member, which offset to be computed
*/
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
/** Casts a member of a structure out to the containing structure
@param ptr the pointer to the member.
@param type the type of the container struct this is embedded in
@param member the name of the member within the struct.
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type, member) );})
/** Get the struct for this entry
@param ptr the &struct list_head pointer.
@param type the type of the struct this is embedded in.
@param member the name of the list_struct within the struct
*/
#define list_entry(ptr, type, member) container_of(ptr, type, member)
/** Iterate over a list
@param pos the &struct list_head to use as a loop counter.
@param head the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->first; pos; \
pos = pos->next)
/**
* list_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 list_for_each_entry(tpos, pos, head, member) \
for (pos = (head)->first; \
pos && ({ tpos = list_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
/** Iterate over list of given type safe against removal of list entry
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct list_node to use as a loop cursor.
* @n: another &struct list_node to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_node within the struct.
*/
#define list_for_each_entry_safe(tpos, pos, n, head, member) \
for (pos = (head)->first; \
pos && ({ n = pos->next; 1; }) && \
({ tpos = list_entry(pos, typeof(*tpos), member); 1;}); \
pos = n)
/** Iterate over a list backwards
@param pos the &struct list_head to use as a loop counter.
@param head the head for your list.
*/
#define list_for_each_prev(pos, head) \
for (pos = (head)->last; pos; \
pos = pos->prev)
/** Iterate over a list safe against removal of list entry
@param pos the &struct list_head to use as a loop counter.
@param n another &struct list_head to use as temporary storage
@param head the head for your list.
*/
#if !defined(list_for_each_safe)
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
pos = n)
#endif
/* to compiler be happy */
struct list_head;
/** Node of the list
@param next next node in the list
@param prev previous node in the list
@param head head of the list
*/
typedef struct list_node
{
struct list_node *next, *prev;
struct list_head *head;
} list_node;
/** Head of the list
@param first first node in the list
@param last last node in the list
@param count cont of the nodes
*/
typedef struct list_head
{
struct list_node *first, *last;
int count;
} list_head;
/**
Compile time initialization of the head struct
*/
#define LIST_HEAD_INIT { .first = NULL, .last = NULL, .count = 0 }
/**
Compile time initialization of the node struct
*/
#define LIST_NODE_INIT { .prev = NULL, .next = NULL, .head = NULL }
/** Runtime initialization of the head struct
(should be applied before first using of the list)
@param node head, which to be initialized.
*/
static inline void list_head_init(struct list_head *head)
{
head->first = head->last = NULL;
head->count = 0;
}
/** Runtime initialization of the node struct
(should be applied before first using of the node)
@param node node, which to be initialized.
*/
static inline void list_node_init(struct list_node *node)
{
node->next = node->prev = NULL;
node->head = NULL;
}
/** Add node to begin of the list
@param head the head of the list
@param node node of the list, which to be added
*/
static inline void list_add_head(struct list_head *head, struct list_node *node)
{
struct list_node *pfirst = head->first;
head->first = node;
node->next = pfirst;
node->prev = NULL;
node->head = head;
if(pfirst) pfirst->prev = node;
else head->last = node;
head->count++;
}
/** Add node to the end of the list
@param head the head of the list;
@param node node of the list, which to be added
*/
static inline void list_add_bottom(struct list_head *head, struct list_node *node)
{
struct list_node *plast = head->last;
head->last = node;
node->next = NULL;
node->prev = plast;
node->head = head;
if(plast) plast->next = node;
else head->first = node;
head->count++;
}
/** Add node in the list after given 'base' node
@param base the base node, after that node will be added
@param node node of the list, which to be added
*/
static inline void list_add_after(struct list_node *base, struct list_node *node)
{
struct list_node *pnext = base->next;
base->next = node;
node->next = pnext;
node->prev = base;
node->head = base->head;
if(pnext) pnext->prev = node;
else base->head->last = node;
base->head->count++;
}
/** Adds node in the list before given 'base' node
@param base the base node, before that node will be added
@param node node of the list, which to be added
*/
static inline void list_add_before(struct list_node *base, struct list_node *node)
{
struct list_node *pprev = base->prev;
base->prev = node;
node->next = base;
node->prev = pprev;
node->head = base->head;
if(pprev) pprev->next = node;
else base->head->first = node;
base->head->count++;
}
/** Remove node from the list
@param node the node, which to be removed
*/
static inline void list_del(struct list_node *node)
{
if(node->head)
{
if(node->prev) node->prev->next = node->next;
else node->head->first = node->next;
if(node->next) node->next->prev = node->prev;
else node->head->last = node->prev;
node->head->count--;
}
node->prev = node->next = NULL;
node->head = NULL;
}
static inline void list_del_init(struct list_node *node)
{
list_del(node);
list_node_init(node);
}
/** Count of the nodes in the list
@param head the head of the list
@return count of the nodes in the list
*/
static inline int list_count(struct list_head *head)
{
return head->count;
}
/** First element of the list
@param head the head of the list
@return pointer to first element of the list
*/
static inline struct list_node* list_first(struct list_head *head)
{
return head->first;
}
/** Last element of the list
@param head the head of the list
@return pointer to last element of the list
*/
static inline struct list_node* list_last(struct list_head *head)
{
return head->last;
}
/** Next element of the list
@param head current element of the list
@return pointer to next element relatively of current
*/
static inline struct list_node* list_next(struct list_node *node)
{
return node->next;
}
/** Previous element of the list
@param head current element of the list
@return pointer to previous element relatively of current
*/
static inline struct list_node* list_prev(struct list_node *node)
{
return node->prev;
}
#endif // __LIST_HEAD_H__
+246
View File
@@ -0,0 +1,246 @@
#include "../../src/utils/log.h"
#include <time.h>
#include <stdlib.h>
const char * const severity_map[] = {
" [DEBUG] : ",
" [INFO] : ",
" [WARNING]: ",
" [ERROR] : "
};
void format_string(pst_log* log, const char* fmt, va_list args)
{
log->mStringLen += vsnprintf(log->mString + log->mStringLen, log->mStringSize - log->mStringLen, fmt, args);
}
void format_prefix(pst_log* log, SC_LogSeverity severity)
{
time_t rawTime;
struct tm * timeinfo;
time(&rawTime);
timeinfo = gmtime(&rawTime);
log->mStringLen += strftime(log->mString, sizeof(log->mString), "%d-%m-%Y %H:%M:%S", timeinfo);
strncpy(log->mString + log->mStringLen, severity_map[(int)severity], strlen(severity_map[(int)severity]));
log->mStringLen += strlen(severity_map[(int)severity]);
}
void format_postfix(pst_log* log)
{
if((log->mStringLen + 2) < log->mStringSize) {
log->mString[log->mStringLen++] = '\n';
log->mString[log->mStringLen++] = 0;
}
}
//variable argument number logging
void log(pst_log* log, SC_LogSeverity severity, const char* fmt, ...)
{
if (severity < log->mCurrentSeverity)
return;
pthread_mutex_lock(&log->mLock);
if(!log->is_opened(log)) {
log->open(log);
}
log->mStringLen = 0;
format_prefix(log, severity);
va_list args;
va_start(args, fmt);
format_string(log, fmt, args);
va_end(args);
format_postfix(log);
log->send_message(log, severity);
pthread_mutex_unlock(&log->mLock);
}
void log_init_base(pst_log* plog, const char* source)
{
// methods
plog->log = log;
// fields
plog->mpSource = 0;
if(source) {
plog->mpSource = strdup(source);
}
plog->mString[0] = 0;
plog->mStringSize = sizeof(plog->mString);
plog->mStringLen = 0;
plog->mCurrentSeverity = SEVERITY_DEBUG;
pthread_mutex_init(&plog->mLock, NULL);
plog->child = 0;
}
void pst_log_fini(pst_log* log)
{
pthread_mutex_destroy(&log->mLock);
log->close(log);
if(log->mpSource) {
free(log->mpSource);
log->mpSource = 0;
}
}
//
// Console logger implementation
//
#define RED "\e[0;31m"
#define GREEN "\e[0;32m"
#define YELLOW "\e[1;33m"
#define NC "\e[0m" // No Color
//actually sends message to the source
void send_msg_console(pst_log* log, SC_LogSeverity severity)
{
const char* color = NC;
switch(severity) {
case SEVERITY_DEBUG:
color = NC;
break;
case SEVERITY_ERROR:
color = RED;
break;
case SEVERITY_INFO:
color = GREEN;
break;
case SEVERITY_WARNING:
color = YELLOW;
break;
default:
color = NC;
break;
}
fprintf(stderr, "%s%s%s", color, log->mString, NC);
}
void close_console(pst_log* log) {
// do nothing
}
bool open_console(pst_log* log) {
return true;
}
bool is_opened_console(pst_log* log) {
return true;
}
void pst_log_init_console(pst_log* log)
{
log_init_base(log, NULL);
log->close = close_console;
log->open = open_console;
log->is_opened = is_opened_console;
log->send_message = send_msg_console;
}
//
// Log to file
//
typedef struct _file_spec {
FILE* fd;
uint64_t max_bytes;
uint64_t num_bytes;
char* dir;
char* fname;
} file_spec;
//open file for writing
bool open_file(pst_log* log)
{
file_spec* fsp = (file_spec*)log->child;
if(!fsp) {
fprintf(stderr, "Wrong initialization of File-based logger\n");
return false;
}
if(!fsp->fd) {
// extract log and path names
uint32_t namelen = strlen(log->mpSource);
if(namelen) {
const char* ptr = strrchr(log->mpSource, '/');
uint32_t pathlen = 0;
if(ptr) {
pathlen = ptr - log->mpSource + 1;
namelen -= pathlen + 1;
}
fsp->dir = strndup(log->mpSource, pathlen);
fsp->fname = strndup(log->mpSource + pathlen, namelen);
//open the file finally
fsp->fd = fopen(log->mpSource, "a+");
}
}
return (fsp->fd != 0);
}
void close_file(pst_log* log)
{
file_spec* fsp = (file_spec*)log->child;
if(!fsp) {
fprintf(stderr, "Wrong initialization of File-based logger while close\n");
return;
}
if(fsp->fd) {
fclose(fsp->fd);
}
fsp->fd = 0;
fsp->max_bytes = 0;
}
bool is_file_opened(pst_log* log)
{
file_spec* fsp = (file_spec*)log->child;
if(!fsp) {
fprintf(stderr, "Wrong initialization of File-based logger while check open\n");
return false;
}
return (fsp->fd != 0);
}
void send_msg_file(pst_log* log, SC_LogSeverity severity)
{
file_spec* fsp = (file_spec*)log->child;
if(!fsp) {
fprintf(stderr, "Wrong initialization of File-based logger while check send message\n");
return;
}
if(fsp->fd && fsp->num_bytes < fsp->max_bytes) {
if(fputs(log->mString, fsp->fd) >= 0) {
fflush(fsp->fd);
fsp->num_bytes += log->mStringLen;
} else {
fclose(fsp->fd);
fsp->fd = 0;
}
}
}
void pst_log_init_file(pst_log* log, const char* path, uint64_t max_bytes)
{
log_init_base(log, path);
file_spec* fsp = (file_spec*)malloc(sizeof(file_spec));
fsp->fd = 0;
fsp->max_bytes = max_bytes;
fsp->num_bytes = 0;
log->child = fsp;
log->close = close_file;
log->open = open_file;
log->is_opened = is_file_opened;
log->send_message = send_msg_file;
}
+50
View File
@@ -0,0 +1,50 @@
#ifndef PST_LOG_H_
#define PST_LOG_H_
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <limits.h>
// Log message severity
enum SC_LogSeverity {
SEVERITY_DEBUG = 0,
SEVERITY_INFO,
SEVERITY_WARNING,
SEVERITY_ERROR,
//----------------
SEVERITY_MAX
};
#define LOG_BUFF_SIZE (1024*1024)
typedef struct __pst_log pst_log;
typedef struct __pst_log {
// methods
void (*close) (pst_log* log);
bool (*open) (pst_log* log);
bool (*is_opened) (pst_log* log);
void (*log) (pst_log* log, SC_LogSeverity severity, const char* fmt, ...);
void (*send_message) (pst_log* log, SC_LogSeverity severity);
// fields
char* mpSource; // source for store log messages (file, IP:port or something else)
char mString[LOG_BUFF_SIZE]; // formatted string to be printed
uint32_t mStringSize; // size of the 'mString' buffer
uint32_t mStringLen; // length of the formatted string
SC_LogSeverity mCurrentSeverity; // maximum severity value to be logged
pthread_mutex_t mLock;
void* child;
} pst_log;
void pst_log_init_console(pst_log* log);
void pst_log_init_file(pst_log* log, const char* path, uint64_t max_bytes = 64 * 1024 * 1024/* 64Mb */);
void pst_log_fini(pst_log* log);
#endif /* PST_LOG_H_ */