1 
2 /* Abstract logging system used to facilitate multiple modes*/
3 /* of logging*/
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #ifndef _MSC_VER
9 #include <syslog.h>
10 #endif
11 #include <errno.h>
12 #include <stdarg.h>
13 #include <ctype.h>
14 
15 #include "localization.h"
16 #include "logger.h"
17 #include "sci_malloc.h"
18 #include "charEncoding.h"
19 
20 //#define SYSLOG_ENABLE 1
21 
22 #ifndef _MSC_VER
23 static int _LOGGER_mode = _LOGGER_SYSLOG;
24 static int _LOGGER_syslog_mode = LOG_MAIL | LOG_INFO;
25 #else
26 static int _LOGGER_mode = _LOGGER_STDERR;
27 static int _LOGGER_syslog_mode = 0;
28 #endif
29 
30 static FILE *_LOGGER_outf;
31 
32 struct LOGGER_globals
33 {
34     int wrap;
35     int wraplength;
36 };
37 
38 /* Create and Initialise the global structure for LOGGER,*/
39 /*		we init it to have NO wrapping.*/
40 
41 static struct LOGGER_globals LOGGER_glb = { 0, 0 };
42 
43 #ifdef _MSC_VER
44 #define vsnprintf _vsnprintf
45 #endif
46 
47 /*------------------------------------------------------------------------
48 Procedure:     LOGGER_get_file ID:1
49 Purpose:       Returns the pointer to the file being used to output logs to
50 Input:
51 Output:
52 Errors:
53 ------------------------------------------------------------------------*/
LOGGER_get_file(void)54 FILE *LOGGER_get_file( void )
55 {
56     return _LOGGER_outf;
57 }
58 
59 
60 /*------------------------------------------------------------------------
61 Procedure:     LOGGER_set_output_mode ID:1
62 Purpose:       Sets the message/log output method, ie, stderr, stdout
63 or syslog
64 Input:
65 Output:
66 Errors:
67 ------------------------------------------------------------------------*/
LOGGER_set_output_mode(int modechoice)68 int LOGGER_set_output_mode( int modechoice )
69 {
70     _LOGGER_mode = modechoice;
71     return 0;
72 }
73 
74 /*------------------------------------------------------------------------
75 Procedure:     LOGGER_set_output_file ID:1
76 Purpose:       Sets the output file for when _LOGGER_mode is set to
77 _LOGGER_file
78 Input:
79 Output:
80 Errors:
81 ------------------------------------------------------------------------*/
LOGGER_set_output_file(FILE * f)82 int LOGGER_set_output_file( FILE *f )
83 {
84     _LOGGER_outf = f;
85     return 0;
86 }
87 
88 /*------------------------------------------------------------------------
89 Procedure:     LOGGER_set_syslog_mode ID:1
90 Purpose:       Sets the mode that messaging to the syslog daemon will
91 be sent as (ie, LOG_MAIL|LOG_INFO)
92 Input:
93 Output:
94 Errors:
95 ------------------------------------------------------------------------*/
LOGGER_set_syslog_mode(int syslogmode)96 int LOGGER_set_syslog_mode( int syslogmode )
97 {
98     _LOGGER_syslog_mode = syslogmode;
99     return 0;
100 }
101 
102 
103 
104 
105 /*------------------------------------------------------------------------
106 Procedure:     LOGGER_set_logfile ID:1
107 Purpose:       Opens and setups the internal Log file file pointer with the
108 log file as given by lfname
109 Input:
110 Output:
111 Errors:
112 ------------------------------------------------------------------------*/
LOGGER_set_logfile(char * lfname)113 int LOGGER_set_logfile( char *lfname )
114 {
115     int result = 0;
116 
117     wcfopen(_LOGGER_outf, lfname, "a");
118     if (!_LOGGER_outf)
119     {
120 #if !defined(_MSC_VER) && defined(SYSLOG_ENABLE)
121         syslog(1, _("LOGGER_set_logfile: ERROR - Cannot open logfile '%s' (%s)"), lfname, strerror(errno));
122 #else
123         fprintf(stderr, _("LOGGER_set_logfile: ERROR - Cannot open logfile '%s' (%s)\n"), lfname, strerror(errno));
124 #endif
125         result = -1;
126     }
127 
128     return result;
129 }
130 
131 
132 
133 /*------------------------------------------------------------------------
134 Procedure:     LOGGER_set_wraplength ID:1
135 Purpose:       Sets the character count at which LOGGER will break a line
136 Input:         int length: Positive int indicating number of chracters at which to wrap at
137 Output:
138 Errors:
139 ------------------------------------------------------------------------*/
LOGGER_set_wraplength(int length)140 int LOGGER_set_wraplength( int length )
141 {
142     if ( length >= 0 )
143     {
144         LOGGER_glb.wraplength = length;
145     }
146 
147     return LOGGER_glb.wraplength;
148 }
149 
150 /*------------------------------------------------------------------------
151 Procedure:     LOGGER_set_wrap ID:1
152 Purpose:       Set log output wrapping to on or off
153 Input:         int level: 0 = no wrap, > 0 = wrap.
154 Output:
155 Errors:
156 ------------------------------------------------------------------------*/
LOGGER_set_wrap(int level)157 int LOGGER_set_wrap( int level )
158 {
159     if ( level >= 0 )
160     {
161         LOGGER_glb.wrap = level;
162     }
163 
164     return LOGGER_glb.wrap;
165 }
166 
167 
168 
169 /*------------------------------------------------------------------------
170 Procedure:     LOGGER_close_logfile ID:1
171 Purpose:       Closes the modules log file pointer.
172 Input:
173 Output:
174 Errors:
175 ------------------------------------------------------------------------*/
LOGGER_close_logfile(void)176 int LOGGER_close_logfile( void )
177 {
178     int result = 0;
179 
180     if (_LOGGER_outf)
181     {
182         fclose(_LOGGER_outf);
183     }
184 
185     return result;
186 }
187 
188 
189 
190 /*------------------------------------------------------------------------
191 Procedure:     LOGGER_clean_output ID:1
192 Purpose:       Checks through the output string for any characters which could cause
193 potential 'isssues' with the data writing calls, items such as stray non-escaped
194 % characters can cause havoc.
195 Input:         char *string: Raw string
196 int maxsize: Maximum available buffer size for this string to expand to
197 Output:
198 Errors:
199 ------------------------------------------------------------------------*/
LOGGER_clean_output(char * string,char ** buffer)200 int LOGGER_clean_output( char *string, char **buffer )
201 {
202     char *newstr;
203     char *p, *q;
204     char *next_space;
205 
206     int pc;
207     int slen = (int)strlen( string );
208     int line_size;
209     int maxsize = slen * 2;
210 
211     /* First up, allocate maxsize bytes for a temporary new string.*/
212     newstr = MALLOC(slen * 2 + 1);
213     if ( newstr == NULL )
214     {
215         /* FIXME - Report an error here ... to -somewhere-*/
216         return -1;
217     }
218 
219     p = newstr;
220     q = string;
221     pc = 0;
222     line_size = 0;
223 
224     while (slen--)
225     {
226 
227         /* Do we need to apply any wrapping to the output? If so then we*/
228         /*		shall embark on a journey of strange space and distance*/
229         /*		evaluations to determine if we should wrap now or later*/
230 
231         if ( LOGGER_glb.wrap > 0 )
232         {
233             if (isspace((int)*q))
234             {
235                 next_space = strpbrk( (q + 1), "\t\n\v " );
236                 if (next_space != NULL)
237                 {
238                     if ((line_size + (next_space - q)) >= LOGGER_glb.wraplength)
239                     {
240                         *p = '\n';
241                         p++;
242                         pc++;
243                         line_size = 0;
244                     }
245                 }
246             }
247 
248             if ( line_size >= LOGGER_glb.wraplength )
249             {
250                 *p = '\n';
251                 p++;
252                 pc++;
253                 line_size = 0;
254             }
255         }
256 
257         /* If the string has a % in it, then we need to encode it as*/
258         /*	a DOUBLE % symbol.*/
259 
260         if (*q == '%')
261         {
262             /*			if (strchr("fdlsxXn",*(q+1)))*/
263             /*			{*/
264             *p = '%';
265             p++;
266             pc++;
267             /*			}*/
268         }
269 
270         /* Copy the character of the string in*/
271         *p = *q;
272 
273         /* Move everything along.*/
274         q++;
275         p++;
276         pc++;
277         line_size++;
278 
279         if ( pc > (maxsize - 1) )
280         {
281             break;
282         }
283     }
284 
285     *p = '\0';
286 
287     /* This will have to be deallocated later!*/
288     if (newstr)
289     {
290         *buffer = newstr;
291     }
292 
293     return 0;
294 }
295 
296 /*------------------------------------------------------------------------
297 Procedure:     LOGGER_log ID:1
298 Purpose:       Logs the params as supplied to the required
299 output as defined by LOGGER_set_output
300 Input:
301 Output:
302 Errors:
303 ------------------------------------------------------------------------*/
LOGGER_log(char * format,...)304 int LOGGER_log( char *format, ...)
305 {
306     va_list ptr;
307     char tmpoutput[10240];
308     char linebreak[] = "\n";
309     char nolinebreak[] = "";
310     char *lineend;
311     char *output;
312 
313 
314     /* get our variable arguments*/
315     va_start(ptr, format);
316 
317     /* produce output, and spit to the log file*/
318 #ifdef NO_SNPRINTF
319     vsprintf(tmpoutput, format, ptr);
320 #else
321     vsnprintf(tmpoutput, 10240, format, ptr);
322 #endif
323 
324     LOGGER_clean_output( tmpoutput, &output );
325 
326     if ( output[strlen(output) - 1] == '\n' )
327     {
328         lineend = nolinebreak;
329     }
330     else
331     {
332         lineend = linebreak;
333     }
334 
335     if ( output[strlen(output) - 1] == '\n' )
336     {
337         lineend = nolinebreak;
338     }
339     else
340     {
341         lineend = linebreak;
342     }
343 
344     /* Send the output to the appropriate output destination*/
345     switch (_LOGGER_mode)
346     {
347         case _LOGGER_SYSLOG:
348 #if !defined(_MSC_VER) && defined(SYSLOG_ENABLE)
349             syslog(_LOGGER_syslog_mode, "%s", output);
350             break;
351 #endif
352         case _LOGGER_STDERR:
353             fprintf(stderr, "%s%s", output, lineend );
354             break;
355 
356         case _LOGGER_STDOUT:
357             fprintf(stdout, "%s%s", output, lineend);
358             fflush(stdout);
359             break;
360         case _LOGGER_FILE:
361             fprintf(_LOGGER_outf, "%s%s", output, lineend);
362             fflush(_LOGGER_outf);
363             break;
364         default:
365             fprintf(stdout, _("LOGGER-Default: %s%s"), output, lineend);
366     }
367 
368 
369     if (output)
370     {
371         FREE(output);
372     }
373 
374     va_end(ptr);
375 
376     return 0;
377 }
378 
379 
380 
381 
382