parent
a4974c8df8
commit
3a8a55d177
@ -0,0 +1,193 @@ |
|||||||
|
#include <stdlib.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <stdarg.h> |
||||||
|
|
||||||
|
#include <linux/limits.h> |
||||||
|
#include <sys/stat.h> |
||||||
|
#include <sys/types.h> |
||||||
|
|
||||||
|
#define PATHS_NO 3 |
||||||
|
|
||||||
|
static char temp[PATH_MAX] = {0}; |
||||||
|
static int valid_paths = 0; |
||||||
|
static char paths[PATHS_NO][PATH_MAX] = {0}; // 0: xdg, 1: fallback, 2: global
|
||||||
|
|
||||||
|
static const mode_t CONFDIR_MODE = S_IRWXU | S_IRWXU | S_IRWXU | S_IRWXU; |
||||||
|
|
||||||
|
static void err(const char *fmt, ...) |
||||||
|
{ |
||||||
|
va_list ap; |
||||||
|
va_start(ap, fmt); |
||||||
|
|
||||||
|
fprintf(stderr, "[libconf]: "); |
||||||
|
vfprintf(stderr, fmt, ap); |
||||||
|
fprintf(stderr, "\n"); |
||||||
|
|
||||||
|
va_end(ap); |
||||||
|
} |
||||||
|
|
||||||
|
// implements "mkdir -p"
|
||||||
|
static int mkdir_p(const char *path) |
||||||
|
{ |
||||||
|
char tmp_path[PATH_MAX] = {0}; |
||||||
|
strncpy(tmp_path, path, PATH_MAX - 1); |
||||||
|
struct stat st; |
||||||
|
|
||||||
|
for (char *tk = strtok(tmp_path, "/"); tk != NULL; tk = strtok(NULL, "/")) { |
||||||
|
if (tk != tmp_path) { |
||||||
|
tk[-1] = '/'; |
||||||
|
} |
||||||
|
|
||||||
|
if (stat(tmp_path, &st)) { |
||||||
|
if (errno != ENOENT) { |
||||||
|
err("could not stat() %s: %s", |
||||||
|
tmp_path, |
||||||
|
strerror(errno)); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
if (mkdir(tmp_path, CONFDIR_MODE)) { |
||||||
|
err("could not mkdir() %s: %s", |
||||||
|
tmp_path, |
||||||
|
strerror(errno)); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
} else if (!S_ISDIR(st.st_mode)) { |
||||||
|
err("could not create directory %s: file exists but it is " |
||||||
|
"not a directory", |
||||||
|
tmp_path); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: add a way to add a custom directory to the paths, for example via an
|
||||||
|
// environment variable
|
||||||
|
// TODO: maybe add a LIBCONF_PATH that overrides the defaults
|
||||||
|
/* default paths are:
|
||||||
|
* 1. ${XDG_CONFIG_HOME}/libconf/appid.d/ |
||||||
|
* 2. ${HOME}/.config/libconf/appid.d/ |
||||||
|
* 3. etc/libconf/appid.d/ |
||||||
|
*/ |
||||||
|
static int fill_paths(const char *id) |
||||||
|
{ |
||||||
|
// TODO: verify id
|
||||||
|
if (id == NULL) { |
||||||
|
err("must provide a valid app id"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
const char *xdg = getenv("XDG_CONFIG_HOME"); |
||||||
|
if (xdg != NULL) { |
||||||
|
snprintf(paths[0], PATH_MAX, "%s/libconf/%s.d", xdg, id); |
||||||
|
} |
||||||
|
|
||||||
|
const char *home = getenv("HOME"); |
||||||
|
if (home) { |
||||||
|
snprintf(temp, PATH_MAX, "%s/.config/libconf/%s.d", home, id); |
||||||
|
|
||||||
|
if (mkdir_p(temp) == 0) { |
||||||
|
strcpy(paths[1], temp); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// do not create global config path since most likely we don't have
|
||||||
|
// the necessary permissions to do so
|
||||||
|
snprintf(paths[2], PATH_MAX, "/etc/libconf/%s.d", id); |
||||||
|
|
||||||
|
for (size_t i = 0; i < PATHS_NO; i++) { |
||||||
|
printf("paths[%ld] = %s\n", i, paths[i]); |
||||||
|
} |
||||||
|
|
||||||
|
valid_paths = 1; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// get config file path
|
||||||
|
const char *lcnf_get_conf_file(const char *id, const char *name, int global) |
||||||
|
{ |
||||||
|
static char str[PATH_MAX] = {0}; |
||||||
|
|
||||||
|
if (id == NULL) { |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
if (!valid_paths) { |
||||||
|
if (fill_paths(id)) { |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// quick path for global config file
|
||||||
|
if (global && paths[2][0] != '\0') { |
||||||
|
snprintf(str, PATH_MAX, "%s/%s", paths[2], name); |
||||||
|
return str; |
||||||
|
} |
||||||
|
|
||||||
|
int found = 0; |
||||||
|
for (size_t i = 0; i < PATHS_NO; i++) { |
||||||
|
if (paths[i][0] == '\0') { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
struct stat st; |
||||||
|
snprintf(str, PATH_MAX, "%s/%s", paths[i], name); |
||||||
|
|
||||||
|
if (stat(str, &st) && errno != ENOENT) { |
||||||
|
err("could not stat %s: %s", str, strerror(errno)); |
||||||
|
} |
||||||
|
|
||||||
|
if (S_ISREG(st.st_mode)) { |
||||||
|
found = 1; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return found ? str : NULL; |
||||||
|
} |
||||||
|
|
||||||
|
// get config file directory path
|
||||||
|
const char *lcnf_get_conf_dir(const char *id, int global) |
||||||
|
{ |
||||||
|
if (id == NULL) { |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
if (global) { |
||||||
|
return paths[2][0] != '\0' ? paths[2] : NULL; |
||||||
|
} |
||||||
|
|
||||||
|
if (paths[0][0] != '\0') { |
||||||
|
return paths[0]; |
||||||
|
} else if (paths[1][0] != '\0') { |
||||||
|
return paths[1]; |
||||||
|
} else { |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: watch directory for file updates
|
||||||
|
int lcnf_watch_conf_dir(const char *id, int global); |
||||||
|
|
||||||
|
// TODO: collect all files into a temporary one, useful for when you have multiple
|
||||||
|
// configuration files like 00-foo.conf, 01-bar.conf and 99-baz.conf
|
||||||
|
const char *lcnf_collect_conf_files(const char *id, int global); |
||||||
|
|
||||||
|
#if 1 |
||||||
|
|
||||||
|
int main(void) |
||||||
|
{ |
||||||
|
const char *p = lcnf_get_conf_file("pippo", "pippo.toml", 0); |
||||||
|
if (p) { |
||||||
|
printf("config found: %s\n", p); |
||||||
|
} else { |
||||||
|
printf("config not found\n"); |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,7 @@ |
|||||||
|
#ifndef LIBCONF_H_ |
||||||
|
#define LIBCONF_H_ |
||||||
|
|
||||||
|
const char *lcnf_get_conf_file(const char *id, const char *name, int global); |
||||||
|
const char *lcnf_get_conf_dir(const char *id, int global); |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,69 @@ |
|||||||
|
#define _POSIX_C_SOURCE 200809l |
||||||
|
|
||||||
|
#include <time.h> |
||||||
|
|
||||||
|
#include "timer.h" |
||||||
|
|
||||||
|
const clockid_t CLOCK_ID = CLOCK_PROCESS_CPUTIME_ID; |
||||||
|
|
||||||
|
struct _timer { |
||||||
|
struct timespec start, stop; |
||||||
|
struct timespec times[TIMER_MAX_PARTIAL]; |
||||||
|
} timer = {0}; |
||||||
|
|
||||||
|
int timer_start(void) { return clock_gettime(CLOCK_ID, &timer.start); } |
||||||
|
|
||||||
|
int timer_reset(void) |
||||||
|
{ |
||||||
|
timer = (struct _timer) {0}; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int timer_stop(void) { return clock_gettime(CLOCK_ID, &timer.stop); } |
||||||
|
|
||||||
|
// partial clocks also update the stop time
|
||||||
|
int timer_partial(int idx) |
||||||
|
{ |
||||||
|
if (idx > TIMER_MAX_PARTIAL || idx < 0) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
clock_gettime(CLOCK_ID, &timer.stop); |
||||||
|
return clock_gettime(CLOCK_ID, &(timer.times[idx])); |
||||||
|
} |
||||||
|
|
||||||
|
size_t timer_get_us(int idx) |
||||||
|
{ |
||||||
|
if (idx > TIMER_MAX_PARTIAL) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
struct timespec ts = {0}; |
||||||
|
if (idx < 0) { |
||||||
|
ts = timer.stop; |
||||||
|
} else { |
||||||
|
ts = timer.times[idx]; |
||||||
|
} |
||||||
|
ts.tv_sec -= timer.start.tv_sec; |
||||||
|
ts.tv_nsec -= timer.start.tv_nsec; |
||||||
|
|
||||||
|
// FIXME: check overflow
|
||||||
|
return (ts.tv_nsec / 1000) + (ts.tv_sec * 1000000); |
||||||
|
} |
||||||
|
|
||||||
|
double timer_get_sec(int idx) |
||||||
|
{ |
||||||
|
if (idx > TIMER_MAX_PARTIAL) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
struct timespec ts = {0}; |
||||||
|
if (idx < 0) { |
||||||
|
ts = timer.stop; |
||||||
|
} else { |
||||||
|
ts = timer.times[idx]; |
||||||
|
} |
||||||
|
ts.tv_sec -= timer.start.tv_sec; |
||||||
|
ts.tv_nsec -= timer.start.tv_nsec; |
||||||
|
|
||||||
|
return (double)ts.tv_sec + ((double)ts.tv_nsec / 1e9); |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
#ifndef UG_TIMER_H_ |
||||||
|
#define UG_TIMER_H_ |
||||||
|
|
||||||
|
#include <stdlib.h> |
||||||
|
|
||||||
|
#define TIMER_MAX_PARTIAL 10 |
||||||
|
|
||||||
|
int timer_start(void); |
||||||
|
int timer_stop(void); |
||||||
|
int timer_reset(void); |
||||||
|
int timer_partial(int idx); |
||||||
|
|
||||||
|
size_t timer_get_us(int idx); |
||||||
|
double timer_get_sec(int idx); |
||||||
|
|
||||||
|
#endif |
Loading…
Reference in new issue