* vim:ts=4:sw=4:expandtab
*
* i3 - an improved dynamic tiling window manager
- * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE)
+ * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
*
* config_parser.c: hand-written parser to parse configuration directives.
*
#include "all.h"
// Macros to make the YAJL API a bit easier to use.
-#define y(x, ...) yajl_gen_ ## x (command_output.json_gen, ##__VA_ARGS__)
-#define ystr(str) yajl_gen_string(command_output.json_gen, (unsigned char*)str, strlen(str))
+#define y(x, ...) yajl_gen_##x(command_output.json_gen, ##__VA_ARGS__)
+#define ystr(str) yajl_gen_string(command_output.json_gen, (unsigned char *)str, strlen(str))
#ifndef TEST_PARSER
pid_t config_error_nagbar_pid = -1;
"in the code, or a new command which contains more than "
"10 identified tokens.\n");
exit(1);
-
}
static const char *get_string(const char *identifier) {
* When jumping back to INITIAL, statelist_idx will simply be set to 1
* (likewise for other states, e.g. MODE or BAR).
* This list is used to process the nearest error token. */
-static cmdp_state statelist[10] = { INITIAL };
+static cmdp_state statelist[10] = {INITIAL};
/* NB: statelist_idx points to where the next entry will be inserted */
static int statelist_idx = 1;
#include "GENERATED_config_call.h"
-
static void next_state(const cmdp_token *token) {
cmdp_state _next_state = token->next_state;
- //printf("token = name %s identifier %s\n", token->name, token->identifier);
- //printf("next_state = %d\n", token->next_state);
+ //printf("token = name %s identifier %s\n", token->name, token->identifier);
+ //printf("next_state = %d\n", token->next_state);
if (token->next_state == __CALL) {
subcommand_output.json_gen = command_output.json_gen;
GENERATED_call(token->extra.call_identifier, &subcommand_output);
for (int i = 0; i < statelist_idx; i++) {
if (statelist[i] != _next_state)
continue;
- statelist_idx = i+1;
+ statelist_idx = i + 1;
return;
}
bool token_handled;
linecnt = 1;
- // TODO: make this testable
+// TODO: make this testable
#ifndef TEST_PARSER
cfg_criteria_init(¤t_match, &subcommand_output, INITIAL);
#endif
while ((*walk == ' ' || *walk == '\t') && *walk != '\0')
walk++;
- //printf("remaining input: %s\n", walk);
+ //printf("remaining input: %s\n", walk);
cmdp_token_ptr *ptr = &(tokens[state]);
token_handled = false;
if (*walk == '"') {
beginning++;
walk++;
- while (*walk != '\0' && (*walk != '"' || *(walk-1) == '\\'))
+ while (*walk != '\0' && (*walk != '"' || *(walk - 1) == '\\'))
walk++;
} else {
if (token->name[0] == 's') {
* semicolon (;). */
while (*walk != ' ' && *walk != '\t' &&
*walk != ']' && *walk != ',' &&
- *walk != ';' && *walk != '\r' &&
+ *walk != ';' && *walk != '\r' &&
*walk != '\n' && *walk != '\0')
walk++;
}
}
if (walk != beginning) {
- char *str = scalloc(walk-beginning + 1);
+ char *str = scalloc(walk - beginning + 1);
/* We copy manually to handle escaping of characters. */
int inpos, outpos;
for (inpos = 0, outpos = 0;
- inpos < (walk-beginning);
+ inpos < (walk - beginning);
inpos++, outpos++) {
/* We only handle escaped double quotes to not break
* backwards compatibility with people using \w in
* regular expressions etc. */
- if (beginning[inpos] == '\\' && beginning[inpos+1] == '"')
+ if (beginning[inpos] == '\\' && beginning[inpos + 1] == '"')
inpos++;
str[outpos] = beginning[inpos];
}
}
if (strcmp(token->name, "line") == 0) {
- while (*walk != '\0' && *walk != '\n' && *walk != '\r')
- walk++;
- next_state(token);
- token_handled = true;
- linecnt++;
- walk++;
- break;
+ while (*walk != '\0' && *walk != '\n' && *walk != '\r')
+ walk++;
+ next_state(token);
+ token_handled = true;
+ linecnt++;
+ walk++;
+ break;
}
if (strcmp(token->name, "end") == 0) {
if (*walk == '\0' || *walk == '\n' || *walk == '\r') {
next_state(token);
token_handled = true;
- /* To make sure we start with an appropriate matching
+/* To make sure we start with an appropriate matching
* datastructure for commands which do *not* specify any
* criteria, we re-initialize the criteria system after
* every command. */
- // TODO: make this testable
+// TODO: make this testable
#ifndef TEST_PARSER
cfg_criteria_init(¤t_match, &subcommand_output, INITIAL);
#endif
linecnt++;
walk++;
break;
- }
- }
+ }
+ }
}
if (!token_handled) {
possible_tokens);
free(possible_tokens);
-
/* Go back to the beginning of the line */
const char *error_line = start_of_line(walk, input);
/* Print context lines *before* the error, if any. */
if (linecnt > 1) {
- const char *context_p1_start = start_of_line(error_line-2, input);
+ const char *context_p1_start = start_of_line(error_line - 2, input);
char *context_p1_line = single_line(context_p1_start);
if (linecnt > 2) {
- const char *context_p2_start = start_of_line(context_p1_start-2, input);
+ const char *context_p2_start = start_of_line(context_p1_start - 2, input);
char *context_p2_line = single_line(context_p2_start);
ELOG("CONFIG: Line %3d: %s\n", linecnt - 2, context_p2_line);
free(context_p2_line);
* we find the nearest state which contains an <error> token
* and follow that one. */
bool error_token_found = false;
- for (int i = statelist_idx-1; (i >= 0) && !error_token_found; i--) {
+ for (int i = statelist_idx - 1; (i >= 0) && !error_token_found; i--) {
cmdp_token_ptr *errptr = &(tokens[statelist[i]]);
for (int j = 0; j < errptr->n; j++) {
if (strcmp(errptr->array[j].name, "error") != 0)
strncasecmp(line, "force_focus_wrapping", strlen("force_focus_wrapping")) == 0 ||
strncasecmp(line, "# i3 config file (v4)", strlen("# i3 config file (v4)")) == 0 ||
strncasecmp(line, "workspace_layout", strlen("workspace_layout")) == 0) {
- printf("deciding for version 4 due to this line: %.*s\n", (int)(walk-line), line);
+ LOG("deciding for version 4 due to this line: %.*s\n", (int)(walk - line), line);
return 4;
}
strncasecmp(bind, "border borderless", strlen("border borderless")) == 0 ||
strncasecmp(bind, "--no-startup-id", strlen("--no-startup-id")) == 0 ||
strncasecmp(bind, "bar", strlen("bar")) == 0) {
- printf("deciding for version 4 due to this line: %.*s\n", (int)(walk-line), line);
+ LOG("deciding for version 4 due to this line: %.*s\n", (int)(walk - line), line);
return 4;
}
}
-next:
+ next:
/* advance to the next line */
walk++;
line = walk;
static char *argv[] = {
NULL, /* will be replaced by the executable path */
- NULL
- };
+ NULL};
exec_i3_utility("i3-migrate-config-to-v4", argv);
}
/* write the whole config file to the pipe, the script will read everything
* immediately */
- int written = 0;
- int ret;
- while (written < size) {
- if ((ret = write(writepipe[1], input + written, size - written)) < 0) {
- warn("Could not write to pipe");
- return NULL;
- }
- written += ret;
+ if (writeall(writepipe[1], input, size) == -1) {
+ warn("Could not write to pipe");
+ return NULL;
}
close(writepipe[1]);
/* read the script’s output */
int conv_size = 65535;
char *converted = malloc(conv_size);
- int read_bytes = 0;
+ int read_bytes = 0, ret;
do {
if (read_bytes == conv_size) {
conv_size += 65535;
fprintf(stderr, "Migration process exit code was != 0\n");
if (returncode == 2) {
fprintf(stderr, "could not start the migration script\n");
- /* TODO: script was not found. tell the user to fix his system or create a v4 config */
+ /* TODO: script was not found. tell the user to fix their system or create a v4 config */
} else if (returncode == 1) {
fprintf(stderr, "This already was a v4 config. Please add the following line to your config file:\n");
fprintf(stderr, "# i3 config file (v4)\n");
- /* TODO: nag the user with a message to include a hint for i3 in his config file */
+ /* TODO: nag the user with a message to include a hint for i3 in their config file */
}
return NULL;
}
* parse_config and possibly launching i3-nagbar.
*
*/
-void parse_file(const char *f) {
+bool parse_file(const char *f, bool use_nagbar) {
SLIST_HEAD(variables_head, Variable) variables = SLIST_HEAD_INITIALIZER(&variables);
int fd, ret, read_bytes = 0;
struct stat stbuf;
char *next;
for (next = bufcopy;
next < (bufcopy + stbuf.st_size) &&
- (next = strcasestr(next, current->key)) != NULL;
+ (next = strcasestr(next, current->key)) != NULL;
next += strlen(current->key)) {
*next = '_';
extra_bytes += extra;
while (walk < (buf + stbuf.st_size)) {
/* Find the next variable */
SLIST_FOREACH(current, &variables, variables)
- current->next_match = strcasestr(walk, current->key);
+ current->next_match = strcasestr(walk, current->key);
nearest = NULL;
int distance = stbuf.st_size;
SLIST_FOREACH(current, &variables, variables) {
free(new);
new = converted;
} else {
- printf("\n");
- printf("**********************************************************************\n");
- printf("ERROR: Could not convert config file. Maybe i3-migrate-config-to-v4\n");
- printf("was not correctly installed on your system?\n");
- printf("**********************************************************************\n");
- printf("\n");
+ LOG("\n");
+ LOG("**********************************************************************\n");
+ LOG("ERROR: Could not convert config file. Maybe i3-migrate-config-to-v4\n");
+ LOG("was not correctly installed on your system?\n");
+ LOG("**********************************************************************\n");
+ LOG("\n");
}
}
-
context = scalloc(sizeof(struct context));
context->filename = f;
check_for_duplicate_bindings(context);
- if (context->has_errors || context->has_warnings) {
- ELOG("FYI: You are using i3 version " I3_VERSION "\n");
+ if (use_nagbar && (context->has_errors || context->has_warnings)) {
+ ELOG("FYI: You are using i3 version %s\n", i3_version);
if (version == 3)
ELOG("Please convert your configfile first, then fix any remaining errors (see above).\n");
char *editaction,
- *pageraction;
+ *pageraction;
sasprintf(&editaction, "i3-sensible-editor \"%s\" && i3-msg reload\n", f);
sasprintf(&pageraction, "i3-sensible-pager \"%s\"\n", errorfilename);
char *argv[] = {
"-t",
(context->has_errors ? "error" : "warning"),
"-m",
- (context->has_errors ?
- "You have an error in your i3 config file!" :
- "Your config is outdated. Please fix the warnings to make sure everything works."),
+ (context->has_errors ? "You have an error in your i3 config file!" : "Your config is outdated. Please fix the warnings to make sure everything works."),
"-b",
"edit config",
editaction,
(errorfilename ? "-b" : NULL),
(context->has_errors ? "show errors" : "show warnings"),
pageraction,
- NULL
- };
+ NULL};
start_nagbar(&config_error_nagbar_pid, argv);
free(editaction);
free(pageraction);
}
+ bool has_errors = context->has_errors;
+
FREE(context->line_copy);
free(context);
free(new);
SLIST_REMOVE_HEAD(&variables, variables);
FREE(current);
}
+
+ return !has_errors;
}
#endif