spdx tags for c and h files
[protos/libecoli.git] / lib / ecoli_log.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
3  */
4
5 #define _GNU_SOURCE /* for vasprintf */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <errno.h>
10
11 #include <ecoli_malloc.h>
12 #include <ecoli_string.h>
13 #include <ecoli_log.h>
14
15 static ec_log_t ec_log_fct = ec_log_default_cb;
16 static void *ec_log_opaque;
17
18 struct ec_log_type {
19         char *name;
20         enum ec_log_level level;
21 };
22
23 static struct ec_log_type *log_types;
24 static size_t log_types_len;
25 static enum ec_log_level global_level = EC_LOG_WARNING;
26
27 int ec_log_level_set(enum ec_log_level level)
28 {
29         if (level < 0 || level > EC_LOG_DEBUG)
30                 return -1;
31         global_level = level;
32
33         return 0;
34 }
35
36 enum ec_log_level ec_log_level_get(void)
37 {
38         return global_level;
39 }
40
41 int ec_log_default_cb(int type, enum ec_log_level level, void *opaque,
42                 const char *str)
43 {
44         (void)opaque;
45
46         if (level > ec_log_level_get())
47                 return 0;
48
49         if (fprintf(stderr, "[%d] %-12s %s", level, ec_log_name(type), str) < 0)
50                 return -1;
51
52         return 0;
53 }
54
55 int ec_log_fct_register(ec_log_t usr_log, void *opaque)
56 {
57         errno = 0;
58
59         if (usr_log == NULL) {
60                 ec_log_fct = ec_log_default_cb;
61                 ec_log_opaque = NULL;
62         } else {
63                 ec_log_fct = usr_log;
64                 ec_log_opaque = opaque;
65         }
66
67         return 0;
68 }
69
70 static int
71 ec_log_lookup(const char *name)
72 {
73         size_t i;
74
75         for (i = 0; i < log_types_len; i++) {
76                 if (log_types[i].name == NULL)
77                         continue;
78                 if (strcmp(name, log_types[i].name) == 0)
79                         return i;
80         }
81
82         return -1;
83 }
84
85 int
86 ec_log_type_register(const char *name)
87 {
88         struct ec_log_type *new_types;
89         char *copy;
90         int id;
91
92         id = ec_log_lookup(name);
93         if (id >= 0)
94                 return id;
95
96         new_types = ec_realloc(log_types,
97                 sizeof(*new_types) * (log_types_len + 1));
98         if (new_types == NULL)
99                 return -1; /* errno is set */
100         log_types = new_types;
101
102         copy = ec_strdup(name);
103         if (copy == NULL)
104                 return -1; /* errno is set */
105
106         id = log_types_len++;
107         log_types[id].name = copy;
108         log_types[id].level = EC_LOG_DEBUG;
109
110         return id;
111 }
112
113 const char *
114 ec_log_name(int type)
115 {
116         if (type < 0 || (unsigned int)type >= log_types_len)
117                 return "unknown";
118         return log_types[type].name;
119 }
120
121 int ec_vlog(int type, enum ec_log_level level, const char *format, va_list ap)
122 {
123         char *s;
124         int ret;
125
126         /* don't use ec_vasprintf here, because it will call
127          * ec_malloc(), then ec_log(), ec_vasprintf()...
128          * -> stack overflow */
129         ret = vasprintf(&s, format, ap);
130         if (ret < 0)
131                 return ret;
132
133         ret = ec_log_fct(type, level, ec_log_opaque, s);
134         free(s);
135
136         return ret;
137 }
138
139 int ec_log(int type, enum ec_log_level level, const char *format, ...)
140 {
141         va_list ap;
142         int ret;
143
144         va_start(ap, format);
145         ret = ec_vlog(type, level, format, ap);
146         va_end(ap);
147
148         return ret;
149 }