From: Michael Stapelberg Date: Sun, 13 Sep 2009 19:32:58 +0000 (+0200) Subject: Make variable expansion work with the new parsing X-Git-Tag: 3.d~90^2~2 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=7fda4a2c32336e0887fc33c6614acdd84b58ece7;p=i3%2Fi3 Make variable expansion work with the new parsing --- diff --git a/include/config.h b/include/config.h index 100faa4c..f94d9a40 100644 --- a/include/config.h +++ b/include/config.h @@ -40,6 +40,7 @@ struct Colortriple { struct Variable { char *key; char *value; + char *next_match; SLIST_ENTRY(Variable) variables; }; diff --git a/src/cfgparse.l b/src/cfgparse.l index e3bacae5..ac2a71b0 100644 --- a/src/cfgparse.l +++ b/src/cfgparse.l @@ -5,7 +5,6 @@ #include "data.h" #include "config.h" - %} %Start BIND_COND @@ -13,8 +12,6 @@ %Start BIND_A2WS_COND %Start ASSIGN_COND %Start COLOR_COND -%Start SET_COND -%Start SET_AWS_COND %Start SCREEN_COND %Start SCREEN_AWS_COND @@ -31,7 +28,7 @@ screen { BEGIN(SCREEN_COND); return TOKSCREEN; } terminal { BEGIN(BIND_AWS_COND); return TOKTERMINAL; } font { BEGIN(BIND_AWS_COND); return TOKFONT; } assign { BEGIN(ASSIGN_COND); return TOKASSIGN; } -set { BEGIN(SET_COND); return TOKSET; } +set[^\n]* { return TOKCOMMENT; } ipc-socket { BEGIN(BIND_AWS_COND); return TOKIPCSOCKET; } exec { BEGIN(BIND_AWS_COND); return TOKEXEC; } client.focused { BEGIN(COLOR_COND); yylval.color = &config.client.focused; return TOKCOLOR; } @@ -52,9 +49,7 @@ shift { return TOKSHIFT; } \n /* ignore end of line */; x { return (int)yytext[0]; } [ \t]+ { BEGIN(BIND_AWS_COND); return WHITESPACE; } -[ \t]+ { BEGIN(SET_AWS_COND); return WHITESPACE; } [ \t]+ { BEGIN(BIND_A2WS_COND); return WHITESPACE; } -[ \t]+ { BEGIN(BIND_A2WS_COND); return WHITESPACE; } [ \t]+ { BEGIN(SCREEN_AWS_COND); return WHITESPACE; } [ \t]+ { BEGIN(BIND_A2WS_COND); return WHITESPACE; } [ \t]+ { return WHITESPACE; } @@ -69,6 +64,5 @@ shift { return TOKSHIFT; } } [^ \t]+ { BEGIN(INITIAL); yylval.string = strdup(yytext); return STR_NG; } [a-zA-Z]+ { yylval.string = strdup(yytext); return WORD; } -[a-zA-Z0-9_-]+ { yylval.string = strdup(yytext); return VARNAME; } . { return (int)yytext[0]; } %% diff --git a/src/cfgparse.y b/src/cfgparse.y index eab11484..59ecd977 100644 --- a/src/cfgparse.y +++ b/src/cfgparse.y @@ -2,9 +2,17 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "data.h" #include "config.h" +#include "util.h" +#include "queue.h" extern int yylex(void); extern FILE *yyin; @@ -20,25 +28,121 @@ int yywrap() { } void parse_file(const char *f) { - printf("opening %s\n", f); - if ((yyin = fopen(f, "r")) == NULL) { - perror("fopen"); - exit(1); + 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); } - fclose(yyin); -} -#if 0 -main() -{ - yyparse(); - printf("parsing done\n"); + free(new); + free(buf); } -#endif %} @@ -52,7 +156,6 @@ main() %token WORD %token STR %token STR_NG -%token VARNAME %token HEX %token TOKBIND %token TOKTERMINAL @@ -87,7 +190,6 @@ line: | floating_modifier | workspace | assign - | set | ipcsocket | exec | color @@ -165,18 +267,6 @@ optional_arrow: | 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); } - ; - ipcsocket: TOKIPCSOCKET WHITESPACE STR {