preparing for the smarter config file writer

pull/68/head
John Tsiombikas 2022-03-12 10:09:37 +02:00
rodzic 8f062901b0
commit 3cfc60b80e
1 zmienionych plików z 134 dodań i 18 usunięć

Wyświetl plik

@ -21,11 +21,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "cfgfile.h"
#include "logger.h"
#include "spnavd.h"
/* all parsable config options... some of them might map to the same cfg field */
enum {
CFG_REPEAT,
CFG_DEADZONE,
CFG_DEADZONE_TX, CFG_DEADZONE_TY, CFG_DEADZONE_TZ,
CFG_DEADZONE_RX, CFG_DEADZONE_RY, CFG_DEADZONE_RZ,
CFG_SENS,
CFG_SENS_TRANS, CFG_SENS_TX, CFG_SENS_TY, CFG_SENS_TZ,
CFG_SENS_ROT, CFG_SENS_RX, CFG_SENS_RY, CFG_SENS_RZ,
CFG_INVROT, CFG_INVTRANS, CFG_SWAPYZ,
CFG_AXISMAP_N, CFG_BNMAP_N, CFG_BNACT_N, CFG_KBMAP_N,
CFG_LED, CFG_GRAB,
CFG_SERIAL, CFG_DEVID,
NUM_CFG_OPTIONS
};
static int parse_bnact(const char *s);
enum {TX, TY, TZ, RX, RY, RZ};
@ -33,6 +52,17 @@ enum {TX, TY, TZ, RX, RY, RZ};
static const int def_axmap[] = {0, 2, 1, 3, 5, 4};
static const int def_axinv[] = {0, 1, 1, 0, 1, 1};
struct cfgline {
char *str; /* points where in the cfgbuf this line starts at */
int opt; /* CFG_* item */
int idx;
};
static char *cfgbuf;
static struct cfgline *cfglines;
static int num_lines;
void default_cfg(struct cfg *cfg)
{
int i;
@ -70,6 +100,15 @@ void default_cfg(struct cfg *cfg)
}
}
void unlock_cfgfile(int fd)
{
struct flock flk;
flk.l_type = F_UNLCK;
flk.l_start = flk.l_len = 0;
flk.l_whence = SEEK_SET;
fcntl(fd, F_SETLK, &flk);
}
#define EXPECT(cond) \
do { \
if(!(cond)) { \
@ -80,16 +119,17 @@ void default_cfg(struct cfg *cfg)
int read_cfg(const char *fname, struct cfg *cfg)
{
FILE *fp;
char buf[512];
int i, j, fd;
char buf[512], *ptr;
struct flock flk;
int num_devid = 0;
/*int num_devnames = 0;*/
struct stat st;
default_cfg(cfg);
logmsg(LOG_INFO, "reading config file: %s\n", fname);
if(!(fp = fopen(fname, "r"))) {
if((fd = open(fname, O_RDONLY)) == -1) {
logmsg(LOG_WARNING, "failed to open config file %s: %s. using defaults.\n", fname, strerror(errno));
return -1;
}
@ -98,12 +138,63 @@ int read_cfg(const char *fname, struct cfg *cfg)
flk.l_type = F_RDLCK;
flk.l_start = flk.l_len = 0;
flk.l_whence = SEEK_SET;
while(fcntl(fileno(fp), F_SETLKW, &flk) == -1);
while(fcntl(fd, F_SETLKW, &flk) == -1);
while(fgets(buf, sizeof buf, fp)) {
int isint, isfloat, ival, i, bnidx, axisidx;
/* read the file into cfgbuf */
fstat(fd, &st);
free(cfgbuf);
cfgbuf = 0;
if(!st.st_size || !(cfgbuf = malloc(st.st_size + 1))) {
logmsg(LOG_WARNING, "failed to allocate config file %s buffer (%ld bytes). using defaults.\n", fname, (long)st.st_size);
unlock_cfgfile(fd);
close(fd);
return -1;
}
if(read(fd, cfgbuf, st.st_size) < st.st_size) {
logmsg(LOG_WARNING, "failed to read config file %s: %s. using defaults.\n", fname, strerror(errno));
free(cfgbuf);
cfgbuf = 0;
unlock_cfgfile(fd);
close(fd);
return -1;
}
cfgbuf[st.st_size] = 0;
unlock_cfgfile(fd);
close(fd);
/* count newlines and populate lines array */
num_lines = 0;
ptr = cfgbuf;
for(i=0; i<st.st_size; i++) {
if(*ptr++ == '\n') num_lines++;
}
if(!num_lines) num_lines = 1;
if(!(cfglines = calloc(num_lines, sizeof *cfglines))) {
logmsg(LOG_WARNING, "failed to allocate config lines buffer (%d lines)\n", num_lines);
free(cfgbuf);
cfgbuf = 0;
}
num_lines = 0;
cfglines[num_lines++].str = cfgbuf;
ptr = cfgbuf;
for(i=0; i<st.st_size; i++) {
if(*ptr == '\n') {
*ptr = 0;
cfglines[num_lines++].str = ptr + 1;
}
++ptr;
}
/* parse config file */
for(i=0; i<num_lines; i++) {
int isint, isfloat, ival, bnidx, axisidx;
float fval;
char *endp, *key_str, *val_str, *line = buf;
strncpy(buf, cfglines[i].str, sizeof buf - 1);
buf[sizeof buf - 1] = 0;
while(*line == ' ' || *line == '\t') line++;
if(!*line || *line == '\n' || *line == '\r' || *line == '#') {
@ -126,76 +217,94 @@ int read_cfg(const char *fname, struct cfg *cfg)
isfloat = (endp > val_str);
if(strcmp(key_str, "repeat-interval") == 0) {
cfglines[i].opt = CFG_REPEAT;
EXPECT(isint);
cfg->repeat_msec = ival;
} else if(strcmp(key_str, "dead-zone") == 0) {
cfglines[i].opt = CFG_DEADZONE;
EXPECT(isint);
for(i=0; i<6; i++) {
cfg->dead_threshold[i] = ival;
for(j=0; j<6; j++) {
cfg->dead_threshold[j] = ival;
}
} else if(strcmp(key_str, "dead-zone-translation-x") == 0) {
cfglines[i].opt = CFG_DEADZONE_TX;
EXPECT(isint);
cfg->dead_threshold[0] = ival;
} else if(strcmp(key_str, "dead-zone-translation-y") == 0) {
cfglines[i].opt = CFG_DEADZONE_TY;
EXPECT(isint);
cfg->dead_threshold[1] = ival;
} else if(strcmp(key_str, "dead-zone-translation-z") == 0) {
cfglines[i].opt = CFG_DEADZONE_TZ;
EXPECT(isint);
cfg->dead_threshold[2] = ival;
} else if(strcmp(key_str, "dead-zone-rotation-x") == 0) {
cfglines[i].opt = CFG_DEADZONE_RX;
EXPECT(isint);
cfg->dead_threshold[3] = ival;
} else if(strcmp(key_str, "dead-zone-rotation-y") == 0) {
cfglines[i].opt = CFG_DEADZONE_RY;
EXPECT(isint);
cfg->dead_threshold[4] = ival;
} else if(strcmp(key_str, "dead-zone-rotation-z") == 0) {
cfglines[i].opt = CFG_DEADZONE_RZ;
EXPECT(isint);
cfg->dead_threshold[5] = ival;
} else if(strcmp(key_str, "sensitivity") == 0) {
cfglines[i].opt = CFG_SENS;
EXPECT(isfloat);
cfg->sensitivity = fval;
} else if(strcmp(key_str, "sensitivity-translation") == 0) {
cfglines[i].opt = CFG_SENS_TRANS;
EXPECT(isfloat);
cfg->sens_trans[0] = cfg->sens_trans[1] = cfg->sens_trans[2] = fval;
} else if(strcmp(key_str, "sensitivity-translation-x") == 0) {
cfglines[i].opt = CFG_SENS_TX;
EXPECT(isfloat);
cfg->sens_trans[0] = fval;
} else if(strcmp(key_str, "sensitivity-translation-y") == 0) {
cfglines[i].opt = CFG_SENS_TY;
EXPECT(isfloat);
cfg->sens_trans[1] = fval;
} else if(strcmp(key_str, "sensitivity-translation-z") == 0) {
cfglines[i].opt = CFG_SENS_TZ;
EXPECT(isfloat);
cfg->sens_trans[2] = fval;
} else if(strcmp(key_str, "sensitivity-rotation") == 0) {
cfglines[i].opt = CFG_SENS_ROT;
EXPECT(isfloat);
cfg->sens_rot[0] = cfg->sens_rot[1] = cfg->sens_rot[2] = fval;
} else if(strcmp(key_str, "sensitivity-rotation-x") == 0) {
cfglines[i].opt = CFG_SENS_RX;
EXPECT(isfloat);
cfg->sens_rot[0] = fval;
} else if(strcmp(key_str, "sensitivity-rotation-y") == 0) {
cfglines[i].opt = CFG_SENS_RY;
EXPECT(isfloat);
cfg->sens_rot[1] = fval;
} else if(strcmp(key_str, "sensitivity-rotation-z") == 0) {
cfglines[i].opt = CFG_SENS_RZ;
EXPECT(isfloat);
cfg->sens_rot[2] = fval;
} else if(strcmp(key_str, "invert-rot") == 0) {
cfglines[i].opt = CFG_INVROT;
if(strchr(val_str, 'x')) {
cfg->invert[RX] = !def_axinv[RX];
}
@ -207,6 +316,7 @@ int read_cfg(const char *fname, struct cfg *cfg)
}
} else if(strcmp(key_str, "invert-trans") == 0) {
cfglines[i].opt = CFG_INVTRANS;
if(strchr(val_str, 'x')) {
cfg->invert[TX] = !def_axinv[TX];
}
@ -218,8 +328,9 @@ int read_cfg(const char *fname, struct cfg *cfg)
}
} else if(strcmp(key_str, "swap-yz") == 0) {
int i, swap_yz = 0;
int swap_yz = 0;
cfglines[i].opt = CFG_SWAPYZ;
if(isint) {
swap_yz = ival;
} else {
@ -233,8 +344,8 @@ int read_cfg(const char *fname, struct cfg *cfg)
}
}
for(i=0; i<6; i++) {
cfg->map_axis[i] = swap_yz ? i : def_axmap[i];
for(j=0; j<6; j++) {
cfg->map_axis[j] = swap_yz ? i : def_axmap[j];
}
} else if(sscanf(key_str, "axismap%d", &axisidx) == 1) {
@ -247,6 +358,8 @@ int read_cfg(const char *fname, struct cfg *cfg)
logmsg(LOG_WARNING, "invalid config value for %s, expected a number from 0 to 6\n", key_str);
continue;
}
cfglines[i].opt = CFG_AXISMAP_N;
cfglines[i].idx = axisidx;
cfg->map_axis[axisidx] = ival;
} else if(sscanf(key_str, "bnmap%d", &bnidx) == 1) {
@ -258,6 +371,8 @@ int read_cfg(const char *fname, struct cfg *cfg)
if(cfg->map_button[bnidx] != bnidx) {
logmsg(LOG_WARNING, "warning: multiple mappings for button %d\n", bnidx);
}
cfglines[i].opt = CFG_BNMAP_N;
cfglines[i].idx = bnidx;
cfg->map_button[bnidx] = ival;
} else if(sscanf(key_str, "bnact%d", &bnidx) == 1) {
@ -265,6 +380,8 @@ int read_cfg(const char *fname, struct cfg *cfg)
logmsg(LOG_WARNING, "invalid configuration value for %s, expected a number from 0 to %d\n", key_str, MAX_BUTTONS);
continue;
}
cfglines[i].opt = CFG_BNACT_N;
cfglines[i].idx = bnidx;
if((cfg->bnact[bnidx] = parse_bnact(val_str)) == -1) {
cfg->bnact[bnidx] = BNACT_NONE;
logmsg(LOG_WARNING, "invalid button action: \"%s\"\n", val_str);
@ -276,6 +393,8 @@ int read_cfg(const char *fname, struct cfg *cfg)
logmsg(LOG_WARNING, "invalid configuration value for %s, expected a number from 0 to %d\n", key_str, MAX_BUTTONS);
continue;
}
cfglines[i].opt = CFG_KBMAP_N;
cfglines[i].idx = bnidx;
if(cfg->kbmap_str[bnidx]) {
logmsg(LOG_WARNING, "warning: multiple keyboard mappings for button %d: %s -> %s\n", bnidx, cfg->kbmap_str[bnidx], val_str);
free(cfg->kbmap_str[bnidx]);
@ -283,6 +402,7 @@ int read_cfg(const char *fname, struct cfg *cfg)
cfg->kbmap_str[bnidx] = strdup(val_str);
} else if(strcmp(key_str, "led") == 0) {
cfglines[i].opt = CFG_LED;
if(isint) {
cfg->led = ival;
} else {
@ -299,6 +419,7 @@ int read_cfg(const char *fname, struct cfg *cfg)
}
} else if(strcmp(key_str, "grab") == 0) {
cfglines[i].opt = CFG_GRAB;
if(isint) {
cfg->grab_device = ival;
} else {
@ -313,10 +434,12 @@ int read_cfg(const char *fname, struct cfg *cfg)
}
} else if(strcmp(key_str, "serial") == 0) {
cfglines[i].opt = CFG_SERIAL;
strncpy(cfg->serial_dev, val_str, PATH_MAX - 1);
} else if(strcmp(key_str, "device-id") == 0) {
unsigned int vendor, prod;
cfglines[i].opt = CFG_DEVID;
if(sscanf(val_str, "%x:%x", &vendor, &prod) == 2) {
cfg->devid[num_devid][0] = (int)vendor;
cfg->devid[num_devid][1] = (int)prod;
@ -331,13 +454,6 @@ int read_cfg(const char *fname, struct cfg *cfg)
}
}
/* unlock */
flk.l_type = F_UNLCK;
flk.l_start = flk.l_len = 0;
flk.l_whence = SEEK_SET;
fcntl(fileno(fp), F_SETLK, &flk);
fclose(fp);
return 0;
}