mirror of https://github.com/merbanan/rtl_433.git
164 lines
3.7 KiB
C
164 lines
3.7 KiB
C
/** @file
|
|
Light-weight (i.e. dumb) config-file parser.
|
|
|
|
- a valid config line is a keyword followed by an argument to the end of line
|
|
- whitespace around the keyword is ignored
|
|
- comments start with a hash sign, no inline comments, empty lines are ok.
|
|
- whitespace is space and tab
|
|
|
|
Copyright (C) 2018 Christian W. Zuckschwerdt <zany@triq.net>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include "confparse.h"
|
|
#include "fatal.h"
|
|
|
|
#ifdef _WIN32
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
#ifdef _MSC_VER
|
|
#define F_OK 0
|
|
#define R_OK (1<<2)
|
|
#endif
|
|
#endif
|
|
#ifndef _MSC_VER
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
static off_t fsize(const char *path)
|
|
{
|
|
struct stat st;
|
|
if (stat(path, &st) == 0)
|
|
return st.st_size;
|
|
|
|
return -1;
|
|
}
|
|
|
|
int hasconf(char const *path)
|
|
{
|
|
return !access(path, R_OK);
|
|
}
|
|
|
|
char *readconf(char const *path)
|
|
{
|
|
FILE *fp;
|
|
char *conf;
|
|
off_t file_size = fsize(path);
|
|
|
|
if (file_size < 0) {
|
|
fprintf(stderr, "Failed to stat \"%s\"\n", path);
|
|
return NULL;
|
|
}
|
|
|
|
fp = fopen(path, "rb");
|
|
if (fp == NULL) {
|
|
fprintf(stderr, "Failed to open \"%s\"\n", path);
|
|
return NULL;
|
|
}
|
|
|
|
conf = malloc(file_size + 1);
|
|
if (!conf) {
|
|
WARN_MALLOC("readconf()");
|
|
fprintf(stderr, "Failed to allocate memory for \"%s\"\n", path);
|
|
fclose(fp);
|
|
return NULL;
|
|
}
|
|
|
|
off_t n_read = fread(conf, sizeof(char), file_size, fp);
|
|
fclose(fp);
|
|
if (n_read != file_size) {
|
|
fprintf(stderr, "Failed to read \"%s\"\n", path);
|
|
free(conf);
|
|
return NULL;
|
|
}
|
|
conf[file_size] = '\0';
|
|
|
|
return conf;
|
|
}
|
|
|
|
int getconf(char **conf, struct conf_keywords const keywords[], char **arg)
|
|
{
|
|
// abort if no conf or EOF
|
|
if (!conf || !*conf || !**conf)
|
|
return -1;
|
|
|
|
char *p = *conf;
|
|
|
|
// skip whitespace and comments
|
|
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == '#')
|
|
if (*p++ == '#') {
|
|
while (*p && *p != '\r' && *p != '\n') p++;
|
|
}
|
|
|
|
// abort if EOF
|
|
if (!*p)
|
|
return -1;
|
|
|
|
// parse keyword
|
|
char *kw = p;
|
|
while (*p && *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n')
|
|
p++;
|
|
if (*p)
|
|
*p++ = '\0';
|
|
|
|
// parse arg
|
|
while (*p == ' ' || *p == '\t')
|
|
p++;
|
|
char *ka = p;
|
|
if (*p == '{') { // quoted
|
|
ka = ++p;
|
|
while (*p) { // skip to end-quote
|
|
while (*p && *p != '}')
|
|
p++;
|
|
char *e = p; // possible end-quote
|
|
if (*p)
|
|
p++;
|
|
// skip ws
|
|
while (*p == ' ' || *p == '\t')
|
|
p++;
|
|
// check if proper end-quote
|
|
if (!*p || *p == '\r' || *p == '\n' || *p == '#') {
|
|
*e = '\0';
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else { // not quoted
|
|
// find end of arg/eol
|
|
while (*p && *p != '\r' && *p != '\n' && *p != '#')
|
|
p++;
|
|
// skip eol comments
|
|
if (*p == '#') {
|
|
*p++ = '\0';
|
|
while (*p && *p != '\r' && *p != '\n')
|
|
p++;
|
|
}
|
|
if (*p)
|
|
*p++ = '\0';
|
|
}
|
|
|
|
// set OUT vars
|
|
if (arg)
|
|
*arg = ka;
|
|
*conf = p;
|
|
|
|
// decode keyword
|
|
for (; keywords->keyword; keywords++) {
|
|
if (!strcmp(keywords->keyword, kw)) {
|
|
return keywords->key;
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "Unknown keyword \"%s\"\n", kw);
|
|
return '?';
|
|
}
|