return item;
fail:
- ec_keyval_free(item->attrs);
+ ec_keyval_free(attrs);
ec_free(comp_cp);
ec_free(start_cp);
ec_free(full_cp);
struct ec_completed_item *ec_completed_iter_next(
struct ec_completed_iter *iter)
{
- struct ec_completed *completed = iter->completed;
+ struct ec_completed *completed;
struct ec_completed_group *cur_node;
struct ec_completed_item *cur_match;
+ if (iter == NULL)
+ return NULL;
+ completed = iter->completed;
if (completed == NULL)
return NULL;
#include <errno.h>
#include <ecoli_malloc.h>
+#include <ecoli_string.h>
#include <ecoli_log.h>
static ec_log_t ec_log_fct = ec_log_default_cb;
char *s;
int ret;
+ /* don't use ec_vasprintf here, because it will call
+ * ec_malloc(), then ec_log(), ec_vasprintf()...
+ * -> stack overflow */
ret = vasprintf(&s, format, ap);
if (ret < 0)
return ret;
#include <errno.h>
#include <ecoli_malloc.h>
+#include <ecoli_string.h>
#include <ecoli_strvec.h>
#include <ecoli_keyval.h>
#include <ecoli_log.h>
struct ec_node *__ec_node(const struct ec_node_type *type, const char *id)
{
struct ec_node *node = NULL;
- char buf[256]; // XXX
EC_LOG(EC_LOG_DEBUG, "create node type=%s id=%s\n",
type->name, id);
if (node->id == NULL)
goto fail;
- snprintf(buf, sizeof(buf), "<%s>", type->name);
- node->desc = ec_strdup(buf); // XXX ec_asprintf ?
- if (node->desc == NULL)
+ if (ec_asprintf(&node->desc, "<%s>", type->name) < 0)
goto fail;
node->attrs = ec_keyval();
return node;
fail:
- ec_keyval_free(node->attrs);
- ec_free(node->desc);
- ec_free(node->id);
+ if (node != NULL) {
+ ec_keyval_free(node->attrs);
+ ec_free(node->desc);
+ ec_free(node->id);
+ }
ec_free(node);
return NULL;
return node->id;
}
-struct ec_node *ec_node_parent(const struct ec_node *node)
-{
- return node->parent;
-}
-
static void __ec_node_dump(FILE *out,
const struct ec_node *node, size_t indent)
{
char *id;
char *desc;
struct ec_keyval *attrs;
- /* XXX ensure parent and child are properly set in all nodes */
- struct ec_node *parent;
unsigned int refcnt;
TAILQ_ENTRY(ec_node) next;
/* XXX add more accessors */
struct ec_keyval *ec_node_attrs(const struct ec_node *node);
-struct ec_node *ec_node_parent(const struct ec_node *node);
const char *ec_node_id(const struct ec_node *node);
const char *ec_node_desc(const struct ec_node *node);
static int ec_node_cmd_build(struct ec_node_cmd *node)
{
struct ec_node *expr = NULL, *lex = NULL, *cmd = NULL;
- struct ec_parsed *p, *child;
+ struct ec_parsed *p = NULL, *child;
void *result;
int ret;
table[node->len] = child;
node->len++;
- child->parent = gen_node;
TAILQ_INSERT_TAIL(&gen_node->children, child, next); // XXX really needed?
return 0;
gen_node = __ec_node(&ec_node_cmd_type, id);
if (gen_node == NULL)
- goto fail;
+ fail = 1;
- node = (struct ec_node_cmd *)gen_node;
- node->cmd_str = ec_strdup(cmd);
- if (node->cmd_str == NULL)
- goto fail;
+ if (fail == 0) {
+ node = (struct ec_node_cmd *)gen_node;
+ node->cmd_str = ec_strdup(cmd);
+ if (node->cmd_str == NULL)
+ fail = 1;
+ }
va_start(ap, cmd);
}
}
+ va_end(ap);
+
if (fail == 1)
goto fail;
- va_end(ap);
-
if (ec_node_cmd_build(node) < 0)
goto fail;
fail:
ec_node_free(gen_node); /* will also free children */
- va_end(ap);
return NULL;
}
snprintf(key, sizeof(key), "_dyn_%p", child);
ret = ec_keyval_set(ec_parsed_get_attrs(parsed), key, child,
(void *)node_free);
- if (ret < 0)
+ if (ret < 0) {
+ child = NULL; /* already freed */
goto fail;
+ }
return ec_node_parse_child(child, parsed, strvec);
snprintf(key, sizeof(key), "_dyn_%p", child);
ret = ec_keyval_set(completed->attrs, key, child,
(void *)node_free);
- if (ret < 0)
+ if (ret < 0) {
+ child = NULL; /* already freed */
goto fail;
+ }
return ec_node_complete_child(child, completed, strvec);
/* LCOV_EXCL_STOP */
static struct ec_test ec_node_expr_test = {
- .name = "expr",
+ .name = "node_expr",
.test = ec_node_expr_testcase,
};
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define _GNU_SOURCE /* for asprintf */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
if (is_dir) {
type = EC_COMP_PARTIAL;
- if (asprintf(&comp_str, "%s%s/", input,
+ if (ec_asprintf(&comp_str, "%s%s/", input,
&de->d_name[bname_len]) < 0) {
ret = -errno;
goto out;
}
- if (asprintf(&disp_str, "%s/", de->d_name) < 0) {
+ if (ec_asprintf(&disp_str, "%s/", de->d_name) < 0) {
ret = -errno;
goto out;
}
} else {
type = EC_COMP_FULL;
- if (asprintf(&comp_str, "%s%s", input,
+ if (ec_asprintf(&comp_str, "%s%s", input,
&de->d_name[bname_len]) < 0) {
ret = -errno;
goto out;
}
- if (asprintf(&disp_str, "%s", de->d_name) < 0) {
+ if (ec_asprintf(&disp_str, "%s", de->d_name) < 0) {
ret = -errno;
goto out;
}
goto out;
item = NULL;
- free(comp_str);
+ ec_free(comp_str);
comp_str = NULL;
- free(disp_str);
+ ec_free(disp_str);
disp_str = NULL;
}
ret = 0;
out:
- free(comp_str);
- free(disp_str);
+ ec_free(comp_str);
+ ec_free(disp_str);
ec_free(dname);
ec_free(bname);
if (dir != NULL)
p = ec_node_parse(node, "0");
s = ec_strvec_val(ec_parsed_strvec(p), 0);
- EC_TEST_ASSERT(s != NULL);
- EC_TEST_ASSERT(ec_node_uint_getval(node, s, &u64) == 0);
- EC_TEST_ASSERT (u64 == 0);
+ EC_TEST_ASSERT(s != NULL &&
+ ec_node_uint_getval(node, s, &u64) == 0 &&
+ u64 == 0);
ec_parsed_free(p);
p = ec_node_parse(node, "10");
s = ec_strvec_val(ec_parsed_strvec(p), 0);
- EC_TEST_ASSERT(s != NULL);
- EC_TEST_ASSERT(ec_node_uint_getval(node, s, &u64) == 0);
- EC_TEST_ASSERT(u64 == 10);
+ EC_TEST_ASSERT(s != NULL &&
+ ec_node_uint_getval(node, s, &u64) == 0 &&
+ u64 == 10);
ec_parsed_free(p);
ec_node_free(node);
p = ec_node_parse(node, "10");
s = ec_strvec_val(ec_parsed_strvec(p), 0);
- EC_TEST_ASSERT(s != NULL);
- EC_TEST_ASSERT(ec_node_int_getval(node, s, &i64) == 0);
- EC_TEST_ASSERT(i64 == 16);
+ EC_TEST_ASSERT(s != NULL &&
+ ec_node_int_getval(node, s, &i64) == 0 &&
+ i64 == 16);
ec_parsed_free(p);
ec_node_free(node);
node->child = child;
- child->parent = gen_node;
TAILQ_INSERT_TAIL(&gen_node->children, child, next); // XXX really needed?
return 0;
gen_node = __ec_node(&ec_node_once_type, id);
if (gen_node == NULL)
- return NULL;
+ goto fail;
ec_node_once_set(gen_node, child);
+ child = NULL;
return gen_node;
+
+fail:
+ ec_node_free(child);
+ return NULL;
}
/* LCOV_EXCL_START */
node->child = child;
- child->parent = gen_node;
TAILQ_INSERT_TAIL(&gen_node->children, child, next);
return &node->gen;
return -EINVAL;
table = ec_realloc(node->table, (node->len + 1) * sizeof(*node->table));
- if (table == NULL) {
- ec_node_free(child);
+ if (table == NULL)
return -1;
- }
node->table = table;
table[node->len] = child;
node->len++;
- child->parent = gen_node;
TAILQ_INSERT_TAIL(&gen_node->children, child, next);
return 0;
table[node->len] = child;
node->len++;
- child->parent = gen_node;
TAILQ_INSERT_TAIL(&gen_node->children, child, next); // XXX really needed?
return 0;
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define _GNU_SOURCE /* for asprintf */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ecoli_malloc.h>
#include <ecoli_log.h>
+#include <ecoli_string.h>
#include <ecoli_test.h>
#include <ecoli_strvec.h>
#include <ecoli_node.h>
goto fail;
while ((item = ec_completed_iter_next(iter)) != NULL) {
str = ec_completed_item_get_str(item);
- if (asprintf(&new_str, "%c%s%c", missing_quote, str,
+ if (ec_asprintf(&new_str, "%c%s%c", missing_quote, str,
missing_quote) < 0) {
new_str = NULL;
goto fail;
}
if (ec_completed_item_set_str(item, new_str) < 0)
goto fail;
- free(new_str);
+ ec_free(new_str);
new_str = NULL;
str = ec_completed_item_get_completion(item);
- if (asprintf(&new_str, "%s%c", str,
+ if (ec_asprintf(&new_str, "%s%c", str,
missing_quote) < 0) {
new_str = NULL;
goto fail;
}
if (ec_completed_item_set_completion(item, new_str) < 0)
goto fail;
- free(new_str);
+ ec_free(new_str);
new_str = NULL;
}
}
ec_completed_free(tmp_completed);
ec_completed_iter_free(iter);
ec_strvec_free(new_vec);
- free(new_str);
+ ec_free(new_str);
return -1;
}
table[node->len] = child;
node->len++;
- child->parent = gen_node;
TAILQ_INSERT_TAIL(&gen_node->children, child, next);
return 0;
node->child = child;
- child->parent = gen_node;
// XXX else it breaks the dump()
//TAILQ_INSERT_TAIL(&gen_node->children, child, next); // XXX really needed?
bool is_root, const struct ec_strvec *strvec)
{
struct ec_strvec *match_strvec;
- struct ec_parsed *child;
+ struct ec_parsed *child = NULL;
int ret;
if (node->type->parse == NULL)
child = state;
}
ret = node->type->parse(node, child, strvec);
- if (ret < 0) // XXX should we free state, child?
- return ret;
-
- if (ret == EC_PARSED_NOMATCH) {
- if (!is_root) {
- ec_parsed_del_child(state, child);
- assert(TAILQ_EMPTY(&child->children));
- ec_parsed_free(child);
- }
- return ret;
- }
+ if (ret < 0 || ret == EC_PARSED_NOMATCH)
+ goto free;
match_strvec = ec_strvec_ndup(strvec, 0, ret);
- if (match_strvec == NULL)
- return -ENOMEM;
+ if (match_strvec == NULL) {
+ ret = -ENOMEM;
+ goto free;
+ }
child->strvec = match_strvec;
return ret;
+
+free:
+ if (!is_root) {
+ ec_parsed_del_child(state, child);
+ ec_parsed_free(child);
+ }
+ return ret;
}
int ec_node_parse_child(const struct ec_node *node, struct ec_parsed *state,
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <stdarg.h>
#include <stddef.h>
#include <string.h>
+#include <stdio.h>
+#include <ecoli_assert.h>
+#include <ecoli_malloc.h>
#include <ecoli_string.h>
/* count the number of identical chars at the beginning of 2 strings */
return 0;
}
+
+int ec_vasprintf(char **buf, const char *fmt, va_list ap)
+{
+ char dummy;
+ int buflen, ret;
+ va_list aq;
+
+ va_copy(aq, ap);
+ *buf = NULL;
+ ret = vsnprintf(&dummy, 1, fmt, aq);
+ va_end(aq);
+ if (ret < 0)
+ return ret;
+
+ buflen = ret + 1;
+ *buf = ec_malloc(buflen);
+ if (*buf == NULL)
+ return -1;
+
+ va_copy(aq, ap);
+ ret = vsnprintf(*buf, buflen, fmt, aq);
+ va_end(aq);
+
+ ec_assert_print(ret < buflen, "invalid return value for vsnprintf");
+ if (ret < 0) {
+ free(*buf);
+ *buf = NULL;
+ return -1;
+ }
+
+ return ret;
+}
+
+int ec_asprintf(char **buf, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = ec_vasprintf(buf, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
/* return 1 if 's' starts with 'beginning' */
int ec_str_startswith(const char *s, const char *beginning);
+/* like asprintf, but use libecoli allocator */
+int ec_asprintf(char **buf, const char *fmt, ...);
+
+/* like vasprintf, but use libecoli allocator */
+int ec_vasprintf(char **buf, const char *fmt, va_list ap);
+
#endif
if (ec_vec_get(&vals, vec, 0) < 0)
GOTO_FAIL;
- if (strcmp(vals, "0"))
+ if (vals == NULL || strcmp(vals, "0"))
GOTO_FAIL;
if (ec_vec_get(&vals, vec, 1) < 0)
GOTO_FAIL;
- if (strcmp(vals, "1"))
+ if (vals == NULL || strcmp(vals, "1"))
GOTO_FAIL;
if (ec_vec_get(&vals, vec, 2) < 0)
GOTO_FAIL;
- if (strcmp(vals, "2"))
+ if (vals == NULL || strcmp(vals, "2"))
GOTO_FAIL;
ec_vec_free(vec);
struct debug_alloc_ftr *ftr;
size_t new_size = size + sizeof(*hdr) + sizeof(*ftr);
void *ret;
+ int r = random();
-
- if (alloc_fail_proba != 0 && (random() % 100) < alloc_fail_proba)
+ if (alloc_fail_proba != 0 && (r % 100) < alloc_fail_proba)
hdr = NULL;
else
hdr = malloc(new_size);
ftr->cookie = 0x87654321;
}
- EC_LOG(EC_LOG_DEBUG, "%s:%d: info: malloc(%zd) -> %p\n",
- file, line, size, ret);
+ EC_LOG(EC_LOG_DEBUG, "%s:%d: info: malloc(%zd) -> %p [rand=%d]\n",
+ file, line, size, ret, r);
+ if (r == 976499400)
+ printf("here\n");
if (ret)
alloc_success++;