int _config_del(config_t *cfg, const char *section, const char *entry) { int start; char *tmp, *value; unsigned int line = 0, end; if ( ! entry ) { start = search_section(cfg, section, 0); if ( start < 0 ) return start; for ( end = (unsigned int) start + 1; end < cfg->elements && ! is_section(cfg->content[end]); end++ ); while ( start >= 2 && ! *cfg->content[start - 1] && ! *cfg->content[start - 2] ) start--; } else { start = search_entry(cfg, section, entry, &line, &tmp, &value); if ( start < 0 ) return start; free_val(&tmp); free_val(&value); end = (unsigned int) start + 1; } cfg->need_sync = TRUE; return op_delete_line(cfg, start, end); }
enum v7_err v7_call(struct v7 *v7, int num_args) { struct v7_val **top = v7_top(v7), **v = top - (num_args + 1), *f = v[0]; if (v7->no_exec) return V7_OK; CHECK(v7->sp > num_args, V7_INTERNAL_ERROR); CHECK(f->type == V7_FUNC || f->type == V7_C_FUNC, V7_CALLED_NON_FUNCTION); // Return value will substitute function objest on a stack v[0] = v7_mkval(v7, V7_UNDEF); // Set return value to 'undefined' v[0]->ref_count++; if (f->type == V7_FUNC) { const char *src = v7->cursor; v7->cursor = f->v.func; // Move control flow to function body TRY(parse_function_definition(v7, v, num_args)); // Execute function body v7->cursor = src; // Return control flow if (v7_top(v7) > top) { // If function body pushed some value on stack, free_val(v7, v[0]); v[0] = top[0]; // use that value as return value v[0]->ref_count++; } } else if (f->type == V7_C_FUNC) { f->v.c_func(v7, v7->cur_obj, v[0], v + 1, num_args); } free_val(v7, f); TRY(inc_stack(v7, - (int) (v7_top(v7) - (v + 1)))); // Clean up stack return V7_OK; }
static enum v7_err del_key(struct v7 *v7, struct v7_val *obj, const struct v7_val *key) { struct v7_prop **p; CHECK(obj->type == V7_OBJ, V7_TYPE_MISMATCH); for (p = &obj->v.props; *p != NULL; p = &p[0]->next) { if (cmp(key, p[0]->key)) { struct v7_prop *next = p[0]->next; free_val(v7, p[0]->key); free_val(v7, p[0]->val); free(p[0]); p[0] = next; break; } } return V7_OK; }
static int new_entry_line(config_t *cfg, const char *entry, const char *val, unsigned int *index) { int ret; char *eout, *vout; ret = search_entry(cfg, NULL, entry, index, &eout, &vout); if ( ret < 0 ) return op_insert_line(cfg, create_new_line(entry, val), *index); free_val(&eout); free_val(&vout); op_modify_line(&cfg->content[*index], create_new_line(entry, val)); return 0; }
struct_t *struct_val(val_t val) { struct_t *ret = & (struct_t) { 0, "" }; if (val -> type == STRUCT) ret = val -> data.struct_; free_val(val); return ret; }
sb_t *sb_val(val_t val) { sb_t *ret = & (sb_t) { 0 }; if (val -> type == SB) ret = val -> data.sb; free_val(val); return ret; }
// function_defition = "function" "(" func_params ")" "{" func_body "}" static enum v7_err parse_function_definition(struct v7 *v7, struct v7_val **v, int num_params) { int i = 0, old_no_exec = v7->no_exec, old_sp = v7->sp; const char *src = v7->cursor; // If 'v' (func to call) is NULL, that means we're just parsing function // definition to save it's body. v7->no_exec = v == NULL; TRY(match(v7, '(')); // Initialize new scope if (!v7->no_exec) { v7->current_scope++; CHECK(v7->current_scope < (int) ARRAY_SIZE(v7->scopes), V7_RECURSION_TOO_DEEP); CHECK(v7->scopes[v7->current_scope].v.props == NULL, V7_INTERNAL_ERROR); CHECK(v7->scopes[v7->current_scope].type == V7_OBJ, V7_INTERNAL_ERROR); } while (*v7->cursor != ')') { TRY(parse_identifier(v7)); if (!v7->no_exec) { struct v7_val *key = v7_mkval_str(v7, v7->tok, v7->tok_len); struct v7_val *val = i < num_params ? v[i + 1] : v7_mkval(v7, V7_UNDEF); v7_set(v7, &v7->scopes[v7->current_scope], key, val); } i++; if (!test_and_skip_char(v7, ',')) break; } TRY(match(v7, ')')); TRY(match(v7, '{')); while (*v7->cursor != '}') { int is_return_statement = 0; inc_stack(v7, old_sp - v7->sp); // Clean up the stack from prev stmt TRY(parse_statement(v7, &is_return_statement)); if (is_return_statement) break; // Leave statement value on stack } if (v7->no_exec) { TRY(v7_make_and_push(v7, V7_FUNC)); v7_top(v7)[-1]->v.func = v7_strdup(src, (v7->cursor + 1) - src); } TRY(match(v7, '}')); // Deinitialize scope if (!v7->no_exec) { v7->scopes[v7->current_scope].ref_count = 1; // Force free_val() below free_val(v7, &v7->scopes[v7->current_scope]); v7->current_scope--; assert(v7->current_scope >= 0); } v7->no_exec = old_no_exec; return V7_OK; }
static int new_section_line(config_t *cfg, const char *section, const char *entry, const char *val, unsigned int *index) { int ret; char *eout, *vout; unsigned int eindex; ret = search_section(cfg, section, *index); if ( ret < 0 ) { char buf[1024]; snprintf(buf, sizeof(buf), "[%s]", section); if ( *index ) *index = adjust_insertion_point(cfg, *index); else *index = cfg->elements; ret = op_insert_line(cfg, strdup(buf), *index); if ( ret < 0 ) return ret; return (! entry) ? 0 : op_insert_line(cfg, create_new_line(entry, val), *index + 1); } *index = ret; if ( ! entry ) return 0; eindex = *index + 1; ret = search_entry(cfg, section, entry, &eindex, &eout, &vout); if ( ret < 0 ) return op_insert_line(cfg, create_new_line(entry, val), eindex); free_val(&eout); free_val(&vout); op_modify_line(&cfg->content[eindex], create_new_line(entry, val)); return 0; }
void free_const_decl(constdecllist_t const_decls) { for (unsigned i = 0; i < const_decls.size; ++i) { free(const_decls.data[i]->type); free(const_decls.data[i]->ident); free_val(const_decls.data[i]->val); free(const_decls.data[i]); } list_free(const_decls); }
static void free_val(struct v7 *v7, struct v7_val *v) { v->ref_count--; assert(v->ref_count >= 0); if (v->ref_count > 0) return; if (v->type == V7_OBJ && !(v->flags & PROP_RO)) { struct v7_prop *p, *tmp; for (p = v->v.props; p != NULL; p = tmp) { tmp = p->next; free_val(v7, p->key); free_val(v7, p->val); free(p); } v->v.props = NULL; } else if (v->type == V7_STR && !(v->flags & STR_RO)) { free(v->v.str.buf); } else if (v->type == V7_FUNC && !(v->flags & STR_RO)) { free(v->v.func); } unlink_val(&v7->values, v); if (!(v->flags & VAL_RO)) free(v); }
void v7_destroy(struct v7 **v7) { size_t i; if (v7 == NULL || v7[0] == NULL) return; assert(v7[0]->sp >= 0); inc_stack(v7[0], -v7[0]->sp); for (i = 0; i < ARRAY_SIZE(v7[0]->scopes); i++) { v7[0]->scopes[i].ref_count = 1; // Force free_val() below to free memory free_val(v7[0], &v7[0]->scopes[i]); } free(v7[0]); v7[0] = NULL; }
/* * Search an entry (delimited by '=' character) in content. * returns the line number matching 'entry' or -1. */ static int search_entry(config_t *cfg, const char *section, const char *entry, unsigned int *index, char **eout, char **vout) { int ret; unsigned int i = *index; if ( ! cfg->content || i >= cfg->elements ) return -1; if ( section && ! index ) { ret = search_section(cfg, section, 0); if ( ret < 0 ) return ret; i = (unsigned int) ret + 1; } for ( ; i < cfg->elements; i++ ) { if ( section && is_section(cfg->content[i]) ) return -1; ret = parse_buffer(cfg->content[i], eout, vout); if ( ret < 0 || ! *eout ) continue; ret = strcmp(entry, *eout); if ( ret == 0 ) { *index = i; return 0; } free_val(eout); free_val(vout); } return -1; }
/* * _config_get_next: * @cfg: Configuration file identifier. * @section: Pointer address where the current section should be stored. * @entry: Pointer address where the current entry should be stored. * @value: Pointer address where the current value should be stored. * @line: Pointer to a line number we should start the search at. * * Parses the whole configuration file starting at @line, * and stores the current section, entry and value within the * provided argument. * * The caller has to call config_get_next() until it returns -1 * or memory will be leaked. * * If the value gathered starts with a '$', which means it is * a variable, the variable is automatically looked up. * * Returns: 0 on success, -1 if there is nothing more to read. */ int _config_get_next(config_t *cfg, char **section, char **entry, char **value, unsigned int *line) { int ret; char *ptr; free_val(entry); free_val(value); free_val(section); if ( ! cfg->content || *line >= cfg->elements ) return -1; while ( *line < cfg->elements ) { ptr = cfg->content[*line]; ptr += strspn(ptr, " \t\r"); (*line)++; if ( ! *ptr || is_line_commented(ptr) ) continue; if ( is_section(ptr) ) return parse_section_buffer(ptr, section, value, FALSE); ret = parse_buffer(ptr, entry, value); if ( ret >= 0 && **entry == '$' ) { free_val(entry); free_val(value); continue; } return ret; } (*line)--; return -1; }
static enum v7_err inc_stack(struct v7 *v7, int incr) { int i; CHECK(v7->sp + incr < (int) ARRAY_SIZE(v7->stack), V7_STACK_OVERFLOW); CHECK(v7->sp + incr >= 0, V7_STACK_UNDERFLOW); // Free values pushed on stack (like string literals and functions) for (i = 0; incr < 0 && i < -incr && i < v7->sp; i++) { free_val(v7, v7->stack[v7->sp - (i + 1)]); v7->stack[v7->sp - (i + 1)] = NULL; } v7->sp += incr; return V7_OK; }
// variable = identifier { '.' identifier | '[' expression ']' } static enum v7_err parse_variable(struct v7 *v7) { struct v7_val **v = NULL, key = str_to_val(v7->tok, v7->tok_len); struct v7_val *ns = find(v7, &key), ro_prop; if (!v7->no_exec) { TRY(v7_make_and_push(v7, V7_UNDEF)); v = v7_top(v7); } while (*v7->cursor == '.' || *v7->cursor == '[') { int ch = *v7->cursor; TRY(match(v7, ch)); CHECK(v7->no_exec || ns != NULL, V7_SYNTAX_ERROR); v7->cur_obj = ns; if (ch == '.') { TRY(parse_identifier(v7)); if (!v7->no_exec) { key = str_to_val(v7->tok, v7->tok_len); ns = get2(ns, &key); if (ns != NULL && ns->type == V7_RO_PROP) { ns->v.prop_func(v7->cur_obj, &ro_prop); ns = &ro_prop; } } } else { TRY(parse_expression(v7)); TRY(match(v7, ']')); if (!v7->no_exec) { ns = get2(ns, v7_top(v7)[-1]); if (ns != NULL && ns->type == V7_RO_PROP) { ns->v.prop_func(v7->cur_obj, &ro_prop); ns = &ro_prop; } TRY(inc_stack(v7, -1)); } } } if (v != NULL && ns != NULL) { free_val(v7, v[-1]); v[-1] = ns; v[-1]->ref_count++; } return V7_OK; }
void table_free(table *t, void (*free_val)(void *val)) { int i; tlink *cur, *n; assert(t); for (i=0; i<t->sz; i++) { cur = t->b[i]; while (cur) { if (free_val) free_val(cur->v); n = cur->next; FREE(cur); cur = n; } } FREE(t->b); FREE(t); }
void fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*)) { fp_pair_map_entry_t **ent, **next, *this; if (map) { for (ent = HT_START(fp_pair_map_impl, &(map->head)); ent != NULL; ent = next) { this = *ent; next = HT_NEXT_RMV(fp_pair_map_impl, &(map->head), ent); if (free_val) free_val(this->val); tor_free(this); } tor_assert(HT_EMPTY(&(map->head))); HT_CLEAR(fp_pair_map_impl, &(map->head)); tor_free(map); } }
float number_val(val_t val) { float ret; switch (val -> type) { case NUMBER: ret = val -> data.number; break; case INTEGER: ret = val -> data.integer; break; default: ret = 0; break; } free_val(val); return ret; }
static enum v7_err parse_assignment(struct v7 *v7, struct v7_val *obj) { const char *tok = v7->tok; unsigned long tok_len = v7->tok_len; struct v7_val **top = v7_top(v7); TRY(match(v7, '=')); TRY(parse_expression(v7)); if (!v7->no_exec) { TRY(v7_make_and_push_string(v7, tok, tok_len, 1)); v7_set(v7, obj, top[1], top[0]); CHECK(v7_top(v7) - top > 1, V7_INTERNAL_ERROR); CHECK(v7->sp > 1, V7_STACK_UNDERFLOW); free_val(v7, top[-1]); top[-1] = top[0]; top[-1]->ref_count++; inc_stack(v7, (int) (top - v7_top(v7))); } return V7_OK; }
enum v7_err v7_set(struct v7 *v7, struct v7_val *obj, struct v7_val *k, struct v7_val *v) { struct v7_prop *m = NULL; CHECK(obj != NULL && obj->type == V7_OBJ, V7_TYPE_MISMATCH); // Find attribute inside object if ((m = v7_get(obj, k)) == NULL) { m = vinsert(v7, &obj->v.props, k); CHECK(m != NULL, V7_OUT_OF_MEMORY); } if (m != NULL) { struct v7_val *tmp = m->val; v->ref_count++; m->val = v; free_val(v7, tmp); // Deallocate previous value } return V7_OK; }
void free_expression(struct expr *e) { switch (e->exprtype) { case valtype: free_val(e->val.val); break; case binopexprtype: free_expression(e->val.binopexpr.e1); free_expression(e->val.binopexpr.e2); break; case unopexprtype: free_expression(e->val.unopexpr.e); break; case arrayexprtype: free_expression(e->val.arrayexpr.e1); free_expressions(e->val.arrayexpr.indices); break; case identtype: free(e->val.ident); break; case dereftype: free_expression(e->val.deref.e); break; case funcalltype: free_args(e->val.funcall.args); free(e->val.funcall.fun_ident); break; case structelttype: free_expression(e->val.structelt.record); free(e->val.structelt.field); default: break; } if (e->type) free(e->type); free(e); }
static int parse_buffer(const char *str, char **entry, char **value) { int ret; size_t len; char *val; const char *ptr; *value = *entry = NULL; if ( ! *str ) return -1; ptr = strchr(str, '='); len = (ptr) ? (size_t) (ptr - str) : strlen(str); ret = strip_value(entry, str, len); if ( ret < 0 ) return ret; if ( ! ptr ) return 0; ret = strip_value(&val, ptr + 1, strlen(ptr + 1)); if ( ret < 0 ) return ret; if ( val ) ret = value_resolve_variable(val, value); free_val(&val); if ( ret < 0 ) return ret; if ( **entry == '$' ) ret = variable_set((*entry) + 1, *value); return ret; }
const char *symbol_val(val_t val) { const char *ret = ""; if (val -> type == SYMBOL) ret = val -> data.symbol; free_val(val); return ret; }
bool boolean_val(val_t val) { bool ret = true; if (val -> type == BOOLEAN) ret = val -> data.boolean; free_val(val); return ret; }
int integer_val(val_t val) { int ret = 0; if (val -> type == INTEGER) ret = val -> data.integer; free_val(val); return ret; }
char character_val(val_t val) { char ret = '\0'; if (val -> type == CHARACTER) ret = val -> data.character; free_val(val); return ret; }
char *string_val(val_t val) { char *ret = ""; if (val -> type == STRING) ret = val -> data.string; free_val(val); return ret; }
enum type type_val(val_t val) { enum type ret = val -> type; free_val(val); return ret; }
void deref(val_t val) { //printf("deref(p%p).\n", val); val -> ref--; free_val(val); }
function_t *function_val(val_t val) { function_t *ret = dummy; if (val -> type == FUNCTION) ret = val -> data.function; free_val(val); return ret; }