Compare commits
9
Commits
b90c42182d
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f5c10cf5d | ||
|
|
17ce2c5753 | ||
|
|
93234df78d | ||
|
|
4ba00ca17a | ||
|
|
0d6fca9b26 | ||
|
|
cf2535c9e5 | ||
|
|
35c8b96967 | ||
|
|
c85c6cc819 | ||
|
|
d72aebcd09 |
@@ -0,0 +1,289 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file config.c
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <cStuff/file.h>
|
||||
#include <cStuff/config.h>
|
||||
|
||||
static const char
|
||||
m_mixed_line_indent[] = "Line indent contains tabs and spaces"
|
||||
, m_incomplete_key[] = "Incomplete key"
|
||||
, m_parser_error[] = "Parser error"
|
||||
, m_indent_error[] = "Indent error"
|
||||
, m_out_of_memory[] = "Out of memory"
|
||||
;
|
||||
|
||||
struct config_path {
|
||||
char *key;
|
||||
int size;
|
||||
int indent;
|
||||
int level;
|
||||
bool is_node;
|
||||
};
|
||||
|
||||
struct config_ctx {
|
||||
struct cstuff_config cfg;
|
||||
struct config_path path;
|
||||
CStuffConfigCallback callback;
|
||||
void *u_ptr;
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
config_get_indent(char *line)
|
||||
{
|
||||
char chr = 0, c;
|
||||
int result = 0;
|
||||
|
||||
while ((c = *line) != '\0') {
|
||||
if (c == ' ' || c == '\t') {
|
||||
if (!chr) {
|
||||
chr = c;
|
||||
}
|
||||
if (chr == c) {
|
||||
result++;
|
||||
} else {
|
||||
/* mixed indent */
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
line++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
config_read_line(char *line, ssize_t length, struct cstuff_config *cfg)
|
||||
{
|
||||
const char *err = NULL;
|
||||
CStuffConfigEvent evt = CSTUFF_CONFIG_NONE;
|
||||
ssize_t i = 0;
|
||||
int k_len = 0, v_len = 0, indent = 0;
|
||||
char c, *key = NULL, *val = NULL;
|
||||
|
||||
cfg->line_num++;
|
||||
fprintf(stderr, "cfg:%d ", cfg->line_num);
|
||||
|
||||
if ((indent = config_get_indent(line)) != -1) {
|
||||
fprintf(stderr, "indent=%d ", indent);
|
||||
key = &line[indent];
|
||||
|
||||
for (i = indent; i < length; i++) {
|
||||
c = line[i];
|
||||
if (isalnum(c) || c == '_' || c == '-') {
|
||||
k_len++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
while (i < length) {
|
||||
switch ((c = line[i++])) {
|
||||
case ':':
|
||||
evt = CSTUFF_CONFIG_NODE;
|
||||
fprintf(stderr, "node! ");
|
||||
continue;
|
||||
case '=':
|
||||
evt = CSTUFF_CONFIG_PAIR;
|
||||
fprintf(stderr, "pair! ");
|
||||
continue;
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (evt == CSTUFF_CONFIG_NODE) {
|
||||
if (line[i] && line[i] != ';') {
|
||||
evt = CSTUFF_CONFIG_ERROR;
|
||||
err = m_incomplete_key;
|
||||
}
|
||||
} else if (evt == CSTUFF_CONFIG_PAIR) {
|
||||
val = &line[i - 1];
|
||||
while (i < length) {
|
||||
switch (line[i++]) {
|
||||
case ';':
|
||||
case '\n':
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
continue;
|
||||
default:
|
||||
v_len = (int) (&line[i] - val) - 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
evt = CSTUFF_CONFIG_ERROR;
|
||||
err = m_parser_error;
|
||||
}
|
||||
} else {
|
||||
evt = CSTUFF_CONFIG_ERROR;
|
||||
err = m_mixed_line_indent;
|
||||
}
|
||||
|
||||
/* Key ! */
|
||||
if (key)
|
||||
key[k_len] = 0;
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
switch ((cfg->evt = evt)) {
|
||||
case CSTUFF_CONFIG_PAIR:
|
||||
cfg->data.pair.key = key;
|
||||
cfg->data.pair.val = val;
|
||||
cfg->data.pair.val_len = v_len;
|
||||
cfg->data.pair.key_len = k_len;
|
||||
val[v_len] = 0;
|
||||
return indent;
|
||||
case CSTUFF_CONFIG_NODE:
|
||||
cfg->data.node.name = key;
|
||||
cfg->data.node.name_len = k_len;
|
||||
return indent;
|
||||
case CSTUFF_CONFIG_ERROR:
|
||||
default:
|
||||
cfg->data.error.char_num = i;
|
||||
cfg->data.error.line_txt = line;
|
||||
cfg->data.error.err_txt = err;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
config_set_path_key(struct config_ctx *ctx, int line_indent, bool is_node)
|
||||
{
|
||||
struct config_path *path = &ctx->path;
|
||||
const char *key = ctx->cfg.data.pair.key;
|
||||
char *ptr;
|
||||
int i, len, level, k_len = ctx->cfg.data.pair.key_len;
|
||||
|
||||
if (line_indent) {
|
||||
if (path->indent) {
|
||||
level = line_indent / path->indent;
|
||||
} else {
|
||||
level = 1;
|
||||
path->indent = line_indent;
|
||||
}
|
||||
} else {
|
||||
path->indent = 0;
|
||||
level = 0;
|
||||
}
|
||||
|
||||
if (level > path->level && (!path->is_node ||
|
||||
level - path->level != path->indent)) {
|
||||
fprintf(stderr, "cfg:%d ((%d > %d && !%d) || %d - %d != %d)\n",
|
||||
ctx->cfg.line_num, level,
|
||||
path->level, path->is_node & 0xFF, level, path->level, path->indent);
|
||||
ctx->cfg.evt = CSTUFF_CONFIG_ERROR;
|
||||
ctx->cfg.data.error.line_txt = NULL;
|
||||
ctx->cfg.data.error.err_txt = m_indent_error;
|
||||
ctx->cfg.data.error.char_num = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = ctx->path.key;
|
||||
for (i = 0; i < level; i++) {
|
||||
int l = strcspn(ptr, ".");
|
||||
ptr += l;
|
||||
fprintf(stderr, "l = %d\n", l);
|
||||
}
|
||||
|
||||
len = (ptr - ctx->path.key) + 1 + k_len + 1;
|
||||
if (len > ctx->path.size) {
|
||||
char *new_key;
|
||||
if (!(new_key = realloc(ctx->path.key, len))) {
|
||||
ctx->cfg.evt = CSTUFF_CONFIG_ERROR;
|
||||
ctx->cfg.data.error.line_txt = NULL;
|
||||
ctx->cfg.data.error.err_txt = m_out_of_memory;
|
||||
ctx->cfg.data.error.char_num = 0;
|
||||
return;
|
||||
}
|
||||
ctx->path.key = new_key;
|
||||
ctx->path.size = len;
|
||||
}
|
||||
|
||||
if (level) {
|
||||
*(ptr++) = '.';
|
||||
} else {
|
||||
*ptr = 0;
|
||||
}
|
||||
strcpy(ptr, key);
|
||||
path->level = level;
|
||||
path->is_node = is_node;
|
||||
|
||||
ctx->cfg.data.pair.key = ctx->path.key;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
config_get_line(char *line, ssize_t length, void *p_ctx)
|
||||
{
|
||||
int result;
|
||||
struct config_ctx *ctx = (struct config_ctx *)p_ctx;
|
||||
|
||||
memset(&ctx->cfg.data, 0, sizeof (ctx->cfg.data));
|
||||
if ((result = config_read_line(line, length, &ctx->cfg)) != -1) {
|
||||
bool is_node = (ctx->cfg.evt == CSTUFF_CONFIG_NODE);
|
||||
/* result == indent */
|
||||
config_set_path_key(ctx, result, is_node);
|
||||
} else {
|
||||
fprintf(stderr, "cfg: read line failed %d\n", result);
|
||||
}
|
||||
|
||||
result = ctx->callback(&ctx->cfg, ctx->u_ptr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
CStuffRetcode
|
||||
cstuff_config_parse(const char *file, CStuffConfigCallback callback, void *u_ptr)
|
||||
{
|
||||
CStuffRetcode rc;
|
||||
struct config_ctx ctx;
|
||||
|
||||
memset(&ctx.cfg, 0, sizeof (ctx.cfg));
|
||||
memset(&ctx.path, 0, sizeof (ctx.path));
|
||||
if (!(ctx.path.key = malloc(CSTUFF_CONFIG_PATH_SIZE))) {
|
||||
return CSTUFF_MALLOC_ERROR;
|
||||
} else {
|
||||
ctx.path.size = CSTUFF_CONFIG_PATH_SIZE;
|
||||
}
|
||||
ctx.u_ptr = u_ptr;
|
||||
ctx.callback = callback;
|
||||
|
||||
rc = cstuff_file_get_lines(file, config_get_line, (void *)&ctx);
|
||||
|
||||
if (rc) {
|
||||
fprintf(stderr, "cfg: get lines failed %d (%s)\n", rc, strerror(errno));
|
||||
}
|
||||
|
||||
if (ctx.path.key)
|
||||
free(ctx.path.key);
|
||||
return rc;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file config.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*/
|
||||
|
||||
#include "retcode.h"
|
||||
|
||||
|
||||
#ifndef CSTUFF_CONFIG_H_6207A85E_26F1_4B64_818F_92C6286FC5F0
|
||||
#define CSTUFF_CONFIG_H_6207A85E_26F1_4B64_818F_92C6286FC5F0
|
||||
|
||||
#ifndef CSTUFF_CONFIG_PATH_SIZE
|
||||
#define CSTUFF_CONFIG_PATH_SIZE 64
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
CSTUFF_CONFIG_NONE
|
||||
, CSTUFF_CONFIG_NODE
|
||||
, CSTUFF_CONFIG_PAIR
|
||||
, CSTUFF_CONFIG_ERROR
|
||||
} CStuffConfigEvent;
|
||||
|
||||
struct cstuff_config_node {
|
||||
const char *name;
|
||||
int name_len;
|
||||
};
|
||||
|
||||
struct cstuff_config_pair {
|
||||
const char *key;
|
||||
const char *val;
|
||||
int key_len;
|
||||
int val_len;
|
||||
};
|
||||
|
||||
struct cstuff_config_error {
|
||||
const char *line_txt;
|
||||
const char *err_txt;
|
||||
int char_num;
|
||||
};
|
||||
|
||||
struct cstuff_config {
|
||||
CStuffConfigEvent evt;
|
||||
int line_num;
|
||||
union {
|
||||
struct cstuff_config_node node;
|
||||
struct cstuff_config_pair pair;
|
||||
struct cstuff_config_error error;
|
||||
} data;
|
||||
};
|
||||
|
||||
typedef struct cstuff_config * CStuffConfig;
|
||||
|
||||
|
||||
typedef int
|
||||
(* CStuffConfigCallback)(struct cstuff_config *config, void *u_ptr);
|
||||
|
||||
|
||||
CStuffRetcode
|
||||
cstuff_config_parse(const char *file, CStuffConfigCallback callback, void *u_ptr);
|
||||
|
||||
|
||||
#endif /* !CSTUFF_CONFIG_H */
|
||||
@@ -0,0 +1,141 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file file.c
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include "file.h"
|
||||
|
||||
|
||||
bool
|
||||
cstuff_file_exists(const char *file)
|
||||
{
|
||||
return ( access( file, F_OK ) != -1 ) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
CStuffRetcode
|
||||
cstuff_file_copy(const char *src, const char *dest)
|
||||
{
|
||||
CStuffRetcode rc = CSTUFF_SYSCALL_ERROR;
|
||||
int fd_src = open(src, O_RDWR), fd_dest, len;
|
||||
struct stat src_stat;
|
||||
|
||||
if (!(fd_src < 0)) {
|
||||
if (lockf(fd_src, F_LOCK, 0) != -1) {
|
||||
if (!stat(src, &src_stat)) {
|
||||
fd_dest = open(dest, O_CREAT | O_WRONLY | O_TRUNC);
|
||||
if (!(fd_dest < 0)) {
|
||||
len = sendfile(fd_dest, fd_src, NULL, src_stat.st_size);
|
||||
if (len == src_stat.st_size) {
|
||||
rc = CSTUFF_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "sendfile error (%d != %d): %s\n", len,
|
||||
(int)src_stat.st_size, strerror(errno));
|
||||
}
|
||||
close(fd_dest);
|
||||
} else {
|
||||
fprintf(stderr, "dest open() error\n");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "src stat() error\n");
|
||||
}
|
||||
if (lockf(fd_src, F_TEST, 0) == 0){
|
||||
lockf(fd_src, F_ULOCK, 0);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "src lockf() error\n");
|
||||
}
|
||||
close(fd_src);
|
||||
} else {
|
||||
fprintf(stderr, "src open() error\n");
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
CStuffRetcode
|
||||
cstuff_file_move(const char *src, const char *dest)
|
||||
{
|
||||
CStuffRetcode rc;
|
||||
|
||||
if (!(rc = cstuff_file_copy(src, dest))) {
|
||||
if (unlink(src) != 0)
|
||||
return CSTUFF_SYSCALL_ERROR;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
CStuffRetcode
|
||||
cstuff_file_get_lines(const char *src, CStuffFileGetLine get_line, void *ctx)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
size_t sz = 256;
|
||||
char *line;
|
||||
ssize_t rs;
|
||||
CStuffRetcode result = CSTUFF_SUCCESS;
|
||||
|
||||
if (!(line = malloc(sz)))
|
||||
goto e_malloc;
|
||||
|
||||
if (!(f = fopen(src, "r")))
|
||||
goto e_syscall;
|
||||
|
||||
while ((rs = getdelim(&line, &sz, '\n', f)) != -1) {
|
||||
if (!get_line(line, rs, ctx)) {
|
||||
continue;
|
||||
} else {
|
||||
goto e_input;
|
||||
}
|
||||
}
|
||||
|
||||
switch(errno) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case ENOMEM:
|
||||
goto e_malloc;
|
||||
|
||||
default:
|
||||
goto e_syscall;
|
||||
}
|
||||
goto finally;
|
||||
|
||||
e_input:
|
||||
result = CSTUFF_INPUT_ERROR;
|
||||
goto finally;
|
||||
|
||||
e_malloc:
|
||||
result = CSTUFF_MALLOC_ERROR;
|
||||
goto finally;
|
||||
|
||||
e_syscall:
|
||||
result = CSTUFF_SYSCALL_ERROR;
|
||||
goto finally;
|
||||
|
||||
finally:
|
||||
if (line)
|
||||
free(line);
|
||||
if (f)
|
||||
fclose(f);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file file.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*/
|
||||
|
||||
#ifndef CSTUFF_FILE_H_3C3D5EDC_A624_4550_98A4_29AD5A41301D
|
||||
#define CSTUFF_FILE_H_3C3D5EDC_A624_4550_98A4_29AD5A41301D
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include "retcode.h"
|
||||
|
||||
|
||||
typedef int
|
||||
(*CStuffFileGetLine)(char *line, ssize_t length, void *ctx);
|
||||
|
||||
bool
|
||||
cstuff_file_exists(const char *file);
|
||||
|
||||
|
||||
CStuffRetcode
|
||||
cstuff_file_copy(const char *src, const char *dest);
|
||||
|
||||
|
||||
CStuffRetcode
|
||||
cstuff_file_move(const char *src, const char *dest);
|
||||
|
||||
|
||||
CStuffRetcode
|
||||
cstuff_file_get_lines(const char *src, CStuffFileGetLine get_line, void *ctx);
|
||||
|
||||
#endif /* !FILE_H */
|
||||
@@ -0,0 +1,132 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file list.c
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief cStuff list module
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "list.h"
|
||||
|
||||
CStuffRetcode
|
||||
cstuff_list_init(CStuffList self, int size)
|
||||
{
|
||||
if (!(self->items = calloc(size, sizeof (void *))))
|
||||
return CSTUFF_MALLOC_ERROR;
|
||||
|
||||
self->length = 0;
|
||||
self->size = size;
|
||||
|
||||
return CSTUFF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cstuff_list_release(CStuffList self, CStuffListFree item_free)
|
||||
{
|
||||
if (self->items) {
|
||||
if (item_free) {
|
||||
int i;
|
||||
for (i = 0; i < self->length; i++) {
|
||||
void *ptr = self->items[i];
|
||||
if (ptr) {
|
||||
item_free(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(self->items);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cstuff_list_append(CStuffList self, void *item)
|
||||
{
|
||||
void **items;
|
||||
int size = self->length + 1;
|
||||
|
||||
if (size > self->size) {
|
||||
if (!(items = realloc(self->items, size * sizeof (void*))))
|
||||
return -1;
|
||||
|
||||
self->items = items;
|
||||
self->size = size;
|
||||
}
|
||||
|
||||
self->items[self->length] = item;
|
||||
|
||||
return self->length++;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cstuff_list_insert(CStuffList self, void *item, int index)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = cstuff_list_append(self, item)) == -1)
|
||||
return -1;
|
||||
|
||||
if (index >= r || index < 0)
|
||||
return r;
|
||||
|
||||
memmove(&self->items[index + 1], &self->items[index],
|
||||
(self->length - index - 1) * sizeof (void*));
|
||||
|
||||
self->items[index] = item;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
cstuff_list_remove(CStuffList self, int index)
|
||||
{
|
||||
void *result;
|
||||
int i;
|
||||
if (index < self->length) {
|
||||
result = self->items[index];
|
||||
self->length--;
|
||||
for (i = index; i < self->length; i++) {
|
||||
self->items[i] = self->items[i + 1];
|
||||
}
|
||||
} else {
|
||||
result = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cstuff_list_remove_item(CStuffList self, void *item)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < self->length; i++) {
|
||||
if (self->items[i] == item) {
|
||||
cstuff_list_remove(self, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cstuff_list_set_item(CStuffList self, int index, void *value)
|
||||
{
|
||||
if (self->size > index) {
|
||||
self->items[index] = value;
|
||||
if (index >= self->length)
|
||||
self->length = index + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file list.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief cStuff List module header file
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*/
|
||||
|
||||
#ifndef CSTUFF_LIST_H_372E2D14_8DEE_4A7C_A5AB_8808A87DF436
|
||||
#define CSTUFF_LIST_H_372E2D14_8DEE_4A7C_A5AB_8808A87DF436
|
||||
|
||||
#include "retcode.h"
|
||||
|
||||
#define cstuff_list_index(LIST, IDX) (LIST->items[IDX])
|
||||
|
||||
|
||||
struct cstuff_list {
|
||||
void **items;
|
||||
int length;
|
||||
int size;
|
||||
};
|
||||
|
||||
typedef struct cstuff_list * CStuffList;
|
||||
|
||||
typedef void
|
||||
(*CStuffListFree)(void *item);
|
||||
|
||||
|
||||
CStuffRetcode
|
||||
cstuff_list_init(CStuffList self, int size);
|
||||
|
||||
|
||||
void
|
||||
cstuff_list_release(CStuffList self, CStuffListFree item_free);
|
||||
|
||||
|
||||
int
|
||||
cstuff_list_append(CStuffList self, void *item);
|
||||
|
||||
|
||||
int
|
||||
cstuff_list_insert(CStuffList self, void *item, int index);
|
||||
|
||||
|
||||
void *
|
||||
cstuff_list_remove(CStuffList self, int index);
|
||||
|
||||
|
||||
void
|
||||
cstuff_list_remove_item(CStuffList self, void *item);
|
||||
|
||||
|
||||
void
|
||||
cstuff_list_set_item(CStuffList self, int index, void *value);
|
||||
|
||||
|
||||
#endif /* !LIST_H */
|
||||
@@ -0,0 +1,103 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file log.c
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief cStuff log module source file
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*/
|
||||
#include <time.h>
|
||||
#include "log.h"
|
||||
|
||||
|
||||
void
|
||||
cstuff_log_init(CStuffLog self, int level)
|
||||
{
|
||||
self->target = stderr;
|
||||
self->level = level;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cstuff_log_release(CStuffLog self)
|
||||
{
|
||||
if (self->target != stderr)
|
||||
fclose(self->target);
|
||||
}
|
||||
|
||||
|
||||
CStuffRetcode
|
||||
cstuff_log_set_file(CStuffLog self, const char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if (!(fp = fopen(filename, "a")))
|
||||
return CSTUFF_SYSCALL_ERROR;
|
||||
|
||||
self->target = fp;
|
||||
return CSTUFF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cstuff_log_printf(CStuffLog self, int level, const char *format, ...)
|
||||
{
|
||||
int result;
|
||||
va_list vl;
|
||||
|
||||
va_start(vl, format);
|
||||
result = cstuff_log_vprintf(self, level, format, vl);
|
||||
va_end(vl);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cstuff_log_vprintf(CStuffLog self, int level, const char *format, va_list vl)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (self->level & level) {
|
||||
FILE *f = self->target;
|
||||
char *label;
|
||||
time_t rawtime;
|
||||
char strtime[32+1];
|
||||
struct tm timeinfo;
|
||||
|
||||
time(&rawtime);
|
||||
localtime_r(&rawtime, &timeinfo);
|
||||
strftime(strtime, 32, "%F %T", &timeinfo);
|
||||
|
||||
switch (level)
|
||||
{
|
||||
case CSTUFF_LOG_ERROR:
|
||||
label = "!!";
|
||||
break;
|
||||
case CSTUFF_LOG_ALERT:
|
||||
label = "~!";
|
||||
break;
|
||||
case CSTUFF_LOG_DEBUG:
|
||||
label = "**";
|
||||
break;
|
||||
default:
|
||||
label = "--";
|
||||
}
|
||||
|
||||
result = fprintf(f, "%s %s ", strtime, label);
|
||||
result += vfprintf(f, format, vl);
|
||||
fputc('\n', f);
|
||||
result++;
|
||||
fflush(f);
|
||||
} else {
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file log.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief cStuff log module header file
|
||||
*
|
||||
* @see https://lowenware.com/cStuff/
|
||||
*/
|
||||
|
||||
#ifndef CSTUFF_LOG_H_557ADEFE_2BE8_4B9B_A894_F08FF64008EF
|
||||
#define CSTUFF_LOG_H_557ADEFE_2BE8_4B9B_A894_F08FF64008EF
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include "retcode.h"
|
||||
|
||||
#define CSTUFF_LOG_OFF (0)
|
||||
#define CSTUFF_LOG_ERROR (1<<0)
|
||||
#define CSTUFF_LOG_ALERT (1<<1)
|
||||
#define CSTUFF_LOG_STATE (1<<2)
|
||||
#define CSTUFF_LOG_DEBUG (1<<3)
|
||||
#define CSTUFF_LOG_ALL (0xFF)
|
||||
|
||||
struct cstuff_log {
|
||||
FILE *target;
|
||||
uint8_t level;
|
||||
};
|
||||
|
||||
typedef struct cstuff_log * CStuffLog;
|
||||
|
||||
|
||||
void
|
||||
cstuff_log_init(CStuffLog self, int level);
|
||||
|
||||
|
||||
void
|
||||
cstuff_log_release(CStuffLog self);
|
||||
|
||||
|
||||
CStuffRetcode
|
||||
cstuff_log_set_file(CStuffLog self, const char *filename);
|
||||
|
||||
|
||||
int
|
||||
cstuff_log_printf(CStuffLog self, int level, const char *format, ...);
|
||||
|
||||
|
||||
int
|
||||
cstuff_log_vprintf(CStuffLog self, int level, const char *format, va_list vl);
|
||||
|
||||
#endif /* !CSTUFF_LOG_H */
|
||||
@@ -0,0 +1,28 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file retcode.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief cStuff return codes
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*/
|
||||
|
||||
#ifndef CSTUFF_RETCODE_H_CBA3C16B_88D6_49F4_966D_DBDA727583FE
|
||||
#define CSTUFF_RETCODE_H_CBA3C16B_88D6_49F4_966D_DBDA727583FE
|
||||
|
||||
typedef enum {
|
||||
CSTUFF_INPUT_ERROR = -3
|
||||
, CSTUFF_MALLOC_ERROR = -2
|
||||
, CSTUFF_SYSCALL_ERROR = -1
|
||||
, CSTUFF_SUCCESS = 0
|
||||
, CSTUFF_IDLE = 1
|
||||
|
||||
} CStuffRetcode;
|
||||
|
||||
#endif /* !CSTUFF_RETCODE_H */
|
||||
@@ -0,0 +1,104 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file string.c
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief cStuff string module implementation
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "string.h"
|
||||
|
||||
int
|
||||
cstuff_strcpy(char **out, const char *in)
|
||||
{
|
||||
return cstuff_strncpy(out, in, strlen(in));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cstuff_strncpy(char **out, const char *in, int len)
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (!(s = malloc( len + 1 )))
|
||||
return -1;
|
||||
|
||||
strncpy(s, in, len);
|
||||
s[len]=0;
|
||||
|
||||
*out = s;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cstuff_strset(char **out, const char *in)
|
||||
{
|
||||
return cstuff_strnset(out, in, strlen(in));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cstuff_strnset(char **out, const char *in, int len)
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (!(s = realloc(*out, len+1)))
|
||||
return -1;
|
||||
|
||||
strncpy(s, in, len);
|
||||
s[len] = 0;
|
||||
|
||||
*out = s;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cstuff_sprintf(char **out, const char *format, ...)
|
||||
{
|
||||
int result;
|
||||
va_list vl;
|
||||
|
||||
va_start(vl, format);
|
||||
result = cstuff_vsprintf(out, format, vl);
|
||||
va_end(vl);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cstuff_vsprintf(char **out, const char *format, va_list args)
|
||||
{
|
||||
int result;
|
||||
va_list vc;
|
||||
char tmp, *s;
|
||||
|
||||
va_copy(vc, args);
|
||||
result = vsnprintf(&tmp, 1, format, vc);
|
||||
va_end(vc);
|
||||
|
||||
if (!(s = malloc(result + 1)))
|
||||
return -1;
|
||||
|
||||
*out = s;
|
||||
result = vsnprintf(s, result+1, format, args);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||
* Please, refer LICENSE file for legal information
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file string.h
|
||||
* @author Ilja Kartašov <ik@lowenware.com>
|
||||
* @brief String module declarations
|
||||
*
|
||||
* @see https://lowenware.com/
|
||||
*/
|
||||
|
||||
#ifndef CSTUFF_STRING_H_938B242C_B750_40E9_8B67_A69F2F37EB87
|
||||
#define CSTUFF_STRING_H_938B242C_B750_40E9_8B67_A69F2F37EB87
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "retcode.h"
|
||||
|
||||
|
||||
/** @brief Copies in string to newly allocated out buffer
|
||||
* @param out a pointer to an address where new pointer must be stored
|
||||
* @param in an input string
|
||||
* @return length of string or -1 if out of memory
|
||||
*/
|
||||
int
|
||||
cstuff_strcpy(char **out, const char *in);
|
||||
|
||||
|
||||
int
|
||||
cstuff_strncpy(char **out, const char *in, int len);
|
||||
|
||||
|
||||
/** @brief Overwrites content of out buffer with in string using realloc
|
||||
* @param out a pointer to an address where new string must be stored
|
||||
* @param in an input string
|
||||
* @return length of string or -1 if out of memory
|
||||
*/
|
||||
int
|
||||
cstuff_strset(char **out, const char *in);
|
||||
|
||||
|
||||
int
|
||||
cstuff_strnset(char **out, const char *in, int len);
|
||||
|
||||
|
||||
/** @brief Allocates memory and prints a formatted string into it
|
||||
* @param out a pointer to an address where new string must be stored
|
||||
* @param format a format for string (see manual for stdlib sprintf)
|
||||
* @return length of string or -1 if out of memory
|
||||
*/
|
||||
int
|
||||
cstuff_sprintf(char **out, const char *format, ...);
|
||||
|
||||
|
||||
int
|
||||
cstuff_vsprintf(char **out, const char *format, va_list args);
|
||||
|
||||
#endif /* !CSTUFF_STRING_H */
|
||||
Reference in New Issue
Block a user