srcs := ecoli_tk.c ecoli_tk_str.c ecoli_tk_seq.c
srcs += ecoli_tk_space.c ecoli_tk_or.c ecoli_test.c
srcs += ecoli_tk_empty.c ecoli_tk_int.c
-srcs += ecoli_malloc.c
+srcs += ecoli_malloc.c ecoli_log.c
shlib-y-$(O)libecoli.so := $(srcs)
exe-y-$(O)test = $(srcs) main.c
--- /dev/null
+/*
+ * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _GNU_SOURCE /* for vasprintf */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <ecoli_log.h>
+
+static ec_log_t ec_log_fct = ec_log_default;
+static void *ec_log_opaque;
+
+int ec_log_default(unsigned int level, void *opaque, const char *str)
+{
+ (void)opaque;
+ (void)level;
+
+ return printf("%s", str);
+}
+
+int ec_log_register(ec_log_t usr_log, void *opaque)
+{
+ if (usr_log == NULL)
+ return -1;
+
+ ec_log_fct = usr_log;
+ ec_log_opaque = opaque;
+
+ return 0;
+}
+
+void ec_log_unregister(void)
+{
+ ec_log_fct = NULL;
+}
+
+int ec_vlog(unsigned int level, const char *format, va_list ap)
+{
+ char *s;
+ int ret;
+
+ if (ec_log_fct == NULL) {
+ errno = ENODEV;
+ return -1;
+ }
+
+ ret = vasprintf(&s, format, ap);
+ if (ret < 0)
+ return ret;
+
+ ret = ec_log_fct(level, ec_log_opaque, s);
+ free(s);
+
+ return ret;
+}
+
+int ec_log(unsigned int level, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = ec_vlog(level, format, ap);
+ va_end(ap);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ECOLI_LOG_
+#define ECOLI_LOG_
+
+#define EC_LOG_EMERG 0 /* system is unusable */
+#define EC_LOG_ALERT 1 /* action must be taken immediately */
+#define EC_LOG_CRIT 2 /* critical conditions */
+#define EC_LOG_ERR 3 /* error conditions */
+#define EC_LOG_WARNING 4 /* warning conditions */
+#define EC_LOG_NOTICE 5 /* normal but significant condition */
+#define EC_LOG_INFO 6 /* informational */
+#define EC_LOG_DEBUG 7 /* debug-level messages */
+
+#include <stdarg.h>
+
+/* return -1 on error, len(s) on success */
+typedef int (*ec_log_t)(unsigned int level, void *opaque, const char *str);
+
+int ec_log_register(ec_log_t usr_log, void *opaque);
+void ec_log_unregister(void);
+
+/* same api than printf */
+int ec_log(unsigned int level, const char *format, ...);
+int ec_vlog(unsigned int level, const char *format, va_list ap);
+
+/* default log handler for the library, use printf */
+int ec_log_default(unsigned int level, void *opaque, const char *str);
+
+#endif
#include <stdio.h>
#include <string.h>
+#include <ecoli_log.h>
#include <ecoli_malloc.h>
#include <ecoli_test.h>
#include <ecoli_tk.h>
ret = 0;
if (expected == NULL && ret != 0)
- printf("tk should not match but matches <%s>\n", s);
+ ec_log(EC_LOG_ERR, "tk should not match but matches <%s>\n", s);
if (expected != NULL && ret != 0)
- printf("tk should match <%s> but matches <%s>\n",
+ ec_log(EC_LOG_ERR, "tk should match <%s> but matches <%s>\n",
expected, s);
ec_parsed_tk_free(p);
ret = 0;
if (expected == NULL && ret != 0)
- printf("tk should not complete but completes with <%s>\n", s);
+ ec_log(EC_LOG_ERR,
+ "tk should not complete but completes with <%s>\n", s);
if (expected != NULL && ret != 0)
- printf("tk should complete with <%s> but completes with <%s>\n",
+ ec_log(EC_LOG_ERR,
+ "tk should complete with <%s> but completes with <%s>\n",
expected, s);
ec_completed_tk_free(p);
ret = hdr + 1;
}
- printf("%s:%d: info: malloc(%zd) -> %p\n", file, line, size, ret);
+ ec_log(EC_LOG_INFO, "%s:%d: info: malloc(%zd) -> %p\n",
+ file, line, size, ret);
return ret;
}
(void)file;
(void)line;
- printf("%s:%d: info: free(%p)\n", file, line, ptr);
+ ec_log(EC_LOG_INFO, "%s:%d: info: free(%p)\n", file, line, ptr);
if (ptr == NULL)
return;
hdr = (ptr - sizeof(*hdr));
if (hdr->cookie != 0x12345678) {
- printf("%s:%d: error: free(%p): bad start cookie\n",
+ ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad start cookie\n",
file, line, ptr);
abort();
}
}
if (h == NULL) {
- printf("%s:%d: error: free(%p): bad ptr\n",
+ ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad ptr\n",
file, line, ptr);
abort();
}
if (ptr != NULL) {
if (hdr->cookie != 0x12345678) {
- printf("%s:%d: error: realloc(%p): bad start cookie\n",
+ ec_log(EC_LOG_ERR, "%s:%d: error: realloc(%p): bad start cookie\n",
file, line, ptr);
abort();
}
}
if (h == NULL) {
- printf("%s:%d: error: realloc(%p): bad ptr\n",
+ ec_log(EC_LOG_ERR, "%s:%d: error: realloc(%p): bad ptr\n",
file, line, ptr);
abort();
}
TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, hdr, next);
}
- printf("%s:%d: info: realloc(%p, %zd) -> %p\n",
+ ec_log(EC_LOG_INFO, "%s:%d: info: realloc(%p, %zd) -> %p\n",
file, line, ptr, size, ret);
return ret;
struct debug_alloc_hdr *hdr;
TAILQ_FOREACH(hdr, &debug_alloc_hdr_list, next) {
- printf("%s:%d: error: memory leak size=%zd ptr=%p\n",
+ ec_log(EC_LOG_ERR, "%s:%d: error: memory leak size=%zd ptr=%p\n",
hdr->file, hdr->line, hdr->size, hdr + 1);
}
}
+/* XXX todo */
/* int ec_test_check_tk_complete_list(const struct ec_tk *tk, */
/* const char *input, ...) */
/* register a new malloc to trac memleaks */
if (ec_malloc_register(debug_malloc, debug_free, debug_realloc) < 0) {
- printf("cannot register new malloc\n");
+ ec_log(EC_LOG_ERR, "cannot register new malloc\n");
return -1;
}
TAILQ_FOREACH(test, &test_list, next) {
if (test->test() == 0) {
- printf("== test %-20s success\n", test->name);
+ ec_log(EC_LOG_INFO, "== test %-20s success\n",
+ test->name);
} else {
- printf("== test %-20s failed\n", test->name);
+ ec_log(EC_LOG_INFO, "== test %-20s failed\n",
+ test->name);
ret = -1;
}
}
ec_free(parsed_tk);
}
-static void __ec_parsed_tk_dump(const struct ec_parsed_tk *parsed_tk,
+static void __ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk,
size_t indent)
{
struct ec_parsed_tk *child;
/* XXX enhance */
for (i = 0; i < indent; i++)
- printf(" ");
+ fprintf(out, " ");
s = ec_parsed_tk_to_string(parsed_tk);
- printf("id=%s, s=<%s>\n", parsed_tk->tk->id, s);
+ fprintf(out, "id=%s, s=<%s>\n", parsed_tk->tk->id, s);
TAILQ_FOREACH(child, &parsed_tk->children, next)
- __ec_parsed_tk_dump(child, indent + 2);
+ __ec_parsed_tk_dump(out, child, indent + 2);
}
-void ec_parsed_tk_dump(const struct ec_parsed_tk *parsed_tk)
+void ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk)
{
if (parsed_tk == NULL) {
- printf("no match\n");
+ fprintf(out, "no match\n");
return;
}
- __ec_parsed_tk_dump(parsed_tk, 0);
+ __ec_parsed_tk_dump(out, parsed_tk, 0);
}
void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk,
ec_free(completed_tk);
}
-void ec_completed_tk_dump(const struct ec_completed_tk *completed_tk)
+void ec_completed_tk_dump(FILE *out, const struct ec_completed_tk *completed_tk)
{
struct ec_completed_tk_elt *elt;
if (completed_tk == NULL || completed_tk->count == 0) {
- printf("no completion\n");
+ fprintf(out, "no completion\n");
return;
}
- printf("completion: count=%u smallest_start=<%s>\n",
+ fprintf(out, "completion: count=%u smallest_start=<%s>\n",
completed_tk->count, completed_tk->smallest_start);
TAILQ_FOREACH(elt, &completed_tk->elts, next)
- printf("add=<%s> full=<%s>\n", elt->add, elt->full);
+ fprintf(out, "add=<%s> full=<%s>\n", elt->add, elt->full);
}
const char *ec_completed_tk_smallest_start(
#include <sys/queue.h>
#include <sys/types.h>
+#include <stdio.h>
+
#define EC_TK_ENDLIST ((void *)1)
struct ec_tk;
struct ec_parsed_tk *ec_tk_parse(const struct ec_tk *token, const char *str);
void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk,
struct ec_parsed_tk *child);
-void ec_parsed_tk_dump(const struct ec_parsed_tk *parsed_tk);
+void ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk);
void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk);
struct ec_parsed_tk *ec_parsed_tk_find_first(struct ec_parsed_tk *parsed_tk,
struct ec_completed_tk *completed_tk1,
struct ec_completed_tk *completed_tk2);
void ec_completed_tk_free(struct ec_completed_tk *completed_tk);
-void ec_completed_tk_dump(const struct ec_completed_tk *completed_tk);
+void ec_completed_tk_dump(FILE *out,
+ const struct ec_completed_tk *completed_tk);
const char *ec_completed_tk_smallest_start(
const struct ec_completed_tk *completed_tk);
#include <ctype.h>
#include <errno.h>
+#include <ecoli_log.h>
#include <ecoli_malloc.h>
#include <ecoli_tk.h>
#include <ecoli_tk_int.h>
tk = ec_tk_int_new(NULL, 0, 256, 0);
if (tk == NULL) {
- printf("cannot create tk\n");
+ ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
ret |= EC_TEST_CHECK_TK_PARSE(tk, "0", "0");
tk = ec_tk_int_new(NULL, -1, LLONG_MAX, 16);
if (tk == NULL) {
- printf("cannot create tk\n");
+ ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
ret |= EC_TEST_CHECK_TK_PARSE(tk, "0", "0");
tk = ec_tk_int_new(NULL, LLONG_MIN, 0, 10);
if (tk == NULL) {
- printf("cannot create tk\n");
+ ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
ret |= EC_TEST_CHECK_TK_PARSE(tk, "0", "0");
/* /\* test completion *\/ */
/* tk = ec_tk_int_new(NULL, "foo"); */
/* if (tk == NULL) { */
- /* printf("cannot create tk\n"); */
+ /* ec_log(EC_LOG_ERR, "cannot create tk\n"); */
/* return -1; */
/* } */
/* ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", "foo"); */
#include <stdarg.h>
#include <ecoli_malloc.h>
+#include <ecoli_log.h>
#include <ecoli_tk.h>
#include <ecoli_tk_or.h>
#include <ecoli_tk_str.h>
ec_tk_str_new(NULL, "bar"),
EC_TK_ENDLIST);
if (tk == NULL) {
- printf("cannot create tk\n");
+ ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo", "foo");
ec_tk_str_new(NULL, "titi"),
EC_TK_ENDLIST);
if (tk == NULL) {
- printf("cannot create tk\n");
+ ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", "");
#include <stdlib.h>
#include <string.h>
+#include <ecoli_log.h>
#include <ecoli_malloc.h>
#include <ecoli_test.h>
#include <ecoli_tk.h>
/* all inputs starting with foo should match */
tk = ec_tk_str_new(NULL, "foo");
if (tk == NULL) {
- printf("cannot create tk\n");
+ ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo", "foo");
/* all inputs starting with foo should match */
tk = ec_tk_str_new(NULL, "Здравствуйте");
if (tk == NULL) {
- printf("cannot create tk\n");
+ ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
ret |= EC_TEST_CHECK_TK_PARSE(tk, "Здравствуйте", "Здравствуйте");
/* an empty token string always matches */
tk = ec_tk_str_new(NULL, "");
if (tk == NULL) {
- printf("cannot create tk\n");
+ ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
ret |= EC_TEST_CHECK_TK_PARSE(tk, "", "");
/* test completion */
tk = ec_tk_str_new(NULL, "foo");
if (tk == NULL) {
- printf("cannot create tk\n");
+ ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", "foo");
/* ok */
p = ec_tk_parse(seq, "hello mike");
- ec_parsed_tk_dump(p);
+ ec_parsed_tk_dump(stdout, p);
name = ec_parsed_tk_to_string(ec_parsed_tk_find_first(p, "name"));
printf("parsed with name=%s\n", name);
ec_parsed_tk_free(p);
/* ko */
p = ec_tk_parse(seq, "hello robert");
- ec_parsed_tk_dump(p);
+ ec_parsed_tk_dump(stdout, p);
name = ec_parsed_tk_to_string(ec_parsed_tk_find_first(p, "name"));
printf("parsed with name=%s\n", name);
ec_parsed_tk_free(p);