Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UCS/CONFIG: let ucx support configuration file #100

Open
wants to merge 3 commits into
base: integration3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,26 @@ AS_IF([${LN_S} --relative symlinktest 2>/dev/null],
#
AC_DEFINE_UNQUOTED([UCX_CONFIGURE_FLAGS], ["$config_flags"], [UCX configure flags])

#
# File path for ucx conf
# ./configure is /etc/ucx.conf
# ./configure --prefix=/usr is /etc/ucx.conf
# ./configure --prefix=/usr/local is /usr/local/etc/ucx.conf
# ./configure --prefix=/usr/local --sysconfdir=/etc is /etc/ucx.conf
#
case "$prefix" in
NONE | /usr)
case "$sysconfdir" in
'${prefix}/etc')
sysconfdir=/etc
;;
esac
;;
esac

SYSCONFDIR_TMP="`eval echo $sysconfdir`"
AC_SUBST([ucx_conf_file], [${SYSCONFDIR_TMP}/ucx.conf])
AC_DEFINE_UNQUOTED([UCX_CONF_FILE], ["$ucx_conf_file"], [ucx conf file])

#
# Provide the functionality of AS_VAR_APPEND if Autoconf does not have it.
Expand Down Expand Up @@ -391,6 +411,7 @@ AC_MSG_NOTICE([Building documents only])
[
AC_MSG_NOTICE([UCX build configuration:])
AC_MSG_NOTICE([ Build prefix: ${prefix}])
AC_MSG_NOTICE([ config file: ${ucx_conf_file}])
AC_MSG_NOTICE([Preprocessor flags: ${BASE_CPPFLAGS}])
AC_MSG_NOTICE([ C compiler: ${CC} ${BASE_CFLAGS}])
AC_MSG_NOTICE([ C++ compiler: ${CXX} ${BASE_CXXFLAGS}])
Expand Down
2 changes: 2 additions & 0 deletions src/ucs/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ nobase_dist_libucs_la_HEADERS = \
algorithm/qsort_r.h \
async/async_fwd.h \
config/global_opts.h \
config/ini.h \
config/parser.h \
config/types.h \
datastruct/callbackq.h \
Expand Down Expand Up @@ -122,6 +123,7 @@ libucs_la_SOURCES = \
async/thread.c \
config/global_opts.c \
config/ucm_opts.c \
config/ini.c \
config/parser.c \
datastruct/arbiter.c \
datastruct/callbackq.c \
Expand Down
344 changes: 344 additions & 0 deletions src/ucs/config/ini.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,344 @@
/* inih -- simple .INI file parser

SPDX-License-Identifier: BSD-3-Clause

Copyright (C) 2009-2020, Ben Hoyt

inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:

https://github.com/benhoyt/inih

*/

/*
An example without section
test.ini
##########
# Test config file for ini example
version = 0.0.1 # verison
name = jack # name
##########

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "ini.h"
typedef struct {
char* version;
char* name;
} config;
static int handler(void* user, const char* section, const char* name,
const char* value) {
config* conf = (config*)user;
#define MATCH(n) (strcmp(section, "") == 0 && strcmp(name, n) == 0)
if (MATCH("version")) {
conf->version = strdup(value);
} else if (MATCH("name")) {
conf->name = strdup(value);
} else {
return 0;
}
return 1;
}
int main() {
config conf;
if (ini_parse("test.ini", handler, &conf) < 0) {
printf("Can't load test.ini %s\n", strerror(errno));
return 1;
}
printf("Config loaded from test.int: version=%s, name=%s\n",
conf.name, conf.version);
free(conf.version);
free(conf.name);
return 0;
}

*/

#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <stdio.h>
#include <ctype.h>
#include <string.h>

#include "ini.h"

#if !INI_USE_STACK
#if INI_CUSTOM_ALLOCATOR
#include <stddef.h>
void* ini_malloc(size_t size);
void ini_free(void* ptr);
void* ini_realloc(void* ptr, size_t size);
#else
#include <stdlib.h>
#define ini_malloc malloc
#define ini_free free
#define ini_realloc realloc
#endif
#endif

#define MAX_SECTION 50
#define MAX_NAME 50

/* Used by ini_parse_string() to keep track of string parsing state. */
typedef struct {
const char* ptr;
size_t num_left;
} ini_parse_string_ctx;

/* Strip whitespace chars off end of given string, in place. Return s. */
static char* rstrip(char* s)
{
char* p = s + strlen(s);
while (p > s && isspace((unsigned char)(*--p)))
*p = '\0';
return s;
}

/* Return pointer to first non-whitespace char in given string. */
static char* lskip(const char* s)
{
while (*s && isspace((unsigned char)(*s)))
s++;
return (char*)s;
}

/* Return pointer to first char (of chars) or inline comment in given string,
or pointer to NUL at end of string if neither found. Inline comment must
be prefixed by a whitespace character to register as a comment. */
static char* find_chars_or_comment(const char* s, const char* chars)
{
#if INI_ALLOW_INLINE_COMMENTS
int was_space = 0;
while (*s && (!chars || !strchr(chars, *s)) &&
!(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
was_space = isspace((unsigned char)(*s));
s++;
}
#else
while (*s && (!chars || !strchr(chars, *s))) {
s++;
}
#endif
return (char*)s;
}

/* Similar to strncpy, but ensures dest (size bytes) is
NUL-terminated, and doesn't pad with NULs. */
static char* strncpy0(char* dest, const char* src, size_t size)
{
/* Could use strncpy internally, but it causes gcc warnings (see issue #91) */
size_t i;
for (i = 0; i < size - 1 && src[i]; i++)
dest[i] = src[i];
dest[i] = '\0';
return dest;
}

/* See documentation in header file. */
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
void* user)
{
/* Uses a fair bit of stack (use heap instead if you need to) */
#if INI_USE_STACK
char line[INI_MAX_LINE];
int max_line = INI_MAX_LINE;
#else
char* line;
size_t max_line = INI_INITIAL_ALLOC;
#endif
#if INI_ALLOW_REALLOC && !INI_USE_STACK
char* new_line;
size_t offset;
#endif
char section[MAX_SECTION] = "";
char prev_name[MAX_NAME] = "";

char* start;
char* end;
char* name;
char* value;
int lineno = 0;
int error = 0;

#if !INI_USE_STACK
line = (char*)ini_malloc(INI_INITIAL_ALLOC);
if (!line) {
return -2;
}
#endif

#if INI_HANDLER_LINENO
#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno)
#else
#define HANDLER(u, s, n, v) handler(u, s, n, v)
#endif

/* Scan through stream line by line */
while (reader(line, (int)max_line, stream) != NULL) {
#if INI_ALLOW_REALLOC && !INI_USE_STACK
offset = strlen(line);
while (offset == max_line - 1 && line[offset - 1] != '\n') {
max_line *= 2;
if (max_line > INI_MAX_LINE)
max_line = INI_MAX_LINE;
new_line = ini_realloc(line, max_line);
if (!new_line) {
ini_free(line);
return -2;
}
line = new_line;
if (reader(line + offset, (int)(max_line - offset), stream) == NULL)
break;
if (max_line >= INI_MAX_LINE)
break;
offset += strlen(line + offset);
}
#endif

lineno++;

start = line;
#if INI_ALLOW_BOM
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
(unsigned char)start[1] == 0xBB &&
(unsigned char)start[2] == 0xBF) {
start += 3;
}
#endif
start = lskip(rstrip(start));

if (strchr(INI_START_COMMENT_PREFIXES, *start)) {
/* Start-of-line comment */
}
#if INI_ALLOW_MULTILINE
else if (*prev_name && *start && start > line) {
/* Non-blank line with leading whitespace, treat as continuation
of previous name's value (as per Python configparser). */
if (!HANDLER(user, section, prev_name, start) && !error)
error = lineno;
}
#endif
else if (*start == '[') {
/* A "[section]" line */
end = find_chars_or_comment(start + 1, "]");
if (*end == ']') {
*end = '\0';
strncpy0(section, start + 1, sizeof(section));
*prev_name = '\0';
#if INI_CALL_HANDLER_ON_NEW_SECTION
if (!HANDLER(user, section, NULL, NULL) && !error)
error = lineno;
#endif
}
else if (!error) {
/* No ']' found on section line */
error = lineno;
}
}
else if (*start) {
/* Not a comment, must be a name[=:]value pair */
end = find_chars_or_comment(start, "=:");
if (*end == '=' || *end == ':') {
*end = '\0';
name = rstrip(start);
value = end + 1;
#if INI_ALLOW_INLINE_COMMENTS
end = find_chars_or_comment(value, NULL);
if (*end)
*end = '\0';
#endif
value = lskip(value);
rstrip(value);

/* Valid name[=:]value pair found, call handler */
strncpy0(prev_name, name, sizeof(prev_name));
if (!HANDLER(user, section, name, value) && !error)
error = lineno;
}
else if (!error) {
/* No '=' or ':' found on name[=:]value line */
#if INI_ALLOW_NO_VALUE
*end = '\0';
name = rstrip(start);
if (!HANDLER(user, section, name, NULL) && !error)
error = lineno;
#else
error = lineno;
#endif
}
}

#if INI_STOP_ON_FIRST_ERROR
if (error)
break;
#endif
}

#if !INI_USE_STACK
ini_free(line);
#endif

return error;
}

/* See documentation in header file. */
int ini_parse_file(FILE* file, ini_handler handler, void* user)
{
return ini_parse_stream((ini_reader)fgets, file, handler, user);
}

/* See documentation in header file. */
int ini_parse(const char* filename, ini_handler handler, void* user)
{
FILE* file;
int error;

file = fopen(filename, "r");
if (!file)
return -1;
error = ini_parse_file(file, handler, user);
fclose(file);
return error;
}

/* An ini_reader function to read the next line from a string buffer. This
is the fgets() equivalent used by ini_parse_string(). */
static char* ini_reader_string(char* str, int num, void* stream) {
ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream;
const char* ctx_ptr = ctx->ptr;
size_t ctx_num_left = ctx->num_left;
char* strp = str;
char c;

if (ctx_num_left == 0 || num < 2)
return NULL;

while (num > 1 && ctx_num_left != 0) {
c = *ctx_ptr++;
ctx_num_left--;
*strp++ = c;
if (c == '\n')
break;
num--;
}

*strp = '\0';
ctx->ptr = ctx_ptr;
ctx->num_left = ctx_num_left;
return str;
}

/* See documentation in header file. */
int ini_parse_string(const char* string, ini_handler handler, void* user) {
ini_parse_string_ctx ctx;

ctx.ptr = string;
ctx.num_left = strlen(string);
return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler,
user);
}
Loading