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