updates.
[silc.git] / lib / silcutil / silclog.c
1 /*
2
3   silclog.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23
24 /* Set TRUE/FALSE to enable/disable debugging */
25 bool silc_debug = FALSE;
26 bool silc_debug_hexdump = FALSE;
27 char *silc_debug_string = NULL;
28 bool log_file_open_error = FALSE;
29
30 /* SILC Log name strings. These strings are printed to the log file. */
31 const SilcLogTypeName silc_log_types[] =
32 {
33   { "Info", SILC_LOG_INFO },
34   { "Warning", SILC_LOG_WARNING },
35   { "Error", SILC_LOG_ERROR },
36   { "Fatal", SILC_LOG_FATAL },
37
38   { NULL, -1 },
39 };
40
41 char *log_info_file;
42 char *log_warning_file;
43 char *log_error_file;
44 char *log_fatal_file;
45 uint32 log_info_size;
46 uint32 log_warning_size;
47 uint32 log_error_size;
48 uint32 log_fatal_size;
49
50 /* Log callbacks. If these are set by the application these are used
51    instead of the default functions in this file. */
52 static SilcLogCb info_cb = NULL;
53 static SilcLogCb warning_cb = NULL;
54 static SilcLogCb error_cb = NULL;
55 static SilcLogCb fatal_cb = NULL;
56
57 /* Debug callbacks. If set these are used instead of default ones. */
58 static SilcDebugCb debug_cb = NULL;
59 static SilcDebugHexdumpCb debug_hexdump_cb = NULL;
60
61 /* Outputs the log message to what ever log file selected. */
62
63 void silc_log_output(const char *filename, uint32 maxsize,
64                      SilcLogType type, char *string)
65 {
66   FILE *fp;
67   const SilcLogTypeName *np;
68
69   switch(type)
70     {
71     case SILC_LOG_INFO:
72       if (info_cb) {
73         (*info_cb)(string);
74         silc_free(string);
75         return;
76       }
77       break;
78     case SILC_LOG_WARNING:
79       if (warning_cb) {
80         (*warning_cb)(string);
81         silc_free(string);
82         return;
83       }
84       break;
85     case SILC_LOG_ERROR:
86       if (error_cb) {
87         (*error_cb)(string);
88         silc_free(string);
89         return;
90       }
91       break;
92     case SILC_LOG_FATAL:
93       if (fatal_cb) {
94         (*fatal_cb)(string);
95         silc_free(string);
96         return;
97       }
98       break;
99     }
100
101   if (!filename)
102     fp = stderr;
103   else {
104     /* Purge the log file if the max size is defined. */
105     if (maxsize) {
106       fp = fopen(filename, "r");
107       if (fp) {
108         int filelen;
109         
110         filelen = fseek(fp, (off_t)0L, SEEK_END);
111         fseek(fp, (off_t)0L, SEEK_SET);  
112         
113         /* Purge? */
114         if (filelen >= maxsize)
115           unlink(filename);
116         
117         fclose(fp);
118       }
119     }
120     
121     /* Open the log file */
122     if ((fp = fopen(filename, "a+")) == NULL) {
123       if (!log_file_open_error) {
124         fprintf(stderr, "warning: could not open log file "
125                 "%s: %s\n", filename, strerror(errno));
126         fprintf(stderr, "warning: log messages will be displayed on "
127                 "the screen\n");
128       }
129       log_file_open_error = TRUE;
130       fp = stderr;
131     }
132   }
133
134   /* Get the log type name */
135   for (np = silc_log_types; np->name; np++) {
136     if (np->type == type)
137       break;
138   }
139
140   fprintf(fp, "[%s] [%s] %s\n", silc_get_time(), np->name, string);
141   fflush(fp);
142   if (fp != stderr)
143     fclose(fp);
144   silc_free(string);
145 }
146
147 /* Outputs the debug message to stderr. */
148
149 void silc_log_output_debug(char *file, char *function, 
150                            int line, char *string)
151 {
152   if (!silc_debug) {
153     silc_free(string);
154     return;
155   }
156
157   if (silc_debug_string && 
158       (!silc_string_regex_match(silc_debug_string, file) &&
159        !silc_string_regex_match(silc_debug_string, function))) {
160     silc_free(string);
161     return;
162   }
163
164   if (debug_cb) {
165     (*debug_cb)(file, function, line, string);
166     silc_free(string);
167     return;
168   }
169
170   fprintf(stderr, "%s:%d: %s\n", function, line, string);
171   fflush(stderr);
172   silc_free(string);
173 }
174
175 /* Hexdumps a message */
176
177 void silc_log_output_hexdump(char *file, char *function, 
178                              int line, void *data_in,
179                              uint32 len, char *string)
180 {
181   int i, k;
182   int off, pos, count;
183   unsigned char *data = (unsigned char *)data_in;
184
185   if (!silc_debug_hexdump) {
186     silc_free(string);
187     return;
188   }
189
190   if (silc_debug_string && 
191       (!silc_string_regex_match(silc_debug_string, file) &&
192        !silc_string_regex_match(silc_debug_string, function))) {
193     silc_free(string);
194     return;
195   }
196
197   if (debug_hexdump_cb) {
198     (*debug_hexdump_cb)(file, function, line, data_in, len, string);
199     silc_free(string);
200     return;
201   }
202
203   fprintf(stderr, "%s:%d: %s\n", function, line, string);
204   silc_free(string);
205
206   k = 0;
207   off = len % 16;
208   pos = 0;
209   count = 16;
210   while (1) {
211
212     if (off) {
213       if ((len - pos) < 16 && (len - pos <= len - off))
214         count = off;
215     } else {
216       if (pos == len)
217         count = 0;
218     }
219     if (off == len)
220       count = len;
221
222     if (count)
223       fprintf(stderr, "%08X  ", k++ * 16);
224
225     for (i = 0; i < count; i++) {
226       fprintf(stderr, "%02X ", data[pos + i]);
227       
228       if ((i + 1) % 4 == 0)
229         fprintf(stderr, " ");
230     }
231
232     if (count && count < 16) {
233       int j;
234       
235       for (j = 0; j < 16 - count; j++) {
236         fprintf(stderr, "   ");
237
238         if ((j + count + 1) % 4 == 0)
239           fprintf(stderr, " ");
240       }
241     }
242   
243     for (i = 0; i < count; i++) {
244       char ch;
245       
246       if (data[pos] < 32 || data[pos] >= 127)
247         ch = '.';
248       else
249         ch = data[pos];
250
251       fprintf(stderr, "%c", ch);
252       pos++;
253     }
254
255     if (count)
256       fprintf(stderr, "\n");
257
258     if (count < 16)
259       break;
260   }
261 }
262
263 /* Sets log files */
264
265 void silc_log_set_files(char *info, uint32 info_size, 
266                         char *warning, uint32 warning_size,
267                         char *error, uint32 error_size,
268                         char *fatal, uint32 fatal_size)
269 {
270   log_info_file = info;
271   log_warning_file = warning;
272   log_error_file = error;
273   log_fatal_file = fatal;
274
275   log_info_size = info_size;
276   log_warning_size = warning_size;
277   log_error_size = error_size;
278   log_fatal_size = fatal_size;
279 }
280
281 /* Sets log callbacks */
282
283 void silc_log_set_callbacks(SilcLogCb info, SilcLogCb warning,
284                             SilcLogCb error, SilcLogCb fatal)
285 {
286   info_cb = info;
287   warning_cb = warning;
288   error_cb = error;
289   fatal_cb = fatal;
290 }
291
292 /* Resets log callbacks */
293
294 void silc_log_reset_callbacks()
295 {
296   info_cb = warning_cb = error_cb = fatal_cb = NULL;
297 }
298
299 /* Sets debug callbacks */
300
301 void silc_log_set_debug_callbacks(SilcDebugCb debug, 
302                                   SilcDebugHexdumpCb debug_hexdump)
303 {
304   debug_cb = debug;
305   debug_hexdump_cb = debug_hexdump;
306 }
307
308 /* Resets debug callbacks */
309
310 void silc_log_reset_debug_callbacks()
311 {
312   debug_cb = NULL;
313   debug_hexdump_cb = NULL;
314 }
315
316 /* Set current debug string */
317
318 void silc_log_set_debug_string(const char *debug_string)
319 {
320   silc_free(silc_debug_string);
321   if ((strchr(debug_string, '(') &&
322        strchr(debug_string, ')')) ||
323       strchr(debug_string, '$'))
324     silc_debug_string = strdup(debug_string);
325   else
326     silc_debug_string = silc_string_regexify(debug_string);
327 }