/* Copyright 2005-2006 Garrett Rooney. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "tree.h" #include "etl_variables.h" #include "etl_array.h" struct etl_variable_t { etl_variable_type_t type; union { char *s; int64_t i; etl_array_t *a; etl_tree_node_t *h; } contents; }; etl_variable_t * etl_variable_make_int(int64_t i) { etl_variable_t *v = malloc(sizeof(*v)); v->type = ETL_VARIABLE_INTEGER; v->contents.i = i; return v; } etl_variable_t * etl_variable_make_str(const char *str) { etl_variable_t *v = malloc(sizeof(*v)); v->type = ETL_VARIABLE_STRING; v->contents.s = strdup(str); return v; } typedef struct { const char *key; etl_variable_t *val; } tree_content_t; static int compare(void *a, void *b) { tree_content_t *one = a, *two = b; return strcmp(one->key, two->key); } static void cleanup(void *content, void *baton) { tree_content_t *c = content; free((char *) c->key); etl_variable_destroy(c->val); free(c); } static etl_tree_vtbl_t vtable = { compare, cleanup }; etl_variable_t * etl_variable_make_hash() { etl_variable_t *h = malloc(sizeof(*h)); h->type = ETL_VARIABLE_HASH; h->contents.h = NULL; return h; } static void destroy_var(void *v, void *baton) { etl_variable_destroy(v); } void etl_variable_destroy(etl_variable_t *var) { if (! var) return; switch (var->type) { case ETL_VARIABLE_HASH: etl_tree_destroy(var->contents.h, NULL); break; case ETL_VARIABLE_STRING: free(var->contents.s); break; case ETL_VARIABLE_INTEGER: break; case ETL_VARIABLE_ARRAY: { etl_array_destroy(var->contents.a, destroy_var, NULL); } break; default: abort(); } free(var); } etl_variable_t * etl_variable_make_array(uint32_t nitems) { etl_variable_t *a = malloc(sizeof(*a)); a->type = ETL_VARIABLE_ARRAY; a->contents.a = etl_array_create(nitems); return a; } etl_variable_type_t etl_variable_type(const etl_variable_t *var) { return var->type; } const char * etl_variable_content_str(const etl_variable_t *var) { assert(var->type == ETL_VARIABLE_STRING); return var->contents.s; } uint64_t etl_variable_content_int(const etl_variable_t *var) { assert(var->type == ETL_VARIABLE_INTEGER); return var->contents.i; } uint32_t etl_variable_array_nelts(const etl_variable_t *var) { assert(var->type == ETL_VARIABLE_ARRAY); return etl_array_nelts(var->contents.a); } const etl_variable_t * etl_variable_array_idx(const etl_variable_t *arr, uint32_t idx) { assert(arr->type == ETL_VARIABLE_ARRAY); return etl_array_idx(arr->contents.a, idx); } const etl_variable_t * etl_variable_hash_get(const etl_variable_t *var, const char *key) { etl_tree_node_t *tn; tree_content_t content; assert(var->type == ETL_VARIABLE_HASH); if (! var->contents.h) return NULL; content.key = key; content.val = NULL; tn = etl_tree_find(var->contents.h, &content); if (tn) return ((tree_content_t *) tn->content)->val; else return NULL; } typedef struct { void (*callback)(const char *, etl_variable_t *, void *); void *baton; } tree_traverse_baton_t; static void tree_traverse_callback(etl_tree_node_t *node, void *b) { tree_content_t *content = node->content; tree_traverse_baton_t *baton = b; baton->callback(content->key, content->val, baton->baton); } void etl_variable_hash_traverse(const etl_variable_t *hash, void (*callback)(const char *key, etl_variable_t *val, void *baton), void *b) { tree_traverse_baton_t baton; assert(hash->type == ETL_VARIABLE_HASH); baton.callback = callback; baton.baton = b; etl_tree_traverse(hash->contents.h, tree_traverse_callback, &baton); } const etl_variable_t * etl_variable_false() { static etl_variable_t f = { ETL_VARIABLE_INTEGER, { (void *) 0 } }; return &f; } const etl_variable_t * etl_variable_true() { static etl_variable_t t = { ETL_VARIABLE_INTEGER, { (void *) 1 } }; return &t; } void etl_variable_str_set(etl_variable_t *str, const char *val) { assert(str->type == ETL_VARIABLE_STRING); free(str->contents.s); str->contents.s = strdup(val); } void etl_variable_int_set(etl_variable_t *var, int64_t val) { assert(var->type == ETL_VARIABLE_INTEGER); var->contents.i = val; } void etl_variable_hash_set(etl_variable_t *hash, const char *key, etl_variable_t *val) { tree_content_t *tc = malloc(sizeof(*tc)); assert(hash->type == ETL_VARIABLE_HASH); tc->key = strdup(key); tc->val = val; /* XXX free existing value? */ if (! hash->contents.h) hash->contents.h = etl_tree_create(tc, &vtable); else etl_tree_insert(hash->contents.h, tc); } void etl_variable_array_push(etl_variable_t *arr, etl_variable_t *item) { assert(arr->type == ETL_VARIABLE_ARRAY); etl_array_push(arr->contents.a, item); }