1 /*
2  * Copyright (c) 2014-2017, Siemens AG. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice,
8  * this list of conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <stdio.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <assert.h>
31 
32 #include <embb/base/c/log.h>
33 
34 #include <embb/base/c/internal/config.h>
35 #include <embb/base/c/internal/unused.h>
36 
embb_log_write_file(void * context,char const * message)37 void embb_log_write_file(
38   void * context,
39   char const * message) {
40   assert(context != NULL);
41   FILE * ff = (FILE*)context;
42   fprintf(ff, "%s", message);
43   fflush(ff);
44 }
45 
46 static embb_log_level_t embb_log_global_log_level =
47   EMBB_LOG_LEVEL_NONE;
48 
49 static void * embb_log_global_log_context = NULL;
50 
51 static embb_log_function_t embb_log_global_log_function = embb_log_write_file;
52 
embb_log_set_log_level(embb_log_level_t log_level)53 void embb_log_set_log_level(
54   embb_log_level_t log_level) {
55   embb_log_global_log_level = log_level;
56 }
57 
embb_log_set_log_function(void * context,embb_log_function_t func)58 void embb_log_set_log_function(
59   void * context,
60   embb_log_function_t func) {
61   embb_log_global_log_context = context;
62   embb_log_global_log_function = func;
63 }
64 
embb_log_write_internal(char const * channel,embb_log_level_t log_level,char const * message,va_list argp)65 void embb_log_write_internal(
66   char const * channel,
67   embb_log_level_t log_level,
68   char const * message,
69   va_list argp) {
70   if (log_level <= embb_log_global_log_level) {
71     char * log_level_str = "     ";
72     char const * channel_str = channel;
73     void * log_context = embb_log_global_log_context;
74     if (NULL == channel_str) {
75       channel_str = " global ";
76     }
77     if (NULL == log_context) {
78       log_context = (void*)stdout;
79     }
80     switch (log_level) {
81     case EMBB_LOG_LEVEL_ERROR:
82       log_level_str = "ERROR";
83       break;
84     case EMBB_LOG_LEVEL_WARNING:
85       log_level_str = "WARN ";
86       break;
87     case EMBB_LOG_LEVEL_INFO:
88       log_level_str = "INFO ";
89       break;
90     case EMBB_LOG_LEVEL_TRACE:
91       log_level_str = "TRACE";
92       break;
93 
94     case EMBB_LOG_LEVEL_NONE:
95     default:
96       break;
97     }
98 #if defined(EMBB_PLATFORM_COMPILER_MSVC)
99     char msg_buffer[400];
100     char buffer[500];
101     vsprintf_s(msg_buffer, sizeof(msg_buffer), message, argp);
102     sprintf_s(buffer, sizeof(buffer), "[%s] - [%s] %s",
103       channel_str, log_level_str, msg_buffer);
104     embb_log_global_log_function(log_context, buffer);
105 #elif defined(EMBB_PLATFORM_COMPILER_GNUC)
106     char msg_buffer[400];
107     char buffer[500];
108     vsnprintf(msg_buffer, sizeof(msg_buffer), message, argp);
109     snprintf(buffer, sizeof(buffer), "[%s] - [%s] %s",
110       channel_str, log_level_str, msg_buffer);
111     embb_log_global_log_function(log_context, buffer);
112 #else
113     embb_log_global_log_function(log_context, "[");
114     embb_log_global_log_function(log_context, channel_str);
115     embb_log_global_log_function(log_context, "] - [");
116     embb_log_global_log_function(log_context, log_level_str);
117     embb_log_global_log_function(log_context, "] ");
118     /* no secure formatting possible, sorry */
119     embb_log_global_log_function(log_context, message);
120 #endif
121   }
122 }
123 
embb_log_write(char const * channel,embb_log_level_t log_level,char const * message,...)124 void embb_log_write(
125   char const * channel,
126   embb_log_level_t log_level,
127   char const * message,
128   ...) {
129   va_list argp;
130   va_start(argp, message);
131   embb_log_write_internal(channel, log_level, message, argp);
132   va_end(argp);
133 }
134 
135 #ifdef EMBB_DEBUG
embb_log_trace(char const * channel,char const * message,...)136 void embb_log_trace(
137   char const * channel,
138   char const * message,
139   ...) {
140   va_list argp;
141   va_start(argp, message);
142   embb_log_write_internal(channel, EMBB_LOG_LEVEL_TRACE, message, argp);
143   va_end(argp);
144 }
145 
embb_log_info(char const * channel,char const * message,...)146 void embb_log_info(
147   char const * channel,
148   char const * message,
149   ...) {
150   va_list argp;
151   va_start(argp, message);
152   embb_log_write_internal(channel, EMBB_LOG_LEVEL_INFO, message, argp);
153   va_end(argp);
154 }
155 #else
156 #undef embb_log_trace
embb_log_trace(char const * channel,char const * message,...)157 void embb_log_trace(
158   char const * channel,
159   char const * message,
160   ...) {
161   EMBB_UNUSED(channel);
162   EMBB_UNUSED(message);
163 }
164 
165 #undef embb_log_info
embb_log_info(char const * channel,char const * message,...)166 void embb_log_info(
167   char const * channel,
168   char const * message,
169   ...) {
170   EMBB_UNUSED(channel);
171   EMBB_UNUSED(message);
172 }
173 #endif
174 
embb_log_warning(char const * channel,char const * message,...)175 void embb_log_warning(
176   char const * channel,
177   char const * message,
178   ...) {
179   va_list argp;
180   va_start(argp, message);
181   embb_log_write_internal(channel, EMBB_LOG_LEVEL_WARNING, message, argp);
182   va_end(argp);
183 }
184 
embb_log_error(char const * channel,char const * message,...)185 void embb_log_error(
186   char const * channel,
187   char const * message,
188   ...) {
189   va_list argp;
190   va_start(argp, message);
191   embb_log_write_internal(channel, EMBB_LOG_LEVEL_ERROR, message, argp);
192   va_end(argp);
193 }
194