summaryrefslogtreecommitdiff
path: root/config.c
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-12-30 13:49:01 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-12-30 13:49:01 -0500
commit3d56cc1986f855f91844915e35d0225bd8e07109 (patch)
tree0ab06288e6a4d699b55b68931487e5a6ab889c3f /config.c
parentf10f07553e599f1320afbaa2dfeb0b267139cd74 (diff)
more config
Diffstat (limited to 'config.c')
-rw-r--r--config.c158
1 files changed, 153 insertions, 5 deletions
diff --git a/config.c b/config.c
index 8218399..1bf6d70 100644
--- a/config.c
+++ b/config.c
@@ -12,10 +12,124 @@ typedef enum {
SECTION_KEYBOARD
} Section;
+// Returns the key combination described by str. filename and line_number should be passed inm to generate nice errors.
+static u32 config_parse_key_combo(Ted *ted, char const *str, char const *filename, uint line_number) {
+ u32 modifier = 0;
+ // read modifier
+ while (true) {
+ if (util_is_prefix(str, "Ctrl+")) {
+ if (modifier & KEY_MODIFIER_CTRL) {
+ ted_seterr(ted, "%s:%u: Ctrl+ written twice", filename, line_number);
+ return 0;
+ }
+ modifier |= KEY_MODIFIER_CTRL;
+ str += strlen("Ctrl+");
+ } else if (util_is_prefix(str, "Shift+")) {
+ if (modifier & KEY_MODIFIER_SHIFT) {
+ ted_seterr(ted, "%s:%u: Shift+ written twice", filename, line_number);
+ return 0;
+ }
+ modifier |= KEY_MODIFIER_SHIFT;
+ str += strlen("Shift+");
+ } else if (util_is_prefix(str, "Alt+")) {
+ if (modifier & KEY_MODIFIER_ALT) {
+ ted_seterr(ted, "%s:%u: Alt+ written twice", filename, line_number);
+ return 0;
+ }
+ modifier |= KEY_MODIFIER_ALT;
+ str += strlen("Alt+");
+ } else break;
+ }
+
+ // read key
+ SDL_Scancode scancode = SDL_GetScancodeFromName(str);
+ if (scancode == SDL_SCANCODE_UNKNOWN) {
+ typedef struct {
+ char const *keyname1;
+ char const *keyname2; // alternate key name
+ SDL_Scancode scancode;
+ bool shift;
+ } KeyName;
+ static KeyName const key_names[] = {
+ {"Apostrophe", "Single Quote", SDL_SCANCODE_APOSTROPHE, 0},
+ {"Backslash", 0, SDL_SCANCODE_BACKSLASH, 0},
+ {"Comma", 0, SDL_SCANCODE_COMMA, 0},
+ {"Equals", 0, SDL_SCANCODE_EQUALS, 0},
+ {"Grave", "Backtick", SDL_SCANCODE_GRAVE, 0},
+ {"Keypad Plus", 0, SDL_SCANCODE_KP_PLUS, 0},
+ {"Keypad Minus", 0, SDL_SCANCODE_KP_MINUS, 0},
+ {"Keypad Divide", 0, SDL_SCANCODE_KP_DIVIDE, 0},
+ {"Keypad Multiply", 0, SDL_SCANCODE_KP_MULTIPLY, 0},
+ {"Left Bracket", 0, SDL_SCANCODE_LEFTBRACKET, 0}, // [
+ {"Right Bracket", 0, SDL_SCANCODE_RIGHTBRACKET, 0}, // ]
+ {"Dash", 0, SDL_SCANCODE_MINUS, 0},
+ {"Minus", 0, SDL_SCANCODE_MINUS, 0},
+ {"Period", 0, SDL_SCANCODE_PERIOD, 0},
+ {"Semicolon", 0, SDL_SCANCODE_SEMICOLON, 0},
+ {"Slash", 0, SDL_SCANCODE_SLASH, 0},
+ {"Exclaim", "Exclamation Mark", SDL_SCANCODE_1, 1},
+ {"!", 0, SDL_SCANCODE_1, 1},
+ {"At", "@", SDL_SCANCODE_2, 1},
+ {"Hash", "#", SDL_SCANCODE_3, 1},
+ {"Dollar", "$", SDL_SCANCODE_4, 1},
+ {"Percent", "%", SDL_SCANCODE_5, 1},
+ {"Caret", "^", SDL_SCANCODE_6, 1},
+ {"Ampersand", "&", SDL_SCANCODE_7, 1},
+ {"Asterisk", "*", SDL_SCANCODE_8, 1},
+ {"Left Paren", "(", SDL_SCANCODE_9, 1},
+ {"Right Paren", ")", SDL_SCANCODE_0, 1},
+ {"Underscore", "_", SDL_SCANCODE_MINUS, 1},
+ {"Plus", "+", SDL_SCANCODE_EQUALS, 1},
+ {"Left Brace", "{", SDL_SCANCODE_LEFTBRACKET, 1},
+ {"Right Brace", "}", SDL_SCANCODE_RIGHTBRACKET, 1},
+ {"Pipe", "|", SDL_SCANCODE_BACKSLASH, 1},
+ {"Colon", ":", SDL_SCANCODE_SEMICOLON, 1},
+ {"Double Quote", "\"", SDL_SCANCODE_APOSTROPHE, 1},
+ {"Less Than", "<", SDL_SCANCODE_COMMA, 1},
+ {"Greater Than", ">", SDL_SCANCODE_PERIOD, 1},
+ {"Question Mark", "?", SDL_SCANCODE_SLASH, 1},
+ {"Question", 0, SDL_SCANCODE_SLASH, 1},
+ {"Tilde", "~", SDL_SCANCODE_GRAVE, 1}
+ };
+
+ // @OPTIMIZE: sort key_names; do a binary search
+ for (size_t i = 0; i < arr_count(key_names); ++i) {
+ KeyName const *k = &key_names[i];
+ if (streq(str, k->keyname1) || (k->keyname2 && streq(str, k->keyname2))) {
+ scancode = k->scancode;
+ if (k->shift) {
+ if (modifier & KEY_MODIFIER_SHIFT) {
+ ted_seterr(ted, "%s:%u: Shift+%s is redundant.", filename, line_number, str);
+ return 0;
+ }
+ modifier |= KEY_MODIFIER_SHIFT;
+ }
+ break;
+ }
+ }
+ if (scancode == SDL_SCANCODE_UNKNOWN) {
+ if (isdigit(str[0])) { // direct scancode numbers, e.g. Ctrl+24 or Ctrl+08
+ char *endp;
+ long n = strtol(str, &endp, 10);
+ if (*endp == '\0' && n > 0 && n < SCANCODE_COUNT) {
+ scancode = (SDL_Scancode)n;
+ } else {
+ ted_seterr(ted, "%s:%u: Invalid scancode number: %s", filename, line_number, str);
+ return 0;
+ }
+ } else {
+ ted_seterr(ted, "%s:%u: Unrecognized key name: %s.", filename, line_number, str);
+ return 0;
+ }
+ }
+ }
+ return (u32)scancode << 3 | modifier;
+}
+
void config_read(Ted *ted, char const *filename) {
FILE *fp = fopen(filename, "rb");
if (fp) {
- u32 line_number = 1;
+ uint line_number = 1;
int line_cap = 4096;
char *line = ted_malloc(ted, (size_t)line_cap);
if (line) {
@@ -37,10 +151,10 @@ void config_read(Ted *ted, char const *filename) {
#define SECTION_HEADER_HELP "Section headers should look like this: [section-name]"
char *closing = strchr(line, ']');
if (!closing) {
- ted_seterr(ted, "%s:" U32_FMT ": Unmatched [. " SECTION_HEADER_HELP, filename, line_number);
+ ted_seterr(ted, "%s:%u: Unmatched [. " SECTION_HEADER_HELP, filename, line_number);
error = true;
} else if (closing[1] != '\0') {
- ted_seterr(ted, "%s:" U32_FMT ": Text after section. " SECTION_HEADER_HELP, filename, line_number);
+ ted_seterr(ted, "%s:%u: Text after section. " SECTION_HEADER_HELP, filename, line_number);
error = true;
} else {
*closing = '\0';
@@ -48,18 +162,52 @@ void config_read(Ted *ted, char const *filename) {
if (streq(section_name, "keyboard")) {
section = SECTION_KEYBOARD;
} else {
- ted_seterr(ted, "%s:" U32_FMT ": Unrecognized section: [%s].", filename, line_number, section_name);
+ ted_seterr(ted, "%s:%u: Unrecognized section: [%s].", filename, line_number, section_name);
error = true;
}
}
} break;
+ default: {
+ char *equals = strchr(line, '=');
+ if (equals) {
+ char *key = line;
+ *equals = '\0';
+ char *value = key + 1;
+ while (isspace(*key)) ++key;
+ while (isspace(*value)) ++value;
+ if (equals != line) {
+ for (char *p = equals - 1; p > line; --p) {
+ // remove trailing spaces after key
+ if (isspace(*p)) *p = '\0';
+ else break;
+ }
+ }
+ if (key[0] == '\0') {
+ ted_seterr(ted, "%s:%u: Empty property name. This line should look like: key = value", filename, line_number);
+ } else {
+ switch (section) {
+ case SECTION_NONE:
+ ted_seterr(ted, "%s:%u: Line outside of any section."
+ "Try putting a section header, e.g. [keyboard] before this line?", filename, line_number);
+ break;
+ case SECTION_KEYBOARD: {
+ u32 key_combo = config_parse_key_combo(ted, key, filename, line_number);
+ (void)key_combo; // @TODO
+ } break;
+ }
+ }
+ } else {
+ ted_seterr(ted, "%s:%u: Invalid line syntax."
+ "Lines should either look like [section-name] or key = value", filename, line_number);
+ }
+ } break;
}
if (error) break;
++line_number;
} else {
- ted_seterr(ted, "%s:" U32_FMT ": Line is too long.", filename, line_number);
+ ted_seterr(ted, "%s:%u: Line is too long.", filename, line_number);
break;
}
}