bump to version 0.2

- better recognition of invalid config files
- general polish of error messages
- hkd follows the rule of silence
- when using -v the correct key names are shown
- commands in config files can be multiline (using \\n)
xkbcommon
Alessandro Mauri 4 years ago
parent 344887c925
commit 1ba688f975
  1. 4
      hkd.1
  2. 167
      hkd.c
  3. 2
      makefile

@ -89,10 +89,6 @@ This is a valid config file example
.PP .PP
Known bugs are: Known bugs are:
.IP - .IP -
Commands in the config file cannot be multiline
.IP -
Invalid config files are not detected properly, or at least not explicitly
.IP -
Child processes Child processes
are waited at program exit possibly causing the process tree to hang as there is are waited at program exit possibly causing the process tree to hang as there is
no real child process control no real child process control

167
hkd.c

@ -228,8 +228,8 @@ int is_empty (const char *s);
/* hotkey list operations */ /* hotkey list operations */
void hotkey_list_add (struct hotkey_list_e *, struct key_buffer *, char *, int); void hotkey_list_add (struct hotkey_list_e *, struct key_buffer *, char *, int);
void hotkey_list_destroy (struct hotkey_list_e *); void hotkey_list_destroy (struct hotkey_list_e *);
void hotkey_list_append_command (struct hotkey_list_e *, char *);
// TODO: use getopts() to parse command line options
int main (int argc, char *argv[]) int main (int argc, char *argv[])
{ {
/* Handle SIGINT */ /* Handle SIGINT */
@ -414,6 +414,10 @@ void int_handler (int signum)
{ {
switch (signum) { switch (signum) {
case SIGINT: case SIGINT:
if (dead) {
fprintf(stderr, red("an error occured, exiting\n"));
exit(EXIT_FAILURE);
}
if (vflag) if (vflag)
printf(yellow("Received interrupt signal, exiting gracefully...\n")); printf(yellow("Received interrupt signal, exiting gracefully...\n"));
dead = 1; dead = 1;
@ -437,7 +441,7 @@ void exec_command (char *command)
return; return;
default: default:
/* Some other error */ /* Some other error */
fprintf(stderr, "Could not parse, %s is not valid", command); fprintf(stderr, "Could not parse, %s is not valid\n", command);
return; return;
} }
@ -600,6 +604,20 @@ void hotkey_list_add (struct hotkey_list_e *head, struct key_buffer *kb, char *c
hotkey_list = tmp; hotkey_list = tmp;
} }
void hotkey_list_append_command (struct hotkey_list_e *head, char *cmd)
{
char *tmp;
if (!head)
return;
while (head->next)
head = head->next;
tmp = realloc(head->command, sizeof(head->command) + strlen(cmd) + 1);
if (!tmp)
die("realloc in hotkey_list_append_command()");
head->command = tmp;
strcat(head->command, cmd);
}
void parse_config_file (void) void parse_config_file (void)
{ {
wordexp_t result = {0}; wordexp_t result = {0};
@ -650,6 +668,7 @@ void parse_config_file (void)
die("could not open any config files, check the log for more details"); die("could not open any config files, check the log for more details");
} }
int iscmd = 0;
struct key_buffer kb; struct key_buffer kb;
for (int linenum = 1;; linenum++) { for (int linenum = 1;; linenum++) {
int fuzzy = 0, tmp; int fuzzy = 0, tmp;
@ -659,6 +678,8 @@ void parse_config_file (void)
if (getline(&line, &linelen, fd) == -1) if (getline(&line, &linelen, fd) == -1)
break; break;
linelen = strlen(line);
if (linelen < 2) if (linelen < 2)
continue; continue;
@ -671,72 +692,106 @@ void parse_config_file (void)
} }
// Skip comments and blank lines // Skip comments and blank lines
if (line[0] == '#' || !line[0]) { if (line[0] == '#' || !line[0])
free(linebegin); goto parse_end_free;
continue;
}
for (size_t i = 1; i < linelen; i++) { for (size_t i = 1; i < linelen; i++) {
if (line[i] == '#') if (line[i] == '#')
line[i] = '\0'; line[i] = '\0';
} }
if (!iscmd) {
if (line[0] != '-' && line[0] != '*') {
fprintf(stderr, red("Error at line %d: "
"Hotkey definitions must start with '*' or '-'\n"), linenum);
exit(EXIT_FAILURE);
}
// TODO: multiline commands, ending with "\\n" if (line[0] == '*')
if (line[0] == '*') fuzzy = 1;
fuzzy = 1;
line = &line[1];
linelen--;
// Remove leading spaces
while (isspace(line[0]) && linelen > 1) {
line = &line[1]; line = &line[1];
linelen--; linelen--;
} // Remove leading spaces
keys = strtok(line, ":"); while (isspace(line[0]) && linelen > 1) {
command = strtok(NULL, ":"); line = &line[1];
if (!command || !keys) { linelen--;
fprintf(stderr, "Error at line %d:" }
"No command or keys specified\n", linenum); keys = strtok(line, ":");
exit(EXIT_FAILURE); command = strtok(NULL, ":");
} if (!command || !keys) {
fprintf(stderr, red("Error at line %d: "
"No command or keys specified\n"), linenum);
exit(EXIT_FAILURE);
}
// Check if keys and command are not blank
if (is_empty(keys) || is_empty(command)) {
fprintf(stderr, red("Error at line %d: "
"command or keys not present\n"), linenum);
exit(EXIT_FAILURE);
}
// Remove whitespaces in keys // Remove whitespaces in keys
tmp = strlen(keys); tmp = strlen(keys);
for (int i = 0; i < tmp; i++) { for (int i = 0; i < tmp; i++) {
if (isspace(keys[i])) { if (isspace(keys[i]))
memmove(&line[i], &line[i + 1], --tmp); memmove(&line[i], &line[i + 1], --tmp);
} }
}
// Remove leading and trailing spaces in command // Remove leading and trailing spaces in command
tmp = strlen(command); tmp = strlen(command);
while (isspace(command[0]) && tmp > 1) { while (isspace(command[0]) && tmp > 1) {
command = &command[1]; command = &command[1];
tmp--; tmp--;
} }
tmp = strlen(command) - 1; for (tmp = strlen(command) - 1; isspace(command[tmp]); tmp--) {
while (isspace(command[tmp])) if (isblank(command[tmp]))
command[tmp--] = '\0'; command[tmp] = '\0';
}
// Check if keys and command are not blank
if (is_empty(keys) || is_empty(command)) {
fprintf(stderr, red("Error at line %d: "
"command or keys not present\n"), linenum);
exit(EXIT_FAILURE);
}
key_buffer_reset(&kb); if (command[strlen(command) - 2] == '\\') {
char *k = strtok(keys, ","); iscmd = 1;
unsigned short kc; } else {
do { iscmd = 0;
if (!(kc = key_to_code(k))) { tmp = strlen(command) - 1;
fprintf(stderr, "Error at line %d:" while (isspace(command[tmp]))
"%s is not a valid key", linenum, k); command[tmp--] = '\0';
exit(EXIT_FAILURE); }
key_buffer_reset(&kb);
char *k = strtok(keys, ",");
unsigned short kc;
do {
if (!(kc = key_to_code(k))) {
fprintf(stderr, red("Error at line %d: "
"%s is not a valid key"), linenum, k);
exit(EXIT_FAILURE);
}
key_buffer_add(&kb, kc);
} while ((k = strtok(NULL, ",")));
hotkey_list_add(hotkey_list, &kb, command, fuzzy);
hotkey_size_mask |= 1 << (kb.size - 1);
key_buffer_reset(&kb);
} else {
for (tmp = strlen(line) - 1; isspace(line[tmp]); tmp--) {
if (isblank(line[tmp]))
line[tmp] = '\0';
} }
key_buffer_add(&kb, kc); linelen = strlen(line);
} while ((k = strtok(NULL, ",")));
hotkey_list_add(hotkey_list, &kb, command, fuzzy); // if line is blank skip
hotkey_size_mask |= 1 << (kb.size - 1); if (is_empty(line))
key_buffer_reset(&kb); goto parse_end_free;
if (line[linelen - 2] == '\\') {
iscmd = 1;
} else {
iscmd = 0;
while (isspace(line[linelen - 1]))
line[--linelen] = '\0';
}
hotkey_list_append_command(hotkey_list, line);
}
parse_end_free:
free(linebegin);
} }
} }

@ -1,6 +1,6 @@
CC = gcc CC = gcc
CFLAGS = -Wall -Werror -pedantic --std=c99 -O2 CFLAGS = -Wall -Werror -pedantic --std=c99 -O2
VERSION = 0.1 VERSION = 0.2
PREFIX = /usr/local PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man MANPREFIX = ${PREFIX}/share/man

Loading…
Cancel
Save