1 /*
2 * Copyright 2018 Oticon A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <string.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11 #include <stdint.h>
12 #include <unistd.h>
13
14 #include "bs_tracing.h"
15 #include "bs_types.h"
16 #include "bs_utils.h"
17 #include "bs_oswrap.h"
18 #include "bs_symbols.h"
19
20 static int is_a_tty[2] = {-1,-1}; //-1 = we do not know yet ; Indexed 0:stdout, 1:stderr
21
22 static int trace_level = 0;
23 static main_cleanup_f main_cleanup_fpr = NULL; //Function from the application which will be called on exit or error
24 static time_f time_fpr = NULL; //Function from the application to get the current time
25
26 #define MAX_PREFIX_LEN 40
27 static char prefix_s[MAX_PREFIX_LEN]="?_??:"; //In case somebody throws messages before initializing the prefix we initialize it to this (will happen if verbosity is high, during command line parsing)
28 static char prefix_s_color[MAX_PREFIX_LEN]="?_??:"; //like prefix_s, but with colors
29
bs_trace_disable_color(char * argv,int offset)30 void bs_trace_disable_color(char * argv, int offset){
31 is_a_tty[0] = 0;
32 is_a_tty[1] = 0;
33 }
34
bs_trace_enable_color(char * argv,int offset)35 void bs_trace_enable_color(char * argv, int offset){
36 //In the next print it will be checked again if this is a tty or not
37 is_a_tty[0] = -1;
38 is_a_tty[1] = -1;
39 }
40
bs_trace_force_color(char * argv,int offset)41 void bs_trace_force_color(char * argv, int offset){
42 is_a_tty[0] = 1;
43 is_a_tty[1] = 1;
44 }
45
bs_trace_is_tty(int file_index)46 int bs_trace_is_tty(int file_index){
47 if (is_a_tty[file_index] == -1) {
48 FILE* fptrs[2] = {stdout, stderr};
49 is_a_tty[file_index] = isatty(fileno(fptrs[file_index]));
50 }
51 return is_a_tty[file_index];
52 }
53
bs_trace_set_level(int new_trace_level)54 void bs_trace_set_level(int new_trace_level) {
55 trace_level = BS_MAX(new_trace_level,0);
56 }
57
bs_trace_will_it_be_traced(int this_message_level)58 int bs_trace_will_it_be_traced(int this_message_level) {
59 return ( this_message_level <= trace_level );
60 }
61
bs_trace_register_cleanup_function(main_cleanup_f cleanup_f)62 void bs_trace_register_cleanup_function(main_cleanup_f cleanup_f) {
63 main_cleanup_fpr = cleanup_f;
64 }
65
bs_trace_register_time_function(time_f t_function)66 void bs_trace_register_time_function(time_f t_function) {
67 time_fpr = t_function;
68 }
69
bs_trace_set_prefix(const char * prefix)70 void bs_trace_set_prefix(const char* prefix) {
71 strncpy(prefix_s, prefix, MAX_PREFIX_LEN-1);
72 int size = BS_MIN(strlen(prefix), MAX_PREFIX_LEN-1);
73 prefix_s[size] = 0;
74
75 strncpy(prefix_s_color, prefix, MAX_PREFIX_LEN-1);
76 size = BS_MIN(strlen(prefix), MAX_PREFIX_LEN-1);
77 prefix_s_color[size] = 0;
78 }
79
bs_trace_set_color_prefix(const char * prefix)80 void bs_trace_set_color_prefix(const char* prefix) {
81 strncpy(prefix_s_color, prefix, MAX_PREFIX_LEN-1);
82 int size = BS_MIN(strlen(prefix), MAX_PREFIX_LEN-1);
83 prefix_s_color[size] = 0;
84 }
85
bs_trace_set_prefix_phy(const char * phy_id)86 void bs_trace_set_prefix_phy(const char *phy_id) {
87 char trace_prefix[strlen(phy_id) + 5];
88 sprintf(trace_prefix, "p_%s:", phy_id);
89 bs_trace_set_prefix(trace_prefix);
90 }
91
bs_trace_set_prefix_dev(int dev_nbr)92 void bs_trace_set_prefix_dev(int dev_nbr) {
93 static const char * const device_colortable[8] = {
94 "\x1b[0;97;41m",
95 "\x1b[0;97;42m",
96 "\x1b[0;97;43m",
97 "\x1b[0;97;44m",
98 "\x1b[0;97;45m",
99 "\x1b[0;97;46m",
100 "\x1b[0;97;47m",
101 "\x1b[0;97;40m"
102 };
103
104 char prefix[40]; //32 bit uint can have max 10 digits
105 snprintf(prefix, 14 , "d_%02i:", dev_nbr);
106 bs_trace_set_prefix(prefix);
107
108 snprintf(prefix, 40, "%sd_%02i:\x1b[0;39m", device_colortable[dev_nbr & 0x7], dev_nbr);
109 bs_trace_set_color_prefix(prefix);
110 }
111
get_time()112 static bs_time_t get_time(){
113 if( time_fpr != NULL ){
114 return time_fpr();
115 } else {
116 return TIME_NEVER;
117 }
118 }
119
bs_trace_silent_exit(uint8_t code)120 void bs_trace_silent_exit(uint8_t code){
121 #if (_CS_TSYMBOLS_TRACE )
122 cs_clear_Tsymbols();
123 #endif
124 uint8_t main_code = 0;
125 if ( main_cleanup_fpr != NULL ){
126 main_code = main_cleanup_fpr();
127 }
128 exit(BS_MAX(code, main_code));
129 }
130
131 static const char *base_trace_type_prefixes[] = {
132 "EXIT:", "ERROR:", "WARNING:", "INFO:", "DEBUG:", ""
133 };
134
135 static const char *trace_type_esc_start[] = {
136 "\x1b[0;39m", //EXIT //reset all styles
137 "\x1b[1;31m", //ERROR //Foreground color = red, bold
138 "\x1b[95m", //WARNING //Foreground color = magenta
139 "\x1b[0;39m", //INFO //reset all styles
140 "\x1b[0;39m", //DEBUG //reset all styles
141 "\x1b[0;39m" //RAW //reset all styles
142 };
143
144 static const char trace_esc_end[] = "\x1b[0;39m"; //reset all styles
145
bs_trace_vprint(base_trace_type_t type,const char * caller_filename,unsigned int caller_line,int this_message_trace_level,base_trace_timed_type_t time_type,bs_time_t time,const char * format,va_list variable_args)146 void bs_trace_vprint(base_trace_type_t type,
147 const char *caller_filename, unsigned int caller_line,
148 int this_message_trace_level,
149 base_trace_timed_type_t time_type, bs_time_t time,
150 const char *format, va_list variable_args){
151
152 uint file_index = 0; //by default thru stdout
153 if (( type == BS_TRACE_ERROR ) || ( type == BS_TRACE_WARNING )) {
154 this_message_trace_level = 0; //we promote the message, so it is always printed
155 file_index = 1; //errors and warnings thru stderr
156 }
157 if ( this_message_trace_level <= trace_level ) {
158 FILE* fptrs[2] = {stdout, stderr};
159
160 char time_s[20] = {0};
161 if ( time_type > BS_TRACE_NOTIME ) {
162 time_s[0] = ' ';
163 time_s[1] = '@';
164 if ( time_type == BS_TRACE_AUTOTIME ){
165 time = get_time();
166 }
167 bs_time_to_str(&time_s[2], time);
168 }
169
170 if ( is_a_tty[file_index] == -1 ){
171 is_a_tty[file_index] = isatty(fileno(fptrs[file_index]));
172 }
173 if ( is_a_tty[file_index] ){
174 fprintf(fptrs[file_index],"%s%s",prefix_s_color, trace_type_esc_start[type]);
175 } else {
176 fprintf(fptrs[file_index],"%s",prefix_s);
177 }
178 fprintf(fptrs[file_index], "%s %s ", time_s, base_trace_type_prefixes[type]);
179 if ( caller_filename != NULL ) {
180 fprintf(fptrs[file_index], "(%s:%u): ", caller_filename, caller_line);
181 }
182 vfprintf(fptrs[file_index], format, variable_args);
183
184 if ( is_a_tty[file_index] ) {
185 fprintf(fptrs[file_index],"%s", trace_esc_end);
186 }
187 }
188
189 if ( type == BS_TRACE_EXIT ) {
190 bs_trace_silent_exit(0);
191 } else if ( type == BS_TRACE_ERROR ) {
192 bs_trace_silent_exit(255);
193 }
194 }
195
bs_trace_print(base_trace_type_t type,const char * caller_filename,unsigned int caller_line,int this_message_trace_level,base_trace_timed_type_t time_type,bs_time_t time,const char * format,...)196 void bs_trace_print(base_trace_type_t type,
197 const char *caller_filename, unsigned int caller_line,
198 int this_message_trace_level,
199 base_trace_timed_type_t time_type, bs_time_t time,
200 const char *format, ...){
201 if ((type == BS_TRACE_ERROR) || (type == BS_TRACE_WARNING)) {
202 this_message_trace_level = 0; //we promote the message, so it is always printed
203 }
204 if ((this_message_trace_level <= trace_level) || (type == BS_TRACE_EXIT)) {
205 va_list variable_args;
206 va_start(variable_args, format);
207 bs_trace_vprint(type,
208 caller_filename, caller_line,
209 this_message_trace_level,
210 time_type, time,
211 format, variable_args);
212 va_end(variable_args);
213 }
214 }
215