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