log framework
authorOlivier Matz <zer0@droids-corp.org>
Fri, 28 Oct 2016 14:51:27 +0000 (16:51 +0200)
committerOlivier Matz <zer0@droids-corp.org>
Fri, 28 Oct 2016 14:51:27 +0000 (16:51 +0200)
lib/Makefile
lib/build/test
lib/ecoli_log.c [new file with mode: 0644]
lib/ecoli_log.h [new file with mode: 0644]
lib/ecoli_test.c
lib/ecoli_tk.c
lib/ecoli_tk.h
lib/ecoli_tk_int.c
lib/ecoli_tk_or.c
lib/ecoli_tk_str.c
lib/main.c

index 9aeeae2..08a1b40 100644 (file)
@@ -36,7 +36,7 @@ CFLAGS += -I.
 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
index 34b89ac..2913edb 100755 (executable)
Binary files a/lib/build/test and b/lib/build/test differ
diff --git a/lib/ecoli_log.c b/lib/ecoli_log.c
new file mode 100644 (file)
index 0000000..53c3acb
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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;
+}
diff --git a/lib/ecoli_log.h b/lib/ecoli_log.h
new file mode 100644 (file)
index 0000000..f46f6f2
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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
index e3942c6..3f1c4fd 100644 (file)
@@ -29,6 +29,7 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <ecoli_log.h>
 #include <ecoli_malloc.h>
 #include <ecoli_test.h>
 #include <ecoli_tk.h>
@@ -57,9 +58,9 @@ int ec_test_check_tk_parse(const struct ec_tk *tk, const char *input,
                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);
@@ -83,9 +84,11 @@ int ec_test_check_tk_complete(const struct ec_tk *tk, const char *input,
                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);
@@ -123,7 +126,8 @@ static void *debug_malloc(size_t size, const char *file, unsigned int line)
                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;
 }
@@ -135,14 +139,14 @@ static void debug_free(void *ptr, const char *file, unsigned int line)
        (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();
        }
@@ -153,7 +157,7 @@ static void debug_free(void *ptr, const char *file, unsigned int line)
        }
 
        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();
        }
@@ -171,7 +175,7 @@ void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line)
 
        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();
                }
@@ -182,7 +186,7 @@ void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line)
                }
 
                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();
                }
@@ -211,7 +215,7 @@ void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line)
                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;
@@ -222,11 +226,12 @@ void debug_alloc_dump(void)
        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, ...) */
 
@@ -239,15 +244,17 @@ int ec_test_all(void)
 
        /* 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;
                }
        }
index 6683af7..e814b68 100644 (file)
@@ -113,7 +113,7 @@ void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk)
        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;
@@ -122,22 +122,22 @@ static void __ec_parsed_tk_dump(const struct ec_parsed_tk *parsed_tk,
 
        /* 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,
@@ -293,20 +293,20 @@ void ec_completed_tk_free(struct ec_completed_tk *completed_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(
index 167a528..490c5e1 100644 (file)
@@ -31,6 +31,8 @@
 #include <sys/queue.h>
 #include <sys/types.h>
 
+#include <stdio.h>
+
 #define EC_TK_ENDLIST ((void *)1)
 
 struct ec_tk;
@@ -71,7 +73,7 @@ struct ec_parsed_tk *ec_parsed_tk_new(const struct ec_tk *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,
@@ -112,7 +114,8 @@ struct ec_completed_tk *ec_completed_tk_merge(
        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);
index 41ed54a..6296b8b 100644 (file)
@@ -32,6 +32,7 @@
 #include <ctype.h>
 #include <errno.h>
 
+#include <ecoli_log.h>
 #include <ecoli_malloc.h>
 #include <ecoli_tk.h>
 #include <ecoli_tk_int.h>
@@ -123,7 +124,7 @@ static int testcase(void)
 
        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");
@@ -156,7 +157,7 @@ static int testcase(void)
 
        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");
@@ -180,7 +181,7 @@ static int testcase(void)
 
        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");
@@ -194,7 +195,7 @@ static int testcase(void)
        /* /\* 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"); */
index 9276c70..b498dcb 100644 (file)
@@ -32,6 +32,7 @@
 #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>
@@ -179,7 +180,7 @@ static int testcase(void)
                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");
@@ -197,7 +198,7 @@ static int testcase(void)
                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, "", "");
index 41f99db..f7b18fb 100644 (file)
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <ecoli_log.h>
 #include <ecoli_malloc.h>
 #include <ecoli_test.h>
 #include <ecoli_tk.h>
@@ -129,7 +130,7 @@ static int testcase(void)
        /* 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");
@@ -142,7 +143,7 @@ static int testcase(void)
        /* 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, "Здравствуйте", "Здравствуйте");
@@ -154,7 +155,7 @@ static int testcase(void)
        /* 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, "", "");
@@ -164,7 +165,7 @@ static int testcase(void)
        /* 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");
index 059515b..601508a 100644 (file)
@@ -56,14 +56,14 @@ static void test(void)
 
        /* 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);