1 /* -*- mode: c; tab-width: 4; c-basic-offset: 4;  indent-tabs-mode: nil -*- */
2 
3 /*********************************************************************
4  * Clustal Omega - Multiple sequence alignment
5  *
6  * Copyright (C) 2010 University College Dublin
7  *
8  * Clustal-Omega is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  * This file is part of Clustal-Omega.
14  *
15  ********************************************************************/
16 
17 /*
18  *  RCS $Id$
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <assert.h>
30 
31 #include "log.h"
32 
33 /* a default standard logger */
34 log_t rLog;
35 
36 
37 
38 void
39 LogVfprintf(FILE *prFP, char *pcFmt, va_list rVArgList);
40 void
41 LogWarn(FILE *prFP, char *pcFmt, va_list rVArgList);
42 void
43 LogError(FILE *prFP, char *pcFmt, va_list rVArgList);
44 void
45 LogCritical(FILE *prFP, char *pcFmt, va_list rVArgList);
46 void
47 LogFatal(FILE *prFP, char *pcFmt, va_list rVArgList);
48 void
49 LogForcedDebug(FILE *prFP, char *pcFmt, va_list rVArgList);
50 
51 
52 
53 
54 /**
55  * @brief Plain, default print function
56  *
57  * Newline character is automatically appended to message.
58  *
59  */
60 void
LogVfprintf(FILE * prFP,char * pcFmt,va_list rVArgList)61 LogVfprintf(FILE *prFP, char *pcFmt, va_list rVArgList)
62 {
63 	/* print prefix */
64     vfprintf(prFP, pcFmt, rVArgList);
65     fprintf(prFP,"\n");
66 
67 #ifndef NDEBUG
68     fflush(prFP);
69 #endif
70 }
71 /* end of LogVfprintf() */
72 
73 
74 
75 /**
76  * @brief
77  *
78  */
79 void
LogWarn(FILE * prFP,char * pcFmt,va_list rVArgList)80 LogWarn(FILE *prFP, char *pcFmt, va_list rVArgList)
81 {
82 	fprintf(prFP, "WARNING: ");
83     LogVfprintf(prFP, pcFmt, rVArgList);
84 }
85 /* end of LogWarn() */
86 
87 
88 
89 /**
90  * @brief
91  *
92  */
93 void
LogError(FILE * prFP,char * pcFmt,va_list rVArgList)94 LogError(FILE *prFP, char *pcFmt, va_list rVArgList)
95 {
96 	fprintf(prFP, "ERROR: ");
97     LogVfprintf(prFP, pcFmt, rVArgList);
98 }
99 /* end of LogError() */
100 
101 
102 
103 /**
104  * @brief
105  *
106  */
107 void
LogCritical(FILE * prFP,char * pcFmt,va_list rVArgList)108 LogCritical(FILE *prFP, char *pcFmt, va_list rVArgList)
109 {
110 	fprintf(prFP, "CRITICAL ERROR: ");
111     LogVfprintf(prFP, pcFmt, rVArgList);
112 }
113 /* end of LogCritical() */
114 
115 
116 
117 /**
118  * @brief Will also exit!
119  */
120 void
LogFatal(FILE * prFP,char * pcFmt,va_list rVArgList)121 LogFatal(FILE *prFP, char *pcFmt, va_list rVArgList)
122 {
123 	fprintf(prFP, "FATAL: ");
124     LogVfprintf(prFP, pcFmt, rVArgList);
125 
126     exit(EXIT_FAILURE);
127 }
128 /* end of LogFatal() */
129 
130 
131 
132 /**
133  * @brief
134  *
135  */
136 void
LogForcedDebug(FILE * prFP,char * pcFmt,va_list rVArgList)137 LogForcedDebug(FILE *prFP, char *pcFmt, va_list rVArgList)
138 {
139 	fprintf(prFP, "FORCED DEBUG: ");
140     LogVfprintf(prFP, pcFmt, rVArgList);
141 }
142 /* end of LogForcedDebug() */
143 
144 
145 
146 /**
147  *
148  * @brief Sets up default function pointers
149  *
150  */
151 void
LogDefaultSetup(log_t * log)152 LogDefaultSetup(log_t *log)
153 {
154     log->iLogLevelEnabled = LOG_WARN;
155 
156 	log->prFP[LOG_DEBUG] = stdout;
157 	log->prFP[LOG_INFO] = stdout;
158 	log->prFP[LOG_WARN] = stderr;
159 	log->prFP[LOG_ERROR] = stderr;
160 	log->prFP[LOG_CRITICAL] = stderr;
161 	log->prFP[LOG_FATAL] = stderr;
162 	log->prFP[LOG_FORCED_DEBUG] = stderr;
163 
164 	log->prFunc[LOG_DEBUG] = &LogVfprintf;
165 	log->prFunc[LOG_INFO] = &LogVfprintf;
166 	log->prFunc[LOG_WARN] = &LogWarn;
167 	log->prFunc[LOG_ERROR] = &LogError;
168 	log->prFunc[LOG_CRITICAL] = &LogCritical;
169 	log->prFunc[LOG_FATAL] = &LogFatal;
170 	log->prFunc[LOG_FORCED_DEBUG] = &LogForcedDebug;
171 }
172 /* end of LogDefaultSetup() */
173 
174 
175 
176 /**
177  * @brief Log to certain level
178  *
179  * See also comp.lang.c FAQ list · Question 15.12
180  * http://c-faq.com/varargs/handoff.html How can I write a function which
181  * takes a variable number of arguments and passes them to some other function
182  * (which takes a variable number of arguments)?
183  *
184  */
185 void
Log(log_t * prLog,int iLevel,char * pcFmt,...)186 Log(log_t *prLog, int iLevel, char *pcFmt, ...)
187 {
188 	va_list rVArgList;
189     void (*prFunc) (FILE *prFP, char *pcFormat, va_list rVArgList);
190 	FILE *prFP;
191 
192 	assert(iLevel>=0 && iLevel<=LOG_NUM_LEVELS);
193 
194     /* fprintf(stderr, "DEBUG: iLevel=%d and iLogLevelEnabled=%d\n", iLevel, prLog->iLogLevelEnabled); */
195 
196 	/* return if below current loglevel */
197 	if (iLevel < prLog->iLogLevelEnabled) {
198 		return;
199 	}
200 
201 	prFunc = prLog->prFunc[iLevel];
202 	prFP = prLog->prFP[iLevel];
203 
204 	/* return if muted */
205 	if (NULL == prFunc) {
206 		return;
207 	}
208 
209 	va_start(rVArgList, pcFmt);
210 	prFunc(prFP, pcFmt, rVArgList);
211 	va_end(rVArgList);
212 }
213 /* end of Log() */
214 
215 
216 
217 /**
218  *
219  * @brief Change file pointer for certain level
220  *
221  */
222 void
LogSetFP(log_t * prLog,int iLevel,FILE * prFP)223 LogSetFP(log_t *prLog, int iLevel, FILE *prFP)
224 {
225 	assert(iLevel>=0 && iLevel<=LOG_NUM_LEVELS);
226 
227 	prLog->prFP[iLevel] = prFP;
228 }
229 /* end of LogSetFP() */
230 
231 
232 
233 /**
234  *
235  * @brief Return file pointer for certain level
236  *
237  */
238 FILE *
LogGetFP(log_t * prLog,int iLevel)239 LogGetFP(log_t *prLog, int iLevel)
240 {
241 	assert(iLevel>=0 && iLevel<=LOG_NUM_LEVELS);
242 
243 	return prLog->prFP[iLevel];
244 }
245 /* end of LogGetFP() */
246 
247 
248 
249 
250 
251 /**
252  *
253  * @brief Change file pointer for all levels
254  *
255  */
256 void
LogSetFPForAll(log_t * prLog,FILE * prFP)257 LogSetFPForAll(log_t *prLog, FILE *prFP)
258 {
259 	int iAux;
260 
261 	for (iAux=0; iAux<LOG_NUM_LEVELS; iAux++) {
262 		prLog->prFP[iAux] = prFP;
263 	}
264 }
265 /* end of LogSetFP() */
266 
267 
268 
269 /**
270  *
271  * @brief Mute certain level (i.e set the corresponding function to NULL)
272  *
273  */
274 void
LogMute(log_t * prLog,int iLevel)275 LogMute(log_t *prLog, int iLevel)
276 {
277 	assert(iLevel>=0 && iLevel<=LOG_NUM_LEVELS);
278 
279 	prLog->prFunc[iLevel] = NULL;
280 }
281 /* end of LogMute() */
282 
283 
284 /**
285  *
286  * @brief Mute all channels
287  *
288  */
289 void
LogMuteAll(log_t * prLog)290 LogMuteAll(log_t *prLog)
291 {
292 	int iAux;
293 
294 	for (iAux=0; iAux<LOG_NUM_LEVELS; iAux++) {
295 		LogMute(prLog, iAux);
296 	}
297 }
298 /* end of LogMuteAll() */
299 
300 
301 
302 /**
303  * @brief
304  *
305  */
306 void
LogFuncOverwrite(log_t * prLog,int iLevel,void (* Func)(FILE * prFP,char * pcFormat,va_list rVArgList))307 LogFuncOverwrite(log_t *prLog, int iLevel,
308                  void (*Func) (FILE *prFP, char *pcFormat, va_list rVArgList))
309 {
310 	assert(iLevel>=0 && iLevel<=LOG_NUM_LEVELS);
311 
312     prLog->prFunc[iLevel] = Func;
313 
314 }
315 /* end of LogFuncOverwrite() */
316 
317 
318 
319 #ifdef LOG_TEST
320 
321 
322 #define TEXT "Lorem ipsum dolor sit amet"
323 
324 void
PrintSomeTextToAll(log_t * prLog)325 PrintSomeTextToAll(log_t *prLog) {
326 	int iAux;
327 	for (iAux=0; iAux<LOG_NUM_LEVELS; iAux++) {
328 		Log(prLog, iAux, TEXT);
329 	}
330 }
331 
332 
333 int
main(int argc,char ** argv)334 main(int argc, char**argv) {
335 	log_t prLog;
336 	log_t pr2ndLog;
337 	FILE *prFP;
338 	char *pcTmpFileName = "schmock.txt";
339 
340 	prFP = fopen(pcTmpFileName, "w");
341 
342 
343 	LogDefaultSetup(&prLog);
344 	LogDefaultSetup(&pr2ndLog);
345 
346 	printf("Printing to log:\n");
347 	PrintSomeTextToAll(&prLog);
348 	printf("---\n");
349 
350 	printf("Printing to pr2ndLog:\n");
351 	PrintSomeTextToAll(&prLog);
352 	printf("---\n");
353 
354 
355 
356 	printf("Changing second log's FP to write to '%s'\n", pcTmpFileName);
357 	LogSetFPForAll(&pr2ndLog, prFP);
358 
359 	printf("Printing to pr2ndLog:\n");
360 	PrintSomeTextToAll(&pr2ndLog);
361 	printf("---\n");
362 
363 
364 	printf("Changing Info() to new function (Fatal()) in log:\n");
365     LogFuncOverwrite(&prLog, LOG_INFO, &LogFatal);
366 
367 	printf("Printing to log:\n");
368 	PrintSomeTextToAll(&prLog);
369 	printf("---\n");
370 
371 
372 
373 	fclose(prFP);
374 
375 	return 0;
376 }
377 
378 
379 #endif
380