-
Notifications
You must be signed in to change notification settings - Fork 114
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
Add configuration file support. #101
base: master
Are you sure you want to change the base?
Changes from 15 commits
0923929
8db0360
7dc1bef
2f178fa
ce1149b
cfd5e5c
2a9fa07
4123947
c5bae23
06078c2
85e416e
5a514c1
4568540
22ba74c
87a6e5e
60af035
be04a66
9f3bc2c
4b41b7e
736c1ed
f3955c6
c06a0bf
001e7c1
559dce8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ | |
|
||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <ctype.h> | ||
#include <string.h> | ||
#include <sys/time.h> | ||
#include <signal.h> | ||
|
@@ -76,6 +77,8 @@ void *sig_handler (void *user_data); | |
|
||
void intercept (XPointer user_data, XRecordInterceptData *data); | ||
|
||
KeyMap_t *parse_confs (Display *ctrl_conn, char **files, size_t n_confs, Bool debug); | ||
|
||
KeyMap_t *parse_mapping (Display *ctrl_conn, char *mapping, Bool debug); | ||
|
||
void delete_mapping (KeyMap_t *map); | ||
|
@@ -96,7 +99,9 @@ int main (int argc, char **argv) | |
int dummy, ch; | ||
|
||
static char default_mapping[] = "Control_L=Escape"; | ||
char *mapping = default_mapping; | ||
char *mapping = NULL; | ||
char **conf_files = NULL; | ||
size_t n_conf = 0; | ||
|
||
XRecordRange *rec_range = XRecordAllocRange(); | ||
XRecordClientSpec client_spec = XRecordAllClients; | ||
|
@@ -147,9 +152,8 @@ int main (int argc, char **argv) | |
|
||
if (optind < argc) | ||
{ | ||
fprintf (stderr, "Not a command line option: '%s'\n", argv[optind]); | ||
print_usage (argv[0]); | ||
return EXIT_SUCCESS; | ||
conf_files = argv + optind; | ||
n_conf = argc - optind; | ||
} | ||
|
||
if (!XInitThreads ()) | ||
|
@@ -184,12 +188,56 @@ int main (int argc, char **argv) | |
exit (EXIT_FAILURE); | ||
} | ||
|
||
self->map = parse_mapping (self->ctrl_conn, mapping, self->debug); | ||
/* This reduces error-prone logic when rearranging the parsing order, | ||
* as we don't need to check for self->map existence */ | ||
|
||
KeyMap_t **current_map = &self->map; | ||
|
||
/* parse mappings given by -e first */ | ||
|
||
if (self->map == NULL) | ||
if (mapping) | ||
{ | ||
fprintf (stderr, "Failed to parse_mapping\n"); | ||
exit (EXIT_FAILURE); | ||
KeyMap_t *emapping = parse_mapping (self->ctrl_conn, mapping, self->debug); | ||
|
||
if (emapping == NULL) | ||
{ | ||
fprintf (stderr, "Failed to parse_mapping\n"); | ||
exit (EXIT_FAILURE); | ||
} | ||
|
||
*current_map = emapping; | ||
current_map = &(*current_map)->next; | ||
} | ||
|
||
/* parse config files */ | ||
|
||
if (conf_files) | ||
{ | ||
KeyMap_t *conf_mapping = parse_confs (self->ctrl_conn, conf_files, n_conf, self->debug); | ||
|
||
if (conf_mapping == NULL) | ||
{ | ||
fprintf (stderr, "Failed to parse_confs\n"); | ||
exit (EXIT_FAILURE); | ||
} | ||
|
||
*current_map = conf_mapping; | ||
current_map = &(*current_map)->next; | ||
} | ||
|
||
/* if there were no config files or mappings supplied, try the default mapping */ | ||
|
||
if (!conf_files && !mapping) | ||
{ | ||
KeyMap_t *def_mapping = parse_mapping (self->ctrl_conn, default_mapping, self->debug); | ||
|
||
if (def_mapping == NULL) | ||
{ | ||
fprintf (stderr, "Failed to parse_mapping default\n"); | ||
exit (EXIT_FAILURE); | ||
} | ||
|
||
*current_map = def_mapping; | ||
} | ||
|
||
if (self->foreground != True) | ||
|
@@ -438,7 +486,7 @@ KeyMap_t *parse_token (Display *dpy, char *token, Bool debug) | |
errno = 0; | ||
parsed_code = strtoul (from, NULL, 0); /* dec, oct, hex automatically */ | ||
if (errno == 0 | ||
&& parsed_code <=255 | ||
&& parsed_code <= 255 | ||
&& XkbKeycodeToKeysym (dpy, (KeyCode) parsed_code, 0, 0) != NoSymbol) | ||
{ | ||
km->UseKeyCode = True; | ||
|
@@ -538,6 +586,105 @@ KeyMap_t *parse_token (Display *dpy, char *token, Bool debug) | |
return km; | ||
} | ||
|
||
char *read_line (FILE *file) | ||
{ | ||
size_t cap = 1024; | ||
size_t nlen = 0; | ||
char *line = realloc (NULL, cap*sizeof(char)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not malloc? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Woops! I'll fix that right away. |
||
|
||
int c = EOF; | ||
int reading = 1; | ||
while (reading) | ||
{ | ||
c = fgetc(file); | ||
if (nlen == cap) | ||
{ | ||
cap *= 2; | ||
line = realloc (line, cap*sizeof(char)); | ||
} | ||
switch (c) | ||
{ | ||
case '\r': | ||
/* check for \r\n */ | ||
{ | ||
int c = fgetc(file); | ||
if(c != '\n'){ | ||
ungetc(c, file); | ||
} | ||
} | ||
break; | ||
case '\n': /* FALLTHROUGH */ | ||
case '\0': | ||
line[nlen++] = '\0'; | ||
reading = 0; | ||
break; | ||
case EOF: | ||
reading = 0; | ||
break; | ||
default: | ||
line[nlen++] = c; | ||
break; | ||
} | ||
} | ||
if(nlen == 0) | ||
{ | ||
free (line); | ||
return NULL; | ||
} | ||
/* shrink down to size */ | ||
line = realloc (line, nlen); | ||
return line; | ||
} | ||
|
||
KeyMap_t *parse_confs (Display *ctrl_conn, char **files, size_t n_confs, Bool debug) | ||
{ | ||
KeyMap_t *rval = NULL; | ||
KeyMap_t **current = &rval; | ||
for (size_t i = 0; i < n_confs; ++i) | ||
{ | ||
char *filename = files[i]; | ||
FILE *file = NULL; | ||
|
||
/* determine if reading from stdin or file */ | ||
if (!strcmp (filename, "-")) | ||
{ | ||
file = stdin; | ||
} | ||
else | ||
{ | ||
file = fopen (filename, "r"); | ||
if (file == NULL) | ||
{ | ||
fprintf (stderr, "unable to open file %s: %s\n", filename, strerror(errno)); | ||
break; | ||
} | ||
} | ||
|
||
/* Read file line by line, treating each line as an expression */ | ||
char *line = NULL; | ||
while ((line = read_line (file)) != NULL) | ||
{ | ||
/* trim leading whitespace */ | ||
char *trimmed = line; | ||
while(isspace(*trimmed)) ++trimmed; | ||
/* check for comments or empty lines */ | ||
if(*trimmed && *trimmed != '#'){ | ||
*current = parse_token (ctrl_conn, trimmed, debug); | ||
if (*current == NULL) | ||
{ | ||
break; | ||
} | ||
current = &(*current)->next; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. isn't this the same as current = current->next; ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not quite, since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. Could you please add some parenthesis to make it clearer. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done! |
||
} | ||
free (line); | ||
} | ||
|
||
if (file != stdin) | ||
fclose (file); | ||
} | ||
return rval; | ||
} | ||
|
||
KeyMap_t *parse_mapping (Display *ctrl_conn, char *mapping, Bool debug) | ||
{ | ||
char *token; | ||
|
@@ -589,6 +736,6 @@ void delete_keys (Key_t *keys) | |
|
||
void print_usage (const char *program_name) | ||
{ | ||
fprintf (stdout, "Usage: %s [-d] [-f] [-t timeout_ms] [-e <mapping>]\n", program_name); | ||
fprintf (stdout, "Usage: %s [file ...] [-d] [-f] [-t timeout_ms] [-e <mapping>]\n", program_name); | ||
fprintf (stdout, "Runs as a daemon unless -d or -f flag is set\n"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer if we used an option prefix. Since -f is taken I suggest using -F. And an additional -F for every extra file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another idea is to use -c for "config"