Added a basic config file parser to lib2ine.

This will let the app set up some state about the OS/2 "system", like what
Unix paths are mapped to which OS/2 drive letters, system vars, etc.

This reads from /etc/2ine.cfg, and then tries a copy in the user's local
config dir to add/override settings.

This mostly doesn't do anything yet, but the framework is there for adding
stuff, and the drive letter mapping is done, even if nothing is using it.
This commit is contained in:
Ryan C. Gordon committed 2018-06-24 02:40:36 -04:00
1 parent 9860532454
commit 14073f3361
2 files changed
+193 -2

No files matched your search

+192 -2
View File
@@ -13,6 +13,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
@@ -348,6 +349,190 @@ static void __attribute__((noreturn)) terminate_lib2ine(const uint32 exitcode)
}
static void cfgWarn(const char *fname, const int lineno, const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "2ine cfg warning: [%s:%d] ", fname, lineno);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
static int cfgIsSpace(const int ch)
{
switch (ch) { case ' ': case '\t': case '\r': case '\n': return 1; }
return 0;
}
static int cfgIsSymChar(const int ch)
{
return ((ch == '_') || ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')));
}
static void cfgProcessDrive(const char *fname, const int lineno, const char *var, const char *val)
{
char letter = var[0];
if ((letter >= 'a') && (letter <= 'z')) {
letter -= 'a' - 'A';
}
if ((letter < 'A') || (letter > 'Z') || (var[1] != '\0')) {
cfgWarn(fname, lineno, "Invalid drive \"%s\" (must be between 'A' and 'Z')", var);
return;
}
const int idx = (int) (letter - 'A');
free(GLoaderState.drives[idx]); // in case we're overriding.
GLoaderState.drives[idx] = NULL;
if (*val != '\0') { // val=="" means don't mount
struct stat statbuf;
if (stat(val, &statbuf) == -1) {
cfgWarn(fname, lineno, "Path \"%s\" for drive %c:\\ isn't accessible: %s", val, letter, strerror(errno));
} else if (!S_ISDIR(statbuf.st_mode)) {
cfgWarn(fname, lineno, "Path \"%s\" for drive %c:\\ isn't a directory", val, letter);
} else if ((GLoaderState.drives[idx] = strdup(val)) == NULL) {
cfgWarn(fname, lineno, "Out of memory!");
}
}
}
static void cfgProcessBoolString(const char *fname, const int lineno, int *output, const char *val)
{
static const char *y[] = { "1", "yes", "y", "true", "t", "on" };
static const char *n[] = { "0", "no", "n", "false", "f", "off" };
int i;
for (i = 0; i < (sizeof (y) / sizeof (y[0])); i++) {
if (strcasecmp(val, y[i]) == 0) { *output = 1; return; }
if (strcasecmp(val, n[i]) == 0) { *output = 0; return; }
}
cfgWarn(fname, lineno, "\"%s\" is not valid for this setting. Try 1 or 0.", val);
}
static void cfgProcessSystem(const char *fname, const int lineno, const char *var, const char *val)
{
if (strcmp(var, "trace_native") == 0) {
cfgProcessBoolString(fname, lineno, &GLoaderState.trace_native, val);
} else if (strcmp(var, "trace_events") == 0) {
cfgProcessBoolString(fname, lineno, &GLoaderState.trace_events, val);
} else {
cfgWarn(fname, lineno, "Unknown variable system.%s", var);
}
}
static void cfgProcessLine(const char *fname, const int lineno, const char *category, const char *var, const char *val)
{
//printf("CFG: process line cat=%s var=%s, val=%s\n", category, var, val);
if ((*category == '\0') || (*var == '\0')) {
cfgWarn(fname, lineno, "Invalid configuration line");
} else if (strcmp(category, "drive") == 0) {
cfgProcessDrive(fname, lineno, var, val);
// eventually will map COM1, LPT1, NUL, etc.
//} else if (strcmp(category, "device") == 0) {
// cfgProcessDevice(fname, lineno, var, val);
} else if (strcmp(category, "system") == 0) {
cfgProcessSystem(fname, lineno, var, val);
} else {
cfgWarn(fname, lineno, "Unknown category \"%s\"", category);
}
}
static void cfgLoad(const char *fname)
{
FILE *io = fopen(fname, "r");
char *buffer = NULL;
size_t buflen = 0;
unsigned int lineno = 0;
ssize_t len;
if (io == NULL) {
return;
}
while ((len = getline(&buffer, &buflen, io)) >= 0) {
lineno++;
// strip whitespace and endlines off end of string.
while ((len > 0) && (cfgIsSpace(buffer[len-1]))) {
buffer[--len] = '\0';
}
//printf("CFG: fname=%s line=%d text=%s\n", fname, lineno, buffer);
#define SKIPSPACE() while (cfgIsSpace(*ptr)) { ptr++; }
char *ptr = buffer;
SKIPSPACE();
if ((*ptr == '\0') || (*ptr == ';') || (*ptr == '#') || ((ptr[0] == '/') && (ptr[1] == '/'))) {
//printf("CFG: comment or blank line\n");
continue; // it's a comment or blank line, skip it.
}
const char *category = ptr;
while (cfgIsSymChar(*ptr)) { ptr++; }
if (*ptr != '.') {
cfgWarn(fname, lineno, "Invalid configuration line");
continue;
}
*(ptr++) = '\0';
const char *var = ptr;
while (cfgIsSymChar(*ptr)) { ptr++; }
if (*ptr == '=') {
*(ptr++) = '\0';
} else if (!cfgIsSpace(*ptr)) {
cfgWarn(fname, lineno, "Invalid configuration line");
continue;
} else {
*(ptr++) = '\0';
SKIPSPACE();
if (*ptr != '=') {
cfgWarn(fname, lineno, "Invalid configuration line");
continue;
}
ptr++;
}
SKIPSPACE();
const char *val = ptr;
#undef SKIPSPACE
cfgProcessLine(fname, lineno, category, var, val);
}
free(buffer);
fclose(io);
}
static void cfgLoadFiles(void)
{
cfgLoad("/etc/2ine.cfg");
// optionally override or add config from user's config dir.
char *fname = NULL;
const char *env = getenv("XDG_CONFIG_HOME");
if (env) {
const size_t buflen = strlen(env) + 32;
fname = (char *) malloc(buflen);
if (fname) {
snprintf(fname, buflen, "%s/2ine/2ine.cfg", env);
}
} else {
env = getenv("HOME");
if (env) {
const size_t buflen = strlen(env) + 32;
fname = (char *) malloc(buflen);
if (fname) {
snprintf(fname, buflen, "%s/.config/2ine/2ine.cfg", env);
}
}
}
if (fname) {
cfgLoad(fname);
free(fname);
}
}
LX_NATIVE_CONSTRUCTOR(lib2ine)
{
if (pthread_key_create(&tlskey, NULL) != 0) {
@@ -371,6 +556,8 @@ LX_NATIVE_CONSTRUCTOR(lib2ine)
GLoaderState.makeUnixPath = makeUnixPath_lib2ine;
GLoaderState.terminate = terminate_lib2ine;
cfgLoadFiles();
struct rlimit rlim;
if (getrlimit(RLIMIT_STACK, &rlim) == -1) {
rlim.rlim_cur = 8 * 1024 * 1024; // oh well.
@@ -378,6 +565,7 @@ LX_NATIVE_CONSTRUCTOR(lib2ine)
GLoaderState.initOs2Tib(GLoaderState.main_tibspace, &rlim, rlim.rlim_cur, 0); // hopefully that's close enough on the stack address.
GLoaderState.main_tib_selector = GLoaderState.setOs2Tib(GLoaderState.main_tibspace);
// these override config files (for now).
if (getenv("TRACE_NATIVE")) {
GLoaderState.trace_native = 1;
}
@@ -395,12 +583,14 @@ LX_NATIVE_CONSTRUCTOR(lib2ine)
LX_NATIVE_DESTRUCTOR(lib2ine)
{
int i;
for (i = 0; i < (sizeof (GLoaderState.drives) / sizeof (GLoaderState.drives[0])); i++) {
free(GLoaderState.drives[i]);
}
free(GLoaderState.pib.pib_pchenv);
memset(&GLoaderState, '\0', sizeof (GLoaderState));
pthread_key_delete(tlskey);
}
// end of lib2ine.c ...
+1
View File
@@ -288,6 +288,7 @@ typedef struct LxLoaderState
int running;
int trace_native;
int trace_events;
char *drives[26]; // mount points, A: through Z: ... NULL if unmounted.
uint8 main_tib_selector;
uint32 mainstacksize;
uint16 original_cs;