X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fcfgparse.y;h=d706b4001b6157f2822fa3bd62ebabad87709065;hb=e101940c5edd3094463fea362fc21e924a46eca4;hp=4e09e2b1d42963ca7ec7d1d0f24f43c710041f2d;hpb=268bf712221de86612ec628a44d1e85ba83db519;p=i3%2Fi3 diff --git a/src/cfgparse.y b/src/cfgparse.y index 4e09e2b1..d706b400 100644 --- a/src/cfgparse.y +++ b/src/cfgparse.y @@ -1,13 +1,32 @@ %{ +/* + * vim:ts=8:expandtab + * + */ #include #include #include +#include +#include +#include +#include +#include +#include #include "data.h" +#include "config.h" +#include "i3.h" +#include "util.h" +#include "queue.h" +#include "table.h" +#include "workspace.h" +#include "xcb.h" extern int yylex(void); extern FILE *yyin; +static struct bindings_head *current_bindings; + int yydebug = 1; void yyerror(const char *str) { @@ -19,38 +38,136 @@ int yywrap() { } void parse_file(const char *f) { - printf("opening %s\n", f); - if ((yyin = fopen(f, "r")) == NULL) { - perror("fopen"); - exit(1); - } - if (yyparse() != 0) { - fprintf(stderr, "Could not parse configfile\n"); - exit(1); - } - fclose(yyin); -} + SLIST_HEAD(variables_head, Variable) variables = SLIST_HEAD_INITIALIZER(&variables); + int fd, ret, read_bytes = 0; + struct stat stbuf; + char *buf; + FILE *fstr; + char buffer[1026], key[512], value[512]; + + if ((fd = open(f, O_RDONLY)) == -1) + die("Could not open configuration file: %s\n", strerror(errno)); + + if (fstat(fd, &stbuf) == -1) + die("Could not fstat file: %s\n", strerror(errno)); + + buf = smalloc(stbuf.st_size * sizeof(char)); + while (read_bytes < stbuf.st_size) { + if ((ret = read(fd, buf + read_bytes, (stbuf.st_size - read_bytes))) < 0) + die("Could not read(): %s\n", strerror(errno)); + read_bytes += ret; + } + + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) + die("Could not lseek: %s\n", strerror(errno)); + + if ((fstr = fdopen(fd, "r")) == NULL) + die("Could not fdopen: %s\n", strerror(errno)); + + while (!feof(fstr)) { + if (fgets(buffer, 1024, fstr) == NULL) { + if (feof(fstr)) + break; + die("Could not read configuration file\n"); + } + + /* sscanf implicitly strips whitespace. Also, we skip comments and empty lines. */ + if (sscanf(buffer, "%s %[^\n]", key, value) < 1 || + key[0] == '#' || strlen(key) < 3) + continue; + + if (strcasecmp(key, "set") == 0) { + if (value[0] != '$') + die("Malformed variable assignment, name has to start with $\n"); + + /* get key/value for this variable */ + char *v_key = value, *v_value; + if ((v_value = strstr(value, " ")) == NULL) + die("Malformed variable assignment, need a value\n"); + + *(v_value++) = '\0'; + + struct Variable *new = scalloc(sizeof(struct Variable)); + new->key = sstrdup(v_key); + new->value = sstrdup(v_value); + SLIST_INSERT_HEAD(&variables, new, variables); + LOG("Got new variable %s = %s\n", v_key, v_value); + continue; + } + } + + /* For every custom variable, see how often it occurs in the file and + * how much extra bytes it requires when replaced. */ + struct Variable *current, *nearest; + int extra_bytes = 0; + SLIST_FOREACH(current, &variables, variables) { + int extra = (strlen(current->value) - strlen(current->key)); + char *next; + for (next = buf; + (next = strcasestr(buf + (next - buf), current->key)) != NULL; + next += strlen(current->key)) + extra_bytes += extra; + } + + /* Then, allocate a new buffer and copy the file over to the new one, + * but replace occurences of our variables */ + char *walk = buf, *destwalk; + char *new = smalloc((stbuf.st_size + extra_bytes) * sizeof(char)); + destwalk = new; + while (walk < (buf + stbuf.st_size)) { + /* Find the next variable */ + SLIST_FOREACH(current, &variables, variables) + current->next_match = strcasestr(walk, current->key); + nearest = NULL; + int distance = stbuf.st_size; + SLIST_FOREACH(current, &variables, variables) { + if (current->next_match == NULL) + continue; + if ((current->next_match - walk) < distance) { + distance = (current->next_match - walk); + nearest = current; + } + } + if (nearest == NULL) { + /* If there are no more variables, we just copy the rest */ + strncpy(destwalk, walk, (buf + stbuf.st_size) - walk); + destwalk += (buf + stbuf.st_size) - walk; + *destwalk = '\0'; + break; + } else { + /* Copy until the next variable, then copy its value */ + strncpy(destwalk, walk, distance); + strncpy(destwalk + distance, nearest->value, strlen(nearest->value)); + walk += distance + strlen(nearest->key); + destwalk += distance + strlen(nearest->value); + } + } + + yy_scan_string(new); + + if (yyparse() != 0) { + fprintf(stderr, "Could not parse configfile\n"); + exit(1); + } -#if 0 -main() -{ - yyparse(); - printf("parsing done\n"); + free(new); + free(buf); } -#endif %} %union { - int number; - char *string; + int number; + char *string; + struct Colortriple *color; + struct Assignment *assignment; + struct Binding *binding; } %token NUMBER %token WORD %token STR %token STR_NG -%token VARNAME %token HEX %token TOKBIND %token TOKTERMINAL @@ -71,151 +188,310 @@ main() %token TOKEXEC %token TOKCOLOR %token TOKARROW +%token TOKMODE +%token TOKNEWCONTAINER +%token TOKCONTAINERMODE +%token TOKSTACKLIMIT %% lines: /* empty */ | lines WHITESPACE line - | lines line + | lines line ; line: - bind - | bindsym - | floating_modifier - | workspace - | assign - | set - | ipcsocket - | exec - | color - | terminal - | font - | comment + bindline + | mode + | floating_modifier + | new_container + | workspace + | assign + | ipcsocket + | exec + | color + | terminal + | font + | comment ; comment: - TOKCOMMENT - ; + TOKCOMMENT + ; command: - STR - ; + STR + ; + +bindline: + binding + { + TAILQ_INSERT_TAIL(bindings, $1, bindings); + } + ; + +binding: + TOKBIND WHITESPACE bind { $$ = $3; } + | TOKBINDSYM WHITESPACE bindsym { $$ = $3; } + ; bind: - TOKBIND WHITESPACE binding_modifiers '+' NUMBER WHITESPACE command + binding_modifiers NUMBER WHITESPACE command { - printf("\tFound binding mod%d with key %d and command %s\n", $3, $5, $7); + printf("\tFound binding mod%d with key %d and command %s\n", $1, $2, $4); + Binding *new = scalloc(sizeof(Binding)); + + new->keycode = $2; + new->mods = $1; + new->command = sstrdup($4); + + $$ = new; } ; bindsym: - TOKBINDSYM WHITESPACE binding_modifiers '+' WORD WHITESPACE command + binding_modifiers WORD WHITESPACE command { - printf("\tFound symbolic mod%d with key %s and command %s\n", $3, $5, $7); + printf("\tFound symbolic mod%d with key %s and command %s\n", $1, $2, $4); + Binding *new = scalloc(sizeof(Binding)); + + new->symbol = sstrdup($2); + new->mods = $1; + new->command = sstrdup($4); + + $$ = new; + } + ; + +mode: + TOKMODE WHITESPACE QUOTEDSTRING WHITESPACE '{' modelines '}' + { + if (strcasecmp($3, "default") == 0) { + printf("You cannot use the name \"default\" for your mode\n"); + exit(1); + } + printf("\t now in mode %s\n", $3); + printf("\t current bindings = %p\n", current_bindings); + Binding *binding; + TAILQ_FOREACH(binding, current_bindings, bindings) { + printf("got binding on mods %d, keycode %d, symbol %s, command %s\n", + binding->mods, binding->keycode, binding->symbol, binding->command); + } + + struct Mode *mode = scalloc(sizeof(struct Mode)); + mode->name = strdup($3); + mode->bindings = current_bindings; + current_bindings = NULL; + SLIST_INSERT_HEAD(&modes, mode, modes); + } + ; + +modelines: + /* empty */ + | modelines WHITESPACE modeline + | modelines modeline + ; + +modeline: + comment + | binding + { + if (current_bindings == NULL) { + current_bindings = scalloc(sizeof(struct bindings_head)); + TAILQ_INIT(current_bindings); + } + + TAILQ_INSERT_TAIL(current_bindings, $1, bindings); } ; floating_modifier: - TOKFLOATING_MODIFIER WHITESPACE binding_modifiers - { - printf("\tfloating modifier %d\n", $3); - } - ; + TOKFLOATING_MODIFIER WHITESPACE binding_modifiers + { + LOG("floating modifier = %d\n", $3); + config.floating_modifier = $3; + } + ; + +new_container: + TOKNEWCONTAINER WHITESPACE TOKCONTAINERMODE + { + LOG("new containers will be in mode %d\n", $3); + config.container_mode = $3; + + /* We also need to change the layout of the already existing + * workspaces here. Workspaces may exist at this point because + * of the other directives which are modifying workspaces + * (setting the preferred screen or name). While the workspace + * objects are already created, they have never been used. + * Thus, the user very likely awaits the default container mode + * to trigger in this case, regardless of where it is inside + * his configuration file. */ + for (int c = 0; c < num_workspaces; c++) { + if (workspaces[c].table == NULL) + continue; + switch_layout_mode(global_conn, + workspaces[c].table[0][0], + config.container_mode); + } + } + | TOKNEWCONTAINER WHITESPACE TOKSTACKLIMIT WHITESPACE TOKSTACKLIMIT WHITESPACE NUMBER + { + LOG("stack-limit %d with val %d\n", $5, $7); + config.container_stack_limit = $5; + config.container_stack_limit_value = $7; + + /* See the comment above */ + for (int c = 0; c < num_workspaces; c++) { + if (workspaces[c].table == NULL) + continue; + Container *con = workspaces[c].table[0][0]; + con->stack_limit = config.container_stack_limit; + con->stack_limit_value = config.container_stack_limit_value; + } + } + ; workspace: - TOKWORKSPACE WHITESPACE NUMBER WHITESPACE TOKSCREEN WHITESPACE screen - { - printf("\t workspace %d to screen %d\n", $3, $7); - } - | TOKWORKSPACE WHITESPACE NUMBER WHITESPACE TOKSCREEN WHITESPACE screen WHITESPACE QUOTEDSTRING - { - printf("\t quoted: %s\n", $9); - } - ; + TOKWORKSPACE WHITESPACE NUMBER WHITESPACE TOKSCREEN WHITESPACE screen workspace_name + { + int ws_num = $3; + if (ws_num < 1) { + LOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num); + } else { + Workspace *ws = workspace_get(ws_num - 1); + ws->preferred_screen = sstrdup($7); + if ($8 != NULL) + workspace_set_name(ws, $8); + } + } + | TOKWORKSPACE WHITESPACE NUMBER workspace_name + { + int ws_num = $3; + if (ws_num < 1) { + LOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num); + } else { + if ($4 != NULL) + workspace_set_name(workspace_get(ws_num - 1), $4); + } + } + ; -screen: - NUMBER - ; +workspace_name: + /* NULL */ { $$ = NULL; } + | WHITESPACE QUOTEDSTRING { $$ = $2; } + | WHITESPACE STR { $$ = $2; } + ; +screen: + NUMBER { asprintf(&$$, "%d", $1); } + | NUMBER 'x' { asprintf(&$$, "%d", $1); } + | NUMBER 'x' NUMBER { asprintf(&$$, "%dx%d", $1, $3); } + | 'x' NUMBER { asprintf(&$$, "x%d", $2); } + ; assign: - TOKASSIGN WHITESPACE window_class WHITESPACE optional_arrow NUMBER - { - printf("assignment of %s to %d\n", $3, $6); - } - ; + TOKASSIGN WHITESPACE window_class WHITESPACE optional_arrow assign_target + { + printf("assignment of %s to %d\n", $3, $6); + + struct Assignment *new = $6; + new->windowclass_title = strdup($3); + TAILQ_INSERT_TAIL(&assignments, new, assignments); + } + ; + +assign_target: + NUMBER + { + struct Assignment *new = scalloc(sizeof(struct Assignment)); + new->workspace = $1; + new->floating = ASSIGN_FLOATING_NO; + $$ = new; + } + | '~' + { + struct Assignment *new = scalloc(sizeof(struct Assignment)); + new->floating = ASSIGN_FLOATING_ONLY; + $$ = new; + } + | '~' NUMBER + { + struct Assignment *new = scalloc(sizeof(struct Assignment)); + new->workspace = $2; + new->floating = ASSIGN_FLOATING; + $$ = new; + } + ; window_class: - QUOTEDSTRING - | STR_NG - ; + QUOTEDSTRING + | STR_NG + ; optional_arrow: - /* NULL */ - | TOKARROW WHITESPACE - ; - -set: - TOKSET WHITESPACE variable WHITESPACE STR - { - printf("set %s to %s\n", $3, $5); - } - ; - -variable: - '$' WORD { asprintf(&$$, "$%s", $2); } - | '$' VARNAME { asprintf(&$$, "$%s", $2); } - ; + /* NULL */ + | TOKARROW WHITESPACE + ; ipcsocket: - TOKIPCSOCKET WHITESPACE STR - { - printf("ipc %s\n", $3); - } - ; + TOKIPCSOCKET WHITESPACE STR + { + config.ipc_socket_path = sstrdup($3); + } + ; exec: - TOKEXEC WHITESPACE STR - { - printf("exec %s\n", $3); - } - ; + TOKEXEC WHITESPACE STR + { + struct Autostart *new = smalloc(sizeof(struct Autostart)); + new->command = sstrdup($3); + TAILQ_INSERT_TAIL(&autostarts, new, autostarts); + } + ; terminal: - TOKTERMINAL WHITESPACE STR - { - printf("terminal %s\n", $3); - } - ; + TOKTERMINAL WHITESPACE STR + { + config.terminal = sstrdup($3); + printf("terminal %s\n", config.terminal); + } + ; font: - TOKFONT WHITESPACE STR - { - printf("font %s\n", $3); - } - ; + TOKFONT WHITESPACE STR + { + config.font = sstrdup($3); + printf("font %s\n", config.font); + } + ; color: - TOKCOLOR WHITESPACE '#' HEX - { - printf("color %s\n", $4); - } - ; + TOKCOLOR WHITESPACE colorpixel WHITESPACE colorpixel WHITESPACE colorpixel + { + struct Colortriple *dest = $1; + + dest->border = $3; + dest->background = $5; + dest->text = $7; + } + ; + +colorpixel: + '#' HEX { $$ = get_colorpixel(global_conn, $2); } + ; binding_modifiers: - binding_modifier - | - binding_modifiers '+' binding_modifier - { - $$ = $1 | $3; - } - ; + /* NULL */ { $$ = 0; } + | binding_modifier + | binding_modifiers '+' binding_modifier { $$ = $1 | $3; } + | binding_modifiers '+' { $$ = $1; } + ; binding_modifier: - MODIFIER { $$ = $1; } - | TOKCONTROL { $$ = BIND_CONTROL; } - | TOKSHIFT { $$ = BIND_SHIFT; } - ; + MODIFIER { $$ = $1; } + | TOKCONTROL { $$ = BIND_CONTROL; } + | TOKSHIFT { $$ = BIND_SHIFT; } + ;