static void report_parsing_error(ParsingErrors error) { if(error == PE_INVALID_EXPRESSION) { text_buffer_addf("%s: %s", "Invalid expression", get_last_position()); } else if(error == PE_MISSING_QUOTE) { text_buffer_addf("%s: %s", "Invalid :let expression (missing quote)", get_last_position()); } else { assert(0 && "Unexpected parsing error code."); } }
var_t function_call(const char func_name[], const call_info_t *call_info) { function_t *function = find_function(func_name); if(function == NULL) { text_buffer_addf("%s: %s", "Unknown function", func_name); return var_error(); } if(call_info->argc < function->arg_count) { text_buffer_addf("%s: %s", "Not enough arguments for function", func_name); return var_error(); } if(call_info->argc > function->arg_count) { text_buffer_addf("%s: %s", "Too many arguments for function", func_name); return var_error(); } return function->ptr(call_info); }
/* Adds value(s) to the option (+= operator). Returns zero on success. */ static int set_add(opt_t *opt, const char value[]) { if(opt->type != OPT_INT && opt->type != OPT_SET && opt->type != OPT_STRLIST && opt->type != OPT_CHARSET) return -1; if(opt->type == OPT_INT) { char *p; int i; i = strtol(value, &p, 10); if(*p != '\0') return -1; if(i == 0) return 0; opt->val.int_val += i; notify_option_update(opt, OP_MODIFIED, opt->val); } else if(opt->type == OPT_SET) { if(set_op(opt, value, SO_ADD)) { notify_option_update(opt, OP_MODIFIED, opt->val); } } else if(opt->type == OPT_CHARSET) { const size_t valid_len = strspn(value, *opt->vals); if(valid_len != strlen(value)) { text_buffer_addf("Illegal character: <%c>", value[valid_len]); return -1; } if(charset_add_all(opt, value)) { notify_option_update(opt, OP_MODIFIED, opt->val); } } else if(*value != '\0') { opt->val.str_val = str_add(opt->val.str_val, value); notify_option_update(opt, OP_MODIFIED, opt->val); } return 0; }
int unlet_variables(const char *cmd) { int error = 0; assert(initialized); while(*cmd != '\0') { envvar_t *record; char name[VAR_NAME_MAX + 1]; char *p; int envvar = 1; /* check if its environment variable */ if(*cmd != '$') envvar = 0; else cmd++; /* copy variable name */ p = name; while(*cmd != '\0' && char_is_one_of(ENV_VAR_NAME_CHARS, *cmd) && p - name < sizeof(name) - 1) *p++ = *cmd++; *p = '\0'; if(*cmd != '\0' && !isspace(*cmd)) { text_buffer_add("Trailing characters"); error++; break; } cmd = skip_whitespace(cmd); /* currently we support only environment variables */ if(!envvar) { text_buffer_addf("%s: %s", "Unsupported variable type", name); cmd = skip_non_whitespace(cmd); error++; continue; } /* test for empty variable name */ if(name[0] == '\0') { text_buffer_addf("%s: %s", "Unsupported variable name", "empty name"); error++; continue; } record = find_record(name); if(record == NULL || record->removed) { text_buffer_addf("%s: %s", "No such variable", name); error++; continue; } if(record->from_parent) record->removed = 1; else free_record(record); env_remove(name); } return error; }
int let_variable(const char *cmd) { char name[VAR_NAME_MAX + 1]; char *p; int append = 0; var_t res_var; char *str_var; ParsingErrors parsing_error; assert(initialized); /* currently we support only environment variables */ if(*cmd != '$') { text_buffer_add("Incorrect variable type"); return -1; } cmd++; /* copy variable name */ p = name; while(*cmd != '\0' && char_is_one_of(ENV_VAR_NAME_CHARS, *cmd) && *cmd != '.' && *cmd != '=' && p - name < sizeof(name) - 1) { if(*cmd != '_' && !isalnum(*cmd)) { text_buffer_add("Incorrect variable name"); return -1; } *p++ = *cmd++; } /* test for empty variable name */ if(p == name) { text_buffer_addf("%s: %s", "Unsupported variable name", "empty name"); return -1; } *p = '\0'; cmd = skip_whitespace(cmd); /* check for dot and skip it */ if(*cmd == '.') { append = 1; cmd++; } /* check for equal sign and skip it */ if(*cmd != '=') { text_buffer_addf("%s: %s", "Incorrect :let statement", "'=' expected"); return -1; } parsing_error = parse(cmd + 1, &res_var); if(parsing_error != PE_NO_ERROR) { report_parsing_error(parsing_error); return -1; } if(get_last_position() != NULL && *get_last_position() != '\0') { text_buffer_addf("%s: %s", "Incorrect :let statement", "trailing characters"); return -1; } /* update environment variable */ str_var = var_to_string(res_var); if(append) append_envvar(name, str_var); else set_envvar(name, str_var); free(str_var); var_free(res_var); return 0; }
/* Assigns value to an option of all kinds except boolean. Returns non-zero in * case of error. */ static int set_set(opt_t *opt, const char value[]) { if(opt->type == OPT_BOOL) return -1; if(opt->type == OPT_SET) { if(set_op(opt, value, SO_SET)) { notify_option_update(opt, OP_SET, opt->val); } } else if(opt->type == OPT_ENUM) { int i = find_val(opt, value); if(i == -1) return -1; if(opt->val.enum_item != i) { opt->val.enum_item = i; notify_option_update(opt, OP_SET, opt->val); } } else if(opt->type == OPT_STR || opt->type == OPT_STRLIST) { if(opt->val.str_val == NULL || strcmp(opt->val.str_val, value) != 0) { (void)replace_string(&opt->val.str_val, value); notify_option_update(opt, OP_SET, opt->val); } } else if(opt->type == OPT_INT) { char *end; int int_val = strtoll(value, &end, 10); if(opt->val.int_val != int_val) { opt->val.int_val = int_val; notify_option_update(opt, OP_SET, opt->val); } } else if(opt->type == OPT_CHARSET) { const size_t valid_len = strspn(value, *opt->vals); if(valid_len != strlen(value)) { text_buffer_addf("Illegal character: <%c>", value[valid_len]); return -1; } if(charset_set(opt, value)) { notify_option_update(opt, OP_SET, opt->val); } } else { assert(0 && "Unknown type of option."); } return 0; }
/* Processes one :set statement. Returns zero on success. */ static int process_option(const char arg[]) { char option[OPTION_NAME_MAX + 1]; int err; const char *p; opt_t *opt; p = skip_alphas(arg); snprintf(option, p - arg + 1, "%s", arg); if(strcmp(option, "all") == 0) { print_options(); return 0; } opt = get_option(option); if(opt == NULL) { text_buffer_addf("%s: %s", "Unknown option", arg); return 1; } err = 0; if(*p == '\0') { opt_t *o = find_option(option); if(o != NULL) { if(o->type == OPT_BOOL) err = set_on(opt); else err = set_print(o); } else if(strncmp(option, "no", 2) == 0) { err = set_off(opt); } else if(strncmp(option, "inv", 3) == 0) { err = set_inv(opt); } } else if(char_is_one_of(ENDING_CHARS, *p)) { if(*(p + 1) != '\0') { text_buffer_addf("%s: %s", "Trailing characters", arg); return 1; } if(*p == '!') err = set_inv(opt); else if(*p == '?') err = set_print(opt); else err = set_reset(opt); } else if(strncmp(p, "+=", 2) == 0) { err = set_add(opt, p + 2); } else if(strncmp(p, "-=", 2) == 0) { err = set_remove(opt, p + 2); } else if(*p == '=' || *p == ':') { err = set_set(opt, p + 1); } else { text_buffer_addf("%s: %s", "Trailing characters", arg); } if(err) { text_buffer_addf("%s: %s", "Invalid argument", arg); } return err; }