Cosmetic documentation update.
[privoxy.git] / errlog.c
1 const char errlog_rcs[] = "$Id: errlog.c,v 1.1.1.1 2001/05/15 13:58:51 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/errlog.c,v $
5  *
6  * Purpose     :  Log errors to a designated destination in an elegant,
7  *                printf-like fashion.
8  *
9  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
10  *                IJBSWA team.  http://ijbswa.sourceforge.net
11  *
12  *                Based on the Internet Junkbuster originally written
13  *                by and Copyright (C) 1997 Anonymous Coders and 
14  *                Junkbusters Corporation.  http://www.junkbusters.com
15  *
16  *                This program is free software; you can redistribute it 
17  *                and/or modify it under the terms of the GNU General
18  *                Public License as published by the Free Software
19  *                Foundation; either version 2 of the License, or (at
20  *                your option) any later version.
21  *
22  *                This program is distributed in the hope that it will
23  *                be useful, but WITHOUT ANY WARRANTY; without even the
24  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
25  *                PARTICULAR PURPOSE.  See the GNU General Public
26  *                License for more details.
27  *
28  *                The GNU General Public License should be included with
29  *                this file.  If not, you can view it at
30  *                http://www.gnu.org/copyleft/gpl.html
31  *                or write to the Free Software Foundation, Inc., 59
32  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33  *
34  * Revisions   :
35  *    $Log: errlog.c,v $
36  *    Revision 1.1.1.1  2001/05/15 13:58:51  oes
37  *    Initial import of version 2.9.3 source tree
38  *
39  *
40  *********************************************************************/
41 \f
42
43 #include "config.h"
44
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <stdarg.h>
48 #include <string.h>
49
50 #ifndef _WIN32
51 #include <unistd.h>
52 #endif /* ndef _WIN32 */
53
54 #include <errno.h>
55 /* #include <pthread.h> */
56
57 #ifdef _WIN32
58 #include <windows.h>
59 #include "w32log.h"
60 #endif /* def _WIN32 */
61
62 #include "errlog.h"
63 #include "project.h"
64
65 const char errlog_h_rcs[] = ERRLOG_H_VERSION;
66
67 /* LOG_LEVEL_ERROR and LOG_LEVEL_INFO cannot be turned off. FIXME: Why?*/
68 #define LOG_LEVEL_MINIMUM  (LOG_LEVEL_ERROR | LOG_LEVEL_INFO)
69
70 /* where to log (default: stderr) */
71 static FILE *logfp = NULL;
72
73 /* where to log (NULL == stderr) */
74 static char * logfilename = NULL;
75
76 /* logging detail level.  */
77 static int debug = LOG_LEVEL_MINIMUM;  
78
79
80 /*********************************************************************
81  *
82  * Function    :  init_errlog
83  *
84  * Description :  Initializes the logging module.  Must call before
85  *                calling log_error.
86  *
87  * Parameters  :
88  *          1  :  prog_name  = The program name.
89  *          2  :  logfname   = The logfile name, or NULL for stderr.
90  *          3  :  debuglevel = The debugging level.
91  *
92  * Returns     :  N/A
93  *
94  *********************************************************************/
95 void init_error_log(const char *prog_name, const char *logfname, int debuglevel)
96 {
97    FILE *fp;
98
99    /* FIXME RACE HAZARD: should start critical section error_log_use here */
100
101    /* set the logging detail level */
102    debug = debuglevel | LOG_LEVEL_MINIMUM;
103
104    if ((logfp != NULL) && (logfp != stderr))
105    {
106       fclose(logfp);
107    }
108    logfp = stderr;
109
110    /* set the designated log file */
111    if( logfname )
112    {
113       if( !(fp = fopen(logfname, "a")) )
114       {
115          log_error(LOG_LEVEL_ERROR, "init_errlog(): can't open logfile: %s", logfname);
116 #if defined(_WIN32) && ! defined (_WIN_CONSOLE)
117             MessageBox(NULL, "init_errlog(): can't open logfile", "Internet JunkBuster Error", 
118                MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);  
119 #endif /* defined(_WIN32) && ! defined (_WIN_CONSOLE) */
120          exit(1);
121       }
122
123       /* set logging to be completely unbuffered */
124       setbuf(fp, NULL);
125
126       logfp = fp;
127    }
128
129    log_error(LOG_LEVEL_INFO, "Internet JunkBuster version " VERSION);
130    if (prog_name != NULL)
131    {
132       log_error(LOG_LEVEL_INFO, "Program name: %s", prog_name);
133    }
134
135    /* FIXME RACE HAZARD: should end critical section error_log_use here */
136
137 } /* init_error_log */
138
139
140 /*********************************************************************
141  *
142  * Function    :  log_error
143  *
144  * Description :  This is the error-reporting and logging function.
145  *
146  * Parameters  :
147  *          1  :  loglevel  = the type of message to be logged
148  *          2  :  fmt       = the main string we want logged, printf-like
149  *          3  :  ...       = arguments to be inserted in fmt (printf-like).
150  *
151  * Returns     :  N/A
152  *
153  *********************************************************************/
154 void log_error(int loglevel, char *fmt, ...)
155 {
156    va_list ap;
157    char outbuf[BUFSIZ];
158    char * src = fmt;
159    int outc = 0;
160    long this_thread = 1;  /* was: pthread_t this_thread;*/
161
162    /* verify if loglevel applies to current settings and bail out if negative */
163    if(!(loglevel & debug))
164    {
165                 return;
166    }
167
168    /* FIXME get current thread id */
169    /* this_thread = (long)pthread_self(); */
170
171    switch (loglevel)
172    {
173       case LOG_LEVEL_ERROR:
174          outc = sprintf(outbuf, "IJB(%d) Error: ", this_thread);
175          break;
176       case LOG_LEVEL_GPC:
177          outc = sprintf(outbuf, "IJB(%d) Request: ", this_thread);
178          break;
179       case LOG_LEVEL_CONNECT:
180          outc = sprintf(outbuf, "IJB(%d) Connect: ", this_thread);
181          break;
182       case LOG_LEVEL_HEADER:
183          outc = sprintf(outbuf, "IJB(%d) Header: ", this_thread);
184          break;
185       case LOG_LEVEL_INFO:
186          outc = sprintf(outbuf, "IJB(%d) Info: ", this_thread);
187          break;
188       case LOG_LEVEL_REF:
189          outc = sprintf(outbuf, "IJB(%d) Re-Filter: ", this_thread);
190          break;
191       case LOG_LEVEL_FRC:
192          outc = sprintf(outbuf, "IJB(%d) Force: ", this_thread);
193          break;
194       default:
195          outc = sprintf(outbuf, "IJB(%d) UNKNOWN LOG TYPE(%d): ", this_thread, loglevel);
196          break;
197    }
198    
199    /* get ready to scan var. args. */
200    va_start( ap, fmt );
201
202    /* build formatted message from fmt and var-args */
203    while ((*src) && (outc < BUFSIZ-2))
204    {
205       char tempbuf[BUFSIZ];
206       char *sval;
207       int ival;
208       unsigned uval;
209       long lval;
210       unsigned long ulval;
211       int oldoutc;
212       char ch;
213       
214       ch = *src++;
215       if( ch != '%' )
216       {
217          outbuf[outc++] = ch;
218          continue;
219       }
220
221       ch = *src++;
222       switch (ch) {
223          case '%':
224             outbuf[outc++] = '%';
225             break;
226          case 'd':
227             ival = va_arg( ap, int );
228             oldoutc = outc;
229             outc += sprintf(tempbuf, "%d", ival);
230             if (outc < BUFSIZ-1) 
231             {
232                strcpy(outbuf + oldoutc, tempbuf);
233             }
234             else
235             {
236                outbuf[oldoutc] = '\0';
237             }
238             break;
239          case 'u':
240             uval = va_arg( ap, unsigned );
241             oldoutc = outc;
242             outc += sprintf(tempbuf, "%u", uval);
243             if (outc < BUFSIZ-1) 
244             {
245                strcpy(outbuf + oldoutc, tempbuf);
246             }
247             else
248             {
249                outbuf[oldoutc] = '\0';
250             }
251             break;
252          case 'l':
253             /* this is a modifier that must be followed by u or d */
254             ch = *src++;
255             if (ch == 'd')
256             {
257                lval = va_arg( ap, long );
258                oldoutc = outc;
259                outc += sprintf(tempbuf, "%ld", lval);
260             }
261             else if (ch == 'u')
262             {
263                ulval = va_arg( ap, unsigned long );
264                oldoutc = outc;
265                outc += sprintf(tempbuf, "%lu", ulval);
266             }
267             else
268             {
269                /* Error */
270                sprintf(outbuf, "IJB(%d) Error: log_error(): Bad format string:\n"
271                                "Format = \"%s\"\n"
272                                "Exiting.", this_thread, fmt);
273                /* FIXME RACE HAZARD: should start critical section error_log_use here */
274                if( !logfp )
275                {
276                   logfp = stderr;
277                }
278                fputs(outbuf, logfp);
279                /* FIXME RACE HAZARD: should end critical section error_log_use here */
280 #if defined(_WIN32) && ! defined (_WIN_CONSOLE)
281                MessageBox(NULL, outbuf, "Internet JunkBuster Error", 
282                   MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);  
283 #endif /* defined(_WIN32) && ! defined (_WIN_CONSOLE) */
284                exit(1);
285                break;
286             }
287             if (outc < BUFSIZ-1) 
288             {
289                strcpy(outbuf + oldoutc, tempbuf);
290             }
291             else
292             {
293                outbuf[oldoutc] = '\0';
294             }
295             break;
296          case 'c':
297             /*
298              * Note that char paramaters are converted to int, so we need to
299              * pass "int" to va_arg.  (See K&R, 2nd ed, section A7.3.2, page 202)
300              */
301             outbuf[outc++] = (char) va_arg( ap, int );
302             break;
303          case 's':
304             sval = va_arg( ap, char * );
305             oldoutc = outc;
306             outc += strlen(sval);
307             if (outc < BUFSIZ-1) 
308             {
309                strcpy(outbuf + oldoutc, sval);
310             }
311             else
312             {
313                outbuf[oldoutc] = '\0';
314             }
315             break;
316          case 'E':
317             /* Non-standard: Print error code from errno */
318             ival = errno;
319 #ifndef NOSTRERROR
320             sval = strerror(ival);
321 #else /* def NOSTRERROR */
322             sval = NULL
323 #endif /* def NOSTRERROR */
324             if (sval == NULL)
325             {
326                sprintf(tempbuf, "(errno = %d)", ival);
327                sval = tempbuf;
328             }
329             oldoutc = outc;
330             outc += strlen(sval);
331             if (outc < BUFSIZ-1) 
332             {
333                strcpy(outbuf + oldoutc, sval);
334             }
335             else
336             {
337                outbuf[oldoutc] = '\0';
338             }
339             break;
340          default:
341             sprintf(outbuf, "IJB(%d) Error: log_error(): Bad format string:\n"
342                             "Format = \"%s\"\n"
343                             "Exiting.", this_thread, fmt);
344             /* FIXME RACE HAZARD: should start critical section error_log_use here */
345             if( !logfp )
346             {
347                logfp = stderr;
348             }
349             fputs(outbuf, logfp);
350             /* FIXME RACE HAZARD: should end critical section error_log_use here */
351 #if defined(_WIN32) && ! defined (_WIN_CONSOLE)
352             MessageBox(NULL, outbuf, "Internet JunkBuster Error", 
353                MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);  
354 #endif /* defined(_WIN32) && ! defined (_WIN_CONSOLE) */
355             exit(1);
356             break;
357
358       } /* switch( p ) */
359
360    } /* for( p ... ) */
361    
362    /* done with var. args */
363    va_end( ap );
364    
365    if (outc >= BUFSIZ-2)
366    {
367       /* insufficient room for newline and trailing null. */
368
369       static const char warning[] = "... [too long, truncated]\n";
370
371       if (outc < BUFSIZ)
372       {
373          /* Need to add terminating null in this case. */
374          outbuf[outc] = '\0';
375       }
376
377       /* Truncate output */
378       outbuf[BUFSIZ - sizeof(warning)] = '\0';
379
380       /* Append warning */
381       strcat(outbuf, warning);
382    }
383    else
384    {
385       /* Add terminating newline and null */
386       outbuf[outc++] = '\n';
387       outbuf[outc] = '\0';
388    }
389
390    /* FIXME RACE HAZARD: should start critical section error_log_use here */
391
392    /* deal with glibc stupidity - it won't let you initialize logfp */
393    if( !logfp )
394    {
395       logfp = stderr;
396    }
397
398    fputs(outbuf, logfp);
399
400    /* FIXME RACE HAZARD: should end critical section error_log_use here */
401
402 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
403    /* Write to display */
404    LogPutString(outbuf);
405    LogShowActivity();
406 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
407
408 }
409
410
411 /*
412   Local Variables:
413   tab-width: 3
414   end:
415 */
416