diff --git a/libobs/util/cf-lexer.c b/libobs/util/cf-lexer.c index 0212cda3978c11..77ccc361d4a3ef 100644 --- a/libobs/util/cf-lexer.c +++ b/libobs/util/cf-lexer.c @@ -759,6 +759,28 @@ static inline struct cf_def *cf_preprocess_get_def(struct cf_preprocessor *pp, c return pp->defines.array + idx; } +bool cf_preprocess_get_def_value(struct cf_preprocessor *pp, const struct strref *def_name, int *value) +{ + struct cf_def *def = cf_preprocess_get_def(pp, def_name); + if (def == NULL || def->macro) + return false; + + for (size_t i = 0; i < def->tokens.num; i++) { + if (def->tokens.array[i].type == CFTOKEN_SPACETAB) + continue; + if (def->tokens.array[i].type == CFTOKEN_NUM && + sscanf(def->tokens.array[i].str.array, "%i", value) == 1) + return true; + + if (def->tokens.array[i].type == CFTOKEN_NAME && + cf_preprocess_get_def_value(pp, &def->tokens.array[i].str, value)) + return true; + + return false; + } + return false; +} + static char space_filler[2] = " "; static inline void append_space(struct cf_preprocessor *pp, cf_token_array_t *tokens, const struct cf_token *base) @@ -887,6 +909,87 @@ static inline bool cf_preprocess_subblock(struct cf_preprocessor *pp, bool ignor return !eof; } +static void cf_preprocess_if(struct cf_preprocessor *pp, struct cf_token **p_cur_token) +{ + struct cf_token *cur_token = *p_cur_token; + + int value_a = 0; + int value_b = 0; + + next_token(&cur_token, true); + if ((cur_token->type != CFTOKEN_NAME || !cf_preprocess_get_def_value(pp, &cur_token->str, &value_a)) && + (cur_token->type != CFTOKEN_NUM || sscanf(cur_token->str.array, "%i", &value_a) != 1)) { + cf_adderror_expecting(pp, cur_token, "identifier or number"); + go_to_newline(&cur_token); + goto exit; + } + next_token(&cur_token, true); + bool is_true = false; + if (cur_token->type == CFTOKEN_NEWLINE) { + is_true = value_a; + cur_token--; + } else { + if (cur_token->type != CFTOKEN_OTHER) { + cf_adderror_expecting(pp, cur_token, "comparator"); + go_to_newline(&cur_token); + goto exit; + } + struct strref comparator = cur_token->str; + cur_token++; + while (cur_token->type == CFTOKEN_OTHER) { + comparator.len += cur_token->str.len; + cur_token++; + } + cur_token--; + next_token(&cur_token, true); + if ((cur_token->type != CFTOKEN_NAME || !cf_preprocess_get_def_value(pp, &cur_token->str, &value_b)) && + (cur_token->type != CFTOKEN_NUM || sscanf(cur_token->str.array, "%i", &value_b) != 1)) { + cf_adderror_expecting(pp, cur_token, "identifier or number"); + go_to_newline(&cur_token); + goto exit; + } + + if (strref_cmp(&comparator, "==") == 0) { + is_true = value_a == value_b; + } else if (strref_cmp(&comparator, ">=") == 0) { + is_true = value_a >= value_b; + } else if (strref_cmp(&comparator, "<=") == 0) { + is_true = value_a <= value_b; + } else if (strref_cmp(&comparator, "!=") == 0) { + is_true = value_a != value_b; + } else if (strref_cmp(&comparator, "<") == 0) { + is_true = value_a < value_b; + } else if (strref_cmp(&comparator, ">") == 0) { + is_true = value_a > value_b; + } else { + cf_adderror_expecting(pp, cur_token, "comparator"); + go_to_newline(&cur_token); + goto exit; + } + } + + if (!cf_preprocess_subblock(pp, !is_true, &cur_token)) + goto exit; + + if (strref_cmp(&cur_token->str, "else") == 0) { + if (!cf_preprocess_subblock(pp, is_true, &cur_token)) + goto exit; + } else if (strref_cmp(&cur_token->str, "elif") == 0) { + if (is_true) { + if (!cf_preprocess_subblock(pp, is_true, &cur_token)) + goto exit; + } else { + cf_preprocess_if(pp, &cur_token); + goto exit; + } + } + + cur_token++; + +exit: + *p_cur_token = cur_token; +} + static void cf_preprocess_ifdef(struct cf_preprocessor *pp, bool ifnot, struct cf_token **p_cur_token) { struct cf_token *cur_token = *p_cur_token; @@ -909,7 +1012,16 @@ static void cf_preprocess_ifdef(struct cf_preprocessor *pp, bool ifnot, struct c if (strref_cmp(&cur_token->str, "else") == 0) { if (!cf_preprocess_subblock(pp, is_true, &cur_token)) goto exit; - /*} else if (strref_cmp(&cur_token->str, "elif") == 0) {*/ + + } else if (strref_cmp(&cur_token->str, "elif") == 0) { + if (is_true) { + if (!cf_preprocess_subblock(pp, is_true, &cur_token)) + goto exit; + + } else { + cf_preprocess_if(pp, &cur_token); + goto exit; + } } cur_token++; @@ -937,10 +1049,10 @@ static bool cf_preprocessor(struct cf_preprocessor *pp, bool if_block, struct cf } else if (strref_cmp(&cur_token->str, "ifndef") == 0) { cf_preprocess_ifdef(pp, true, p_cur_token); - /*} else if (strref_cmp(&cur_token->str, "if") == 0) { - TODO;*/ - } else if (strref_cmp(&cur_token->str, "else") == 0 || - /*strref_cmp(&cur_token->str, "elif") == 0 ||*/ + } else if (strref_cmp(&cur_token->str, "if") == 0) { + cf_preprocess_if(pp, p_cur_token); + + } else if (strref_cmp(&cur_token->str, "else") == 0 || strref_cmp(&cur_token->str, "elif") == 0 || strref_cmp(&cur_token->str, "endif") == 0) { if (!if_block) { struct dstr name;