diff options
Diffstat (limited to 'src/parser.c')
-rw-r--r-- | src/parser.c | 535 |
1 files changed, 289 insertions, 246 deletions
diff --git a/src/parser.c b/src/parser.c index 7cf7b18..d1bd533 100644 --- a/src/parser.c +++ b/src/parser.c @@ -10,8 +10,8 @@ #include "defs.h" static const struct { - const char *name; - void (*fn)(void); + const char *name; + void (*fn)(void); } call_table[] = {{"close_window", close_focused}, {"decrease_gaps", dec_gaps}, {"focus_next", focus_next}, @@ -30,294 +30,337 @@ static const struct { static void remap_and_dedupe_binds(Config *cfg) { - for (int i = 0; i < cfg->bindsn; i++) { - Binding *b = &cfg->binds[i]; - if (b->mods & (Mod1Mask | Mod4Mask)) { - unsigned others = b->mods & ~(Mod1Mask | Mod4Mask); - b->mods = others | cfg->modkey; - } - } + for (int i = 0; i < cfg->bindsn; i++) { + Binding *b = &cfg->binds[i]; + if (b->mods & (Mod1Mask | Mod4Mask)) { + unsigned others = b->mods & ~(Mod1Mask | Mod4Mask); + b->mods = others | cfg->modkey; + } + } - for (int i = 0; i < cfg->bindsn; i++) { - for (int j = i + 1; j < cfg->bindsn; j++) { - if (cfg->binds[i].mods == cfg->binds[j].mods && cfg->binds[i].keysym == cfg->binds[j].keysym) { - memmove(&cfg->binds[j], &cfg->binds[j + 1], sizeof(Binding) * (cfg->bindsn - j - 1)); - cfg->bindsn--; - j--; - } - } - } + for (int i = 0; i < cfg->bindsn; i++) { + for (int j = i + 1; j < cfg->bindsn; j++) { + if (cfg->binds[i].mods == cfg->binds[j].mods && cfg->binds[i].keysym == cfg->binds[j].keysym) { + memmove(&cfg->binds[j], &cfg->binds[j + 1], sizeof(Binding) * (cfg->bindsn - j - 1)); + cfg->bindsn--; + j--; + } + } + } } static char *strip(char *s) { - while (*s && isspace((unsigned char)*s)) { - s++; - } - char *e = s + strlen(s) - 1; - while (e > s && isspace((unsigned char)*e)) { - *e-- = '\0'; - } - return s; + while (*s && isspace((unsigned char)*s)) { + s++; + } + char *e = s + strlen(s) - 1; + while (e > s && isspace((unsigned char)*e)) { + *e-- = '\0'; + } + return s; } static char *strip_quotes(char *s) { - size_t L = strlen(s); - if (L > 0 && s[0] == '"') { - s++; - L--; - } - if (L > 0 && s[L - 1] == '"') { - s[L - 1] = '\0'; - } - return s; + size_t L = strlen(s); + if (L > 0 && s[0] == '"') { + s++; + L--; + } + if (L > 0 && s[L - 1] == '"') { + s[L - 1] = '\0'; + } + return s; } static Binding *alloc_bind(Config *cfg, unsigned mods, KeySym ks) { - for (int i = 0; i < cfg->bindsn; i++) { - if (cfg->binds[i].mods == (int)mods && cfg->binds[i].keysym == ks) { - return &cfg->binds[i]; - } - } - if (cfg->bindsn >= 256) { - return NULL; - } - Binding *b = &cfg->binds[cfg->bindsn++]; - b->mods = mods; - b->keysym = ks; - return b; + for (int i = 0; i < cfg->bindsn; i++) { + if (cfg->binds[i].mods == (int)mods && cfg->binds[i].keysym == ks) { + return &cfg->binds[i]; + } + } + if (cfg->bindsn >= 256) { + return NULL; + } + Binding *b = &cfg->binds[cfg->bindsn++]; + b->mods = mods; + b->keysym = ks; + return b; } static unsigned parse_combo(const char *combo, Config *cfg, KeySym *out_ks) { - unsigned m = 0; - KeySym ks = NoSymbol; - char buf[256]; - strncpy(buf, combo, sizeof buf - 1); - for (char *p = buf; *p; p++) { - if (*p == '+' || isspace((unsigned char)*p)) { - *p = '+'; - } - } - buf[sizeof buf - 1] = '\0'; - for (char *tok = strtok(buf, "+"); tok; tok = strtok(NULL, "+")) { - for (char *q = tok; *q; q++) { - *q = tolower((unsigned char)*q); - } - if (!strcmp(tok, "mod")) { - m |= cfg->modkey; - } else if (!strcmp(tok, "shift")) { - m |= ShiftMask; - } else if (!strcmp(tok, "ctrl")) { - m |= ControlMask; - } else if (!strcmp(tok, "alt")) { - m |= Mod1Mask; - } else if (!strcmp(tok, "super")) { - m |= Mod4Mask; - } else { - ks = parse_keysym(tok); - } - } - *out_ks = ks; - return m; + unsigned m = 0; + KeySym ks = NoSymbol; + char buf[256]; + strncpy(buf, combo, sizeof buf - 1); + for (char *p = buf; *p; p++) { + if (*p == '+' || isspace((unsigned char)*p)) { + *p = '+'; + } + } + buf[sizeof buf - 1] = '\0'; + for (char *tok = strtok(buf, "+"); tok; tok = strtok(NULL, "+")) { + for (char *q = tok; *q; q++) { + *q = tolower((unsigned char)*q); + } + if (!strcmp(tok, "mod")) { + m |= cfg->modkey; + } + else if (!strcmp(tok, "shift")) { + m |= ShiftMask; + } + else if (!strcmp(tok, "ctrl")) { + m |= ControlMask; + } + else if (!strcmp(tok, "alt")) { + m |= Mod1Mask; + } + else if (!strcmp(tok, "super")) { + m |= Mod4Mask; + } + else { + ks = parse_keysym(tok); + } + } + *out_ks = ks; + return m; } int parser(Config *cfg) { - char path[PATH_MAX]; - const char *home = getenv("HOME"); - if (!home) { - fputs("sxwmrc: HOME not set\n", stderr); - return -1; - } - snprintf(path, sizeof path, "%s/.config/sxwmrc", home); - FILE *f = fopen(path, "r"); - if (!f) { - fprintf(stderr, "sxwmrc: cannot open %s\n", path); - return -1; - } + char path[PATH_MAX]; + const char *home = getenv("HOME"); + if (!home) { + fputs("sxwmrc: HOME not set\n", stderr); + return -1; + } + snprintf(path, sizeof path, "%s/.config/sxwmrc", home); + FILE *f = fopen(path, "r"); + if (!f) { + fprintf(stderr, "sxwmrc: cannot open %s\n", path); + return -1; + } - char line[512]; - int lineno = 0; - while (fgets(line, sizeof line, f)) { - lineno++; - char *s = strip(line); - if (!*s || *s == '#') { - continue; - } + char line[512]; + int lineno = 0; + while (fgets(line, sizeof line, f)) { + lineno++; + char *s = strip(line); + if (!*s || *s == '#') { + continue; + } - char *sep = strchr(s, ':'); - if (!sep) { - fprintf(stderr, "sxwmrc:%d: missing ':'\n", lineno); - continue; - } - *sep = '\0'; - char *key = strip(s); - char *rest = strip(sep + 1); + char *sep = strchr(s, ':'); + if (!sep) { + fprintf(stderr, "sxwmrc:%d: missing ':'\n", lineno); + continue; + } + *sep = '\0'; + char *key = strip(s); + char *rest = strip(sep + 1); - if (!strcmp(key, "mod_key")) { - unsigned m = parse_mods(rest, cfg); - if (m & (Mod1Mask | Mod4Mask)) { - cfg->modkey = m; - } else { - fprintf(stderr, "sxwmrc:%d: unknown mod_key '%s'\n", lineno, rest); - } - } else if (!strcmp(key, "gaps")) { - cfg->gaps = atoi(rest); - } else if (!strcmp(key, "border_width")) { - cfg->border_width = atoi(rest); - } else if (!strcmp(key, "focused_border_colour")) { - cfg->border_foc_col = parse_col(rest); - } else if (!strcmp(key, "unfocused_border_colour")) { - cfg->border_ufoc_col = parse_col(rest); - } else if (!strcmp(key, "swap_border_colour")) { - cfg->border_swap_col = parse_col(rest); - } else if (!strcmp(key, "master_width")) { - cfg->master_width = atoi(rest) / 100.0f; - } else if (!strcmp(key, "motion_throttle")) { - cfg->motion_throttle = atoi(rest); - } else if (!strcmp(key, "resize_master_amount")) { - cfg->resize_master_amt = atoi(rest); - } else if (!strcmp(key, "snap_distance")) { - cfg->snap_distance = atoi(rest); - } else if (!strcmp(key, "call") || !strcmp(key, "bind")) { - char *mid = strchr(rest, ':'); - if (!mid) { - fprintf(stderr, "sxwmrc:%d: '%s' missing action\n", lineno, key); - continue; - } - *mid = '\0'; - char *combo = strip(rest); - char *act = strip(mid + 1); + if (!strcmp(key, "mod_key")) { + unsigned m = parse_mods(rest, cfg); + if (m & (Mod1Mask | Mod4Mask)) { + cfg->modkey = m; + } + else { + fprintf(stderr, "sxwmrc:%d: unknown mod_key '%s'\n", lineno, rest); + } + } + else if (!strcmp(key, "gaps")) { + cfg->gaps = atoi(rest); + } + else if (!strcmp(key, "border_width")) { + cfg->border_width = atoi(rest); + } + else if (!strcmp(key, "focused_border_colour")) { + cfg->border_foc_col = parse_col(rest); + } + else if (!strcmp(key, "unfocused_border_colour")) { + cfg->border_ufoc_col = parse_col(rest); + } + else if (!strcmp(key, "swap_border_colour")) { + cfg->border_swap_col = parse_col(rest); + } + else if (!strcmp(key, "master_width")) { + cfg->master_width = atoi(rest) / 100.0f; + } + else if (!strcmp(key, "motion_throttle")) { + cfg->motion_throttle = atoi(rest); + } + else if (!strcmp(key, "resize_master_amount")) { + cfg->resize_master_amt = atoi(rest); + } + else if (!strcmp(key, "snap_distance")) { + cfg->snap_distance = atoi(rest); + } + else if (!strcmp(key, "call") || !strcmp(key, "bind")) { + char *mid = strchr(rest, ':'); + if (!mid) { + fprintf(stderr, "sxwmrc:%d: '%s' missing action\n", lineno, key); + continue; + } + *mid = '\0'; + char *combo = strip(rest); + char *act = strip(mid + 1); - KeySym ks; - unsigned mods = parse_combo(combo, cfg, &ks); - if (ks == NoSymbol) { - fprintf(stderr, "sxwmrc:%d: bad key in '%s'\n", lineno, combo); - continue; - } - Binding *b = alloc_bind(cfg, mods, ks); - if (!b) { - fputs("sxwm: too many binds\n", stderr); - break; - } + KeySym ks; + unsigned mods = parse_combo(combo, cfg, &ks); + if (ks == NoSymbol) { + fprintf(stderr, "sxwmrc:%d: bad key in '%s'\n", lineno, combo); + continue; + } + Binding *b = alloc_bind(cfg, mods, ks); + if (!b) { + fputs("sxwm: too many binds\n", stderr); + break; + } - if (*act == '"' && !strcmp(key, "bind")) { - b->type = TYPE_CMD; - b->action.cmd = build_argv(strip_quotes(act)); - } else { - b->type = TYPE_FUNC; - Bool found = False; - for (int i = 0; call_table[i].name; i++) { - if (!strcmp(act, call_table[i].name)) { - b->action.fn = call_table[i].fn; - found = True; - break; - } - } - if (!found) { - fprintf(stderr, "sxwmrc:%d: unknown function '%s'\n", lineno, act); - } - } - } else if (!strcmp(key, "workspace")) { - char *mid = strchr(rest, ':'); - if (!mid) { - fprintf(stderr, "sxwmrc:%d: workspace missing action\n", lineno); - continue; - } - *mid = '\0'; - char *combo = strip(rest); - char *act = strip(mid + 1); + if (*act == '"' && !strcmp(key, "bind")) { + b->type = TYPE_CMD; + b->action.cmd = build_argv(strip_quotes(act)); + } + else { + b->type = TYPE_FUNC; + Bool found = False; + for (int i = 0; call_table[i].name; i++) { + if (!strcmp(act, call_table[i].name)) { + b->action.fn = call_table[i].fn; + found = True; + break; + } + } + if (!found) { + fprintf(stderr, "sxwmrc:%d: unknown function '%s'\n", lineno, act); + } + } + } + else if (!strcmp(key, "workspace")) { + char *mid = strchr(rest, ':'); + if (!mid) { + fprintf(stderr, "sxwmrc:%d: workspace missing action\n", lineno); + continue; + } + *mid = '\0'; + char *combo = strip(rest); + char *act = strip(mid + 1); - KeySym ks; - unsigned mods = parse_combo(combo, cfg, &ks); - if (ks == NoSymbol) { - fprintf(stderr, "sxwmrc:%d: bad key in '%s'\n", lineno, combo); - continue; - } - Binding *b = alloc_bind(cfg, mods, ks); - if (!b) { - fputs("sxwm: too many binds\n", stderr); - break; - } + KeySym ks; + unsigned mods = parse_combo(combo, cfg, &ks); + if (ks == NoSymbol) { + fprintf(stderr, "sxwmrc:%d: bad key in '%s'\n", lineno, combo); + continue; + } + Binding *b = alloc_bind(cfg, mods, ks); + if (!b) { + fputs("sxwm: too many binds\n", stderr); + break; + } - int n; - if (sscanf(act, "move %d", &n) == 1 && n >= 1 && n <= NUM_WORKSPACES) { - b->type = TYPE_CWKSP; - b->action.ws = n - 1; - } else if (sscanf(act, "swap %d", &n) == 1 && n >= 1 && n <= NUM_WORKSPACES) { - b->type = TYPE_MWKSP; - b->action.ws = n - 1; - } else { - fprintf(stderr, "sxwmrc:%d: invalid workspace action '%s'\n", lineno, act); - } - } else { - fprintf(stderr, "sxwmrc:%d: unknown option '%s'\n", lineno, key); - } - } + int n; + if (sscanf(act, "move %d", &n) == 1 && n >= 1 && n <= NUM_WORKSPACES) { + b->type = TYPE_CWKSP; + b->action.ws = n - 1; + } + else if (sscanf(act, "swap %d", &n) == 1 && n >= 1 && n <= NUM_WORKSPACES) { + b->type = TYPE_MWKSP; + b->action.ws = n - 1; + } + else { + fprintf(stderr, "sxwmrc:%d: invalid workspace action '%s'\n", lineno, act); + } + } + else { + fprintf(stderr, "sxwmrc:%d: unknown option '%s'\n", lineno, key); + } + } - fclose(f); - remap_and_dedupe_binds(cfg); - return 0; + fclose(f); + remap_and_dedupe_binds(cfg); + return 0; } int parse_mods(const char *mods, Config *cfg) { - KeySym dummy; - return parse_combo(mods, cfg, &dummy); + KeySym dummy; + return parse_combo(mods, cfg, &dummy); } KeySym parse_keysym(const char *key) { - KeySym ks = XStringToKeysym(key); - if (ks != NoSymbol) { - return ks; - } + KeySym ks = XStringToKeysym(key); + if (ks != NoSymbol) { + return ks; + } - char buf[64]; - size_t n = strlen(key); - if (n >= sizeof buf) { - n = sizeof buf - 1; - } + char buf[64]; + size_t n = strlen(key); + if (n >= sizeof buf) { + n = sizeof buf - 1; + } - buf[0] = toupper((unsigned char)key[0]); - for (size_t i = 1; i < n; i++) { - buf[i] = tolower((unsigned char)key[i]); - } - buf[n] = '\0'; - ks = XStringToKeysym(buf); - if (ks != NoSymbol) { - return ks; - } + buf[0] = toupper((unsigned char)key[0]); + for (size_t i = 1; i < n; i++) { + buf[i] = tolower((unsigned char)key[i]); + } + buf[n] = '\0'; + ks = XStringToKeysym(buf); + if (ks != NoSymbol) { + return ks; + } - for (size_t i = 0; i < n; i++) { - buf[i] = toupper((unsigned char)key[i]); - } - buf[n] = '\0'; - ks = XStringToKeysym(buf); - if (ks != NoSymbol) { - return ks; - } + for (size_t i = 0; i < n; i++) { + buf[i] = toupper((unsigned char)key[i]); + } + buf[n] = '\0'; + ks = XStringToKeysym(buf); + if (ks != NoSymbol) { + return ks; + } - fprintf(stderr, "sxwmrc: unknown keysym '%s'\n", key); - return NoSymbol; + fprintf(stderr, "sxwmrc: unknown keysym '%s'\n", key); + return NoSymbol; } const char **build_argv(const char *cmd) { - char *dup = strdup(cmd); - char *saveptr, *tok; - const char **argv = malloc(MAX_ARGS * sizeof *argv); - int i = 0; + char *dup = strdup(cmd); + char *saveptr = NULL; + const char **argv = malloc(MAX_ARGS * sizeof(*argv)); + int i = 0; - for (tok = strtok_r(dup, " \t", &saveptr); tok && i < MAX_ARGS - 1; tok = strtok_r(NULL, " \t", &saveptr)) { - if (*tok) { - argv[i++] = strdup(tok); - } - } - argv[i] = NULL; - free(dup); - return argv; + char *tok = strtok_r(dup, " \t", &saveptr); + while (tok && i < MAX_ARGS - 1) { + if (*tok == '"') { + char *end = tok + strlen(tok) - 1; + if (*end == '"') { + *end = '\0'; + argv[i++] = strdup(tok + 1); + } + else { + char *quoted = strdup(tok + 1); + while ((tok = strtok_r(NULL, " \t", &saveptr)) && *tok != '"') { + quoted = realloc(quoted, strlen(quoted) + strlen(tok) + 2); + strcat(quoted, " "); + strcat(quoted, tok); + } + if (tok && *tok == '"') { + quoted = realloc(quoted, strlen(quoted) + strlen(tok)); + strcat(quoted, tok); + } + argv[i++] = quoted; + } + } + else { + argv[i++] = strdup(tok); + } + tok = strtok_r(NULL, " \t", &saveptr); + } + argv[i] = NULL; + free(dup); + return argv; }
\ No newline at end of file |