diff options
Diffstat (limited to 'src/parser.c')
-rw-r--r-- | src/parser.c | 342 |
1 files changed, 198 insertions, 144 deletions
diff --git a/src/parser.c b/src/parser.c index 4eca3c2..ae22651 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 200809L /* for strdup */ #include <ctype.h> #include <linux/limits.h> #include <stdio.h> @@ -8,204 +9,257 @@ #include <X11/keysymdef.h> #include "parser.h" +#define MAX_LINE 512 -static struct { const char *n; void (*fn)(void); } call_table[] = { - {"close_window", close_focused}, - {"decrease_gaps", dec_gaps}, - {"focus_next", focus_next}, - {"focus_previous", focus_prev}, - {"increase_gaps", inc_gaps}, - {"master_next", move_master_next}, - {"master_previous", move_master_prev}, - {"quit", quit}, - {"reload_config", reload_config}, - {"master_increase", resize_master_add}, - {"master_decrease", resize_master_sub}, - {"floating", toggle_floating}, - {"global_floating", toggle_floating_global}, - {"fullscreen", toggle_fullscreen}, +static const struct { const char *name; void (*fn)(void); } call_table[] = { + { "close_window", close_focused }, + { "decrease_gaps", dec_gaps }, + { "focus_next", focus_next }, + { "focus_previous", focus_prev }, + { "increase_gaps", inc_gaps }, + { "master_next", move_master_next }, + { "master_previous", move_master_prev }, + { "quit", quit }, + { "reload_config", reload_config }, + { "master_increase", resize_master_add }, + { "master_decrease", resize_master_sub }, + { "toggle_floating", toggle_floating }, + { "global_floating", toggle_floating_global }, + { "fullscreen", toggle_fullscreen }, { NULL, NULL } }; +/* helpers */ +static char* +strip(char *s) +{ + while (isspace((unsigned char)*s)) s++; + if (!*s) return s; + char *end = s + strlen(s) - 1; + while (end > s && isspace((unsigned char)*end)) *end-- = '\0'; + return s; +} + +static char* +strip_quotes(char *s) +{ + size_t len = strlen(s); + if (len > 0 && s[0] == '"') { + s++; + len--; + } + if (len > 0 && s[len-1] == '"') { + s[len-1] = '\0'; + } + return s; +} + +static const char** build_argv(char *cmdline) +{ + char **argv = calloc(MAX_ARGS + 1, sizeof(char *)); + if (!argv) return NULL; + + int argc = 0; + char *tok = strtok(cmdline, " \t"); + while (tok && argc < MAX_ARGS) { + argv[argc++] = strdup(tok); + tok = strtok(NULL, " \t"); + } + argv[argc] = NULL; + return (const char **)argv; +} + +unsigned int +parse_mods(const char *mods, Config *user_config) +{ + unsigned int m = 0; + char buf[MAX_LINE]; + strncpy(buf, mods, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + + for (char *tok = strtok(buf, "+"); tok; tok = strtok(NULL, "+")) { + for (char *p = tok; *p; p++) *p = tolower((unsigned char)*p); + if (strcmp(tok, "mod") == 0) m |= user_config->modkey; + else if (strcmp(tok, "shift") == 0) m |= ShiftMask; + else if (strcmp(tok, "ctrl") == 0) m |= ControlMask; + else if (strcmp(tok, "alt") == 0) m |= Mod1Mask; + else if (strcmp(tok, "super") == 0) m |= Mod4Mask; + } + return m; +} + +KeySym +parse_keysym(const char *key) +{ + char buf[64]; + size_t len = strlen(key); + if (len >= sizeof(buf)) len = sizeof(buf) - 1; + + if (len == 1) { + buf[0] = key[0]; + buf[1] = '\0'; + } else { + buf[0] = toupper((unsigned char)key[0]); + for (size_t i = 1; i < len; i++) + buf[i] = tolower((unsigned char)key[i]); + buf[len] = '\0'; + } + + KeySym ks = XStringToKeysym(buf); + if (ks == NoSymbol) { + for (size_t i = 0; i < len; i++) + buf[i] = toupper((unsigned char)key[i]); + buf[len] = '\0'; + ks = XStringToKeysym(buf); + } + if (ks == NoSymbol) + fprintf(stderr, "sxwmrc: unknown keysym '%s'\n", key); + return ks; +} + void -handler(char *command, char *arg, - unsigned int mods, KeySym keysym, - Action action, Bool is_func, - Config *user_config) +handler(char *command, char *arg, int mods, KeySym keysym, Action action, + Bool is_func, Config *user_config) { if (strcmp(command, "bind") == 0) { + /* check if binding already exists */ + int slot = user_config->bindsn; + for (int i = 0; i < user_config->bindsn; i++) { + if (user_config->binds[i].mods == mods && + user_config->binds[i].keysym == keysym) { + slot = i; + break; + } + } + + if (slot == user_config->bindsn) + user_config->bindsn++; + + Binding *b = &user_config->binds[slot]; + b->mods = mods; + b->keysym = keysym; + b->is_func = is_func; + if (is_func) { - /* look up function by name */ - for (unsigned long i = 0; i < LENGTH(call_table); ++i) { - if (strcmp(arg, call_table[i].n) == 0) { - user_config->binds[user_config->bindsn].action.fn = call_table[i].fn; - user_config->binds[user_config->bindsn].is_func = True; - user_config->binds[user_config->bindsn].mods = mods; - user_config->binds[user_config->bindsn].keysym = keysym; - ++user_config->bindsn; - return; + for (size_t j = 0; call_table[j].name; j++) { + if (strcmp(arg, call_table[j].name) == 0) { + b->action.fn = call_table[j].fn; + break; } } - fprintf(stderr, "sxwmrc: unknown function call: %s\n", arg); } else { - user_config->binds[user_config->bindsn].action.cmd = action.cmd; - user_config->binds[user_config->bindsn].is_func = False; - user_config->binds[user_config->bindsn].mods = mods; - user_config->binds[user_config->bindsn].keysym = keysym; - ++user_config->bindsn; + b->action.cmd = action.cmd; } return; } - /* TODO USE A TABLE */ - if (strcmp(command, "gaps") == 0) user_config->gaps = atoi(arg); - else if (strcmp(command, "border_width") == 0) user_config->border_width = atoi(arg); - else if (strcmp(command, "focus_border_colour") == 0) user_config->border_foc_col = parse_col(arg); - else if (strcmp(command, "unfocus_border_colour")== 0) user_config->border_ufoc_col = parse_col(arg); - else if (strcmp(command, "swap_border_colour") == 0) user_config->border_swap_col = parse_col(arg); - else if (strcmp(command, "master_coverage") == 0) user_config->master_width = atoi(arg); - else if (strcmp(command, "resize_master_amount") == 0) user_config->resize_master_amt = atoi(arg); - else if (strcmp(command, "snap_distance") == 0) user_config->snap_distance = atoi(arg); + if (strcmp(command, "gaps") == 0) user_config->gaps = atoi(arg); + else if (strcmp(command, "border_width") == 0) user_config->border_width = atoi(arg); + else if (strcmp(command, "focused_border_colour") == 0) user_config->border_foc_col = parse_col(arg); + else if (strcmp(command, "unfocused_border_colour") == 0) user_config->border_ufoc_col = parse_col(arg); + else if (strcmp(command, "swap_border_colour") == 0) user_config->border_swap_col = parse_col(arg); + else if (strcmp(command, "master_coverage") == 0) user_config->master_width = atoi(arg); + else if (strcmp(command, "resize_master_amount") == 0) user_config->resize_master_amt = atoi(arg); + else if (strcmp(command, "snap_distance") == 0) user_config->snap_distance = atoi(arg); + else if (strcmp(command, "mod_key") == 0) user_config->modkey = parse_mods(arg, user_config); else - fprintf(stderr, "sxwmrc: unknown command: %s\n", command); + fprintf(stderr, "sxwmrc: unknown setting '%s'\n", command); } - -void +int parser(Config *user_config) { char *home = getenv("HOME"); if (!home) { - fputs("sxwmrc: HOME environment variable not set\n", stderr); - return; + fputs("sxwmrc: HOME not set\n", stderr); + return -1; } - char sxwmrc[PATH_MAX]; - snprintf(sxwmrc, sizeof(sxwmrc), "%s/.config/sxwmrc", home); - FILE *f = fopen(sxwmrc, "r"); + char path[PATH_MAX]; + snprintf(path, sizeof(path), "%s/.config/sxwmrc", home); + FILE *f = fopen(path, "r"); if (!f) { - fprintf(stderr, "sxwmrc: file not found: %s\n", sxwmrc); - return; + fprintf(stderr, "sxwmrc: cannot open '%s'\n", path); + return -1; } - char line[512]; + char line[MAX_LINE]; + int lineno = 0; while (fgets(line, sizeof(line), f)) { + lineno++; char *s = strip(line); - if (!*s || *s == '#' || *s == '\n') - continue; + if (!*s || *s == '#') continue; - char *c = strchr(s, ':'); - if (!c) { - fprintf(stderr, "sxwmrc: invalid line (no colon): %s\n", s); + /* split key : value */ + char *sep = strchr(s, ':'); + if (!sep) { + fprintf(stderr, "sxwmrc:%d: missing ':'\n", lineno); continue; } - *c = '\0'; + *sep = '\0'; char *key = strip(s); - char *val = strip(c+1); + char *val = strip(sep + 1); if (strcmp(key, "bind") == 0) { - char *d = strchr(val, ':'); - if (!d) { - fprintf(stderr, "sxwmrc: invalid bind (no action): %s\n", val); + /* bind parsing */ + char *mid = strchr(val, ':'); + if (!mid) { + fprintf(stderr, "sxwmrc:%d: bind missing action\n", lineno); continue; } - *d = '\0'; + *mid = '\0'; char *combo = strip(val); - char *act = strip(d+1); + char *act = strip(mid + 1); - if (*combo == '[') combo++; + if (*combo == '[') { + combo++; + } size_t L = strlen(combo); - if (L && combo[L-1] == ']') combo[L-1] = '\0'; + if (L && combo[L-1] == ']') { + combo[L-1] = '\0'; + } + /* parse mods & key */ unsigned int mods = 0; - KeySym ks = 0; - char part[64]; - char *tok = strtok(combo, "+"); - while (tok) { + char key_part[64] = {0}; + char tokbuf[MAX_LINE]; + strncpy(tokbuf, combo, sizeof(tokbuf)-1); + tokbuf[sizeof(tokbuf)-1] = '\0'; + + for (char *tok = strtok(tokbuf, "+"); tok; tok = strtok(NULL, "+")) { char *p = strip(tok); - for (size_t i=0; p[i]; i++) p[i] = tolower((unsigned char)p[i]); - if (strcmp(p,"mod") == 0) mods |= user_config->modkey; - else if (strcmp(p,"shift")==0) mods |= ShiftMask; - else if (strcmp(p,"ctrl")==0) mods |= ControlMask; - else if (strcmp(p,"alt")==0) mods |= Mod1Mask; - else { - strncpy(part, tok, sizeof(part)-1); - part[sizeof(part)-1] = '\0'; - ks = parse_keysym(strip(part)); - } - tok = strtok(NULL, "+"); + for (char *c = p; *c; c++) *c = tolower((unsigned char)*c); + if (strcmp(p, "mod") == 0) mods |= user_config->modkey; + else if (strcmp(p, "shift") == 0) mods |= ShiftMask; + else if (strcmp(p, "ctrl") == 0) mods |= ControlMask; + else if (strcmp(p, "alt") == 0) mods |= Mod1Mask; + else if (strcmp(p, "super") == 0) mods |= Mod4Mask; + else strncpy(key_part, p, sizeof(key_part)-1); } + KeySym ks = parse_keysym(key_part); + if (!ks) continue; + Action a = { .cmd = NULL }; Bool is_fn = False; if (*act == '"') { - char *cmdstr = strip_quotes(act); - a.cmd = build_argv(cmdstr); + char act_buf[MAX_LINE]; + strncpy(act_buf, strip_quotes(act), sizeof(act_buf)-1); + act_buf[sizeof(act_buf)-1] = '\0'; + a.cmd = build_argv(act_buf); + fprintf(stderr, "[DEBUG parser] Parsed bind: mods=0x%x, keysym=0x%lx, cmd='%s'\n", mods, ks, act); } else { is_fn = True; + fprintf(stderr, "[DEBUG parser] Parsed bind: mods=0x%x, keysym=0x%lx, func='%s'\n", mods, ks, act); } - handler(key, act, mods, ks, a, is_fn, user_config); + + handler("bind", act, mods, ks, a, is_fn, user_config); } else { - handler(key, val, 0, 0, (Action){0}, False, user_config); + /* normal settings */ + handler(key, val, 0, 0, (Action){ .cmd = NULL }, False, user_config); } } fclose(f); -} - -char * -strip(char *str) -{ - while (*str == ' ' || *str == '\t') str++; - char *end = str + strlen(str) - 1; - while (end > str && (*end==' '||*end=='\t'||*end=='\r'||*end=='\n')) - *end-- = '\0'; - return str; -} - - char * -strip_quotes(char *s) -{ - if (*s == '"') s++; - size_t n = strlen(s); - if (n && s[n-1] == '"') s[n-1] = '\0'; - return s; -} - -unsigned int -parse_mods(const char *mods, Config *user_config) -{ - unsigned int m = 0; - if (strstr(mods, "mod")) m |= user_config->modkey; - if (strstr(mods, "shift")) m |= ShiftMask; - if (strstr(mods, "ctrl")) m |= ControlMask; - if (strstr(mods, "alt")) m |= Mod1Mask; - return m; -} - -KeySym -parse_keysym(const char *key) -{ - KeySym ks = XStringToKeysym(key); - if (ks == NoSymbol) { - fprintf(stderr, "sxwmrc: unknown keysym: %s\n", key); - return 0; - } - return ks; -} - -static const char ** -build_argv(char *cmdline) -{ - char **argv = calloc(MAX_ARGS+1, sizeof(char *)); - if (!argv) return NULL; - - int argc = 0; - char *tok = strtok(cmdline, " \t"); - while (tok && argc < MAX_ARGS) { - argv[argc++] = tok; - tok = strtok(NULL, " \t"); - } - argv[argc] = NULL; - return (const char **)argv; + return 0; } |