1 /***************************************************************************
2  * logging.c
3  *
4  * Log handling routines for libmseed
5  *
6  * Chad Trabant
7  * IRIS Data Management Center
8  *
9  * modified: 2014.197
10  ***************************************************************************/
11 
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include "libmseed.h"
18 
19 void ms_loginit_main (MSLogParam *logp,
20                       void (*log_print) (char *), const char *logprefix,
21                       void (*diag_print) (char *), const char *errprefix);
22 
23 int ms_log_main (MSLogParam *logp, int level, va_list *varlist);
24 
25 /* Initialize the global logging parameters */
26 MSLogParam gMSLogParam = {NULL, NULL, NULL, NULL};
27 
28 /***************************************************************************
29  * ms_loginit:
30  *
31  * Initialize the global logging parameters.
32  *
33  * See ms_loginit_main() description for usage.
34  ***************************************************************************/
35 void
ms_loginit(void (* log_print)(char *),const char * logprefix,void (* diag_print)(char *),const char * errprefix)36 ms_loginit (void (*log_print) (char *), const char *logprefix,
37             void (*diag_print) (char *), const char *errprefix)
38 {
39   ms_loginit_main (&gMSLogParam, log_print, logprefix, diag_print, errprefix);
40 } /* End of ms_loginit() */
41 
42 /***************************************************************************
43  * ms_loginit_l:
44  *
45  * Initialize MSLogParam specific logging parameters.  If the logging parameters
46  * have not been initialized (log == NULL) new parameter space will
47  * be allocated.
48  *
49  * See ms_loginit_main() description for usage.
50  *
51  * Returns a pointer to the created/re-initialized MSLogParam struct
52  * on success and NULL on error.
53  ***************************************************************************/
54 MSLogParam *
ms_loginit_l(MSLogParam * logp,void (* log_print)(char *),const char * logprefix,void (* diag_print)(char *),const char * errprefix)55 ms_loginit_l (MSLogParam *logp,
56               void (*log_print) (char *), const char *logprefix,
57               void (*diag_print) (char *), const char *errprefix)
58 {
59   MSLogParam *llog;
60 
61   if (logp == NULL)
62   {
63     llog = (MSLogParam *)malloc (sizeof (MSLogParam));
64 
65     if (llog == NULL)
66     {
67       ms_log (2, "ms_loginit_l(): Cannot allocate memory\n");
68       return NULL;
69     }
70 
71     llog->log_print  = NULL;
72     llog->logprefix  = NULL;
73     llog->diag_print = NULL;
74     llog->errprefix  = NULL;
75   }
76   else
77   {
78     llog = logp;
79   }
80 
81   ms_loginit_main (llog, log_print, logprefix, diag_print, errprefix);
82 
83   return llog;
84 } /* End of ms_loginit_l() */
85 
86 /***************************************************************************
87  * ms_loginit_main:
88  *
89  * Initialize the logging subsystem.  Given values determine how ms_log()
90  * and ms_log_l() emit messages.
91  *
92  * This function modifies the logging parameters in the passed MSLogParam.
93  *
94  * Any log/error printing functions indicated must except a single
95  * argument, namely a string (char *).  The ms_log() and
96  * ms_log_r() functions format each message and then pass the result
97  * on to the log/error printing functions.
98  *
99  * If the log/error prefixes have been set they will be pre-pended to the
100  * message.
101  *
102  * Use NULL for the function pointers or the prefixes if they should not
103  * be changed from previously set or default values.  The default behavior
104  * of the logging subsystem is given in the example below.
105  *
106  * Example: ms_loginit_main (0, (void*)&printf, NULL, (void*)&printf, "error: ");
107  ***************************************************************************/
108 void
ms_loginit_main(MSLogParam * logp,void (* log_print)(char *),const char * logprefix,void (* diag_print)(char *),const char * errprefix)109 ms_loginit_main (MSLogParam *logp,
110                  void (*log_print) (char *), const char *logprefix,
111                  void (*diag_print) (char *), const char *errprefix)
112 {
113   if (!logp)
114     return;
115 
116   if (log_print)
117     logp->log_print = log_print;
118 
119   if (logprefix)
120   {
121     if (strlen (logprefix) >= MAX_LOG_MSG_LENGTH)
122     {
123       ms_log_l (logp, 2, 0, "log message prefix is too large\n");
124     }
125     else
126     {
127       logp->logprefix = logprefix;
128     }
129   }
130 
131   if (diag_print)
132     logp->diag_print = diag_print;
133 
134   if (errprefix)
135   {
136     if (strlen (errprefix) >= MAX_LOG_MSG_LENGTH)
137     {
138       ms_log_l (logp, 2, 0, "error message prefix is too large\n");
139     }
140     else
141     {
142       logp->errprefix = errprefix;
143     }
144   }
145 
146   return;
147 } /* End of ms_loginit_main() */
148 
149 /***************************************************************************
150  * ms_log:
151  *
152  * A wrapper to ms_log_main() that uses the global logging parameters.
153  *
154  * See ms_log_main() description for return values.
155  ***************************************************************************/
156 int
ms_log(int level,...)157 ms_log (int level, ...)
158 {
159   int retval;
160   va_list varlist;
161 
162   va_start (varlist, level);
163 
164   retval = ms_log_main (&gMSLogParam, level, &varlist);
165 
166   va_end (varlist);
167 
168   return retval;
169 } /* End of ms_log() */
170 
171 /***************************************************************************
172  * ms_log_l:
173  *
174  * A wrapper to ms_log_main() that uses the logging parameters in a
175  * supplied MSLogParam.  If the supplied pointer is NULL the global logging
176  * parameters will be used.
177  *
178  * See ms_log_main() description for return values.
179  ***************************************************************************/
180 int
ms_log_l(MSLogParam * logp,int level,...)181 ms_log_l (MSLogParam *logp, int level, ...)
182 {
183   int retval;
184   va_list varlist;
185   MSLogParam *llog;
186 
187   if (!logp)
188     llog = &gMSLogParam;
189   else
190     llog = logp;
191 
192   va_start (varlist, level);
193 
194   retval = ms_log_main (llog, level, &varlist);
195 
196   va_end (varlist);
197 
198   return retval;
199 } /* End of ms_log_l() */
200 
201 /***************************************************************************
202  * ms_log_main:
203  *
204  * A standard logging/printing routine.
205  *
206  * The function uses logging parameters specified in the supplied
207  * MSLogParam.
208  *
209  * This function expects 2+ arguments: message level, fprintf format,
210  * and fprintf arguments.
211  *
212  * Three levels are recognized:
213  * 0  : Normal log messages, printed using log_print with logprefix
214  * 1  : Diagnostic messages, printed using diag_print with logprefix
215  * 2+ : Error messagess, printed using diag_print with errprefix
216  *
217  * This function builds the log/error message and passes to it as a
218  * string (char *) to the functions defined with ms_loginit() or
219  * ms_loginit_l().  If the log/error printing functions have not been
220  * defined messages will be printed with fprintf, log messages to
221  * stdout and error messages to stderr.
222  *
223  * If the log/error prefix's have been set with ms_loginit() or
224  * ms_loginit_l() they will be pre-pended to the message.
225  *
226  * All messages will be truncated to the MAX_LOG_MSG_LENGTH, this includes
227  * any set prefix.
228  *
229  * Returns the number of characters formatted on success, and a
230  * a negative value on error.
231  ***************************************************************************/
232 int
ms_log_main(MSLogParam * logp,int level,va_list * varlist)233 ms_log_main (MSLogParam *logp, int level, va_list *varlist)
234 {
235   static char message[MAX_LOG_MSG_LENGTH];
236   int retvalue = 0;
237   int presize;
238   const char *format;
239 
240   if (!logp)
241   {
242     fprintf (stderr, "ms_log_main() called without specifying log parameters");
243     return -1;
244   }
245 
246   message[0] = '\0';
247 
248   format = va_arg (*varlist, const char *);
249 
250   if (level >= 2) /* Error message */
251   {
252     if (logp->errprefix != NULL)
253     {
254       strncpy (message, logp->errprefix, MAX_LOG_MSG_LENGTH);
255       message[MAX_LOG_MSG_LENGTH - 1] = '\0';
256     }
257     else
258     {
259       strncpy (message, "Error: ", MAX_LOG_MSG_LENGTH);
260     }
261 
262     presize  = strlen (message);
263     retvalue = vsnprintf (&message[presize],
264                           MAX_LOG_MSG_LENGTH - presize,
265                           format, *varlist);
266 
267     message[MAX_LOG_MSG_LENGTH - 1] = '\0';
268 
269     if (logp->diag_print != NULL)
270     {
271       logp->diag_print (message);
272     }
273     else
274     {
275       fprintf (stderr, "%s", message);
276     }
277   }
278   else if (level == 1) /* Diagnostic message */
279   {
280     if (logp->logprefix != NULL)
281     {
282       strncpy (message, logp->logprefix, MAX_LOG_MSG_LENGTH);
283       message[MAX_LOG_MSG_LENGTH - 1] = '\0';
284     }
285 
286     presize  = strlen (message);
287     retvalue = vsnprintf (&message[presize],
288                           MAX_LOG_MSG_LENGTH - presize,
289                           format, *varlist);
290 
291     message[MAX_LOG_MSG_LENGTH - 1] = '\0';
292 
293     if (logp->diag_print != NULL)
294     {
295       logp->diag_print (message);
296     }
297     else
298     {
299       fprintf (stderr, "%s", message);
300     }
301   }
302   else if (level == 0) /* Normal log message */
303   {
304     if (logp->logprefix != NULL)
305     {
306       strncpy (message, logp->logprefix, MAX_LOG_MSG_LENGTH);
307       message[MAX_LOG_MSG_LENGTH - 1] = '\0';
308     }
309 
310     presize  = strlen (message);
311     retvalue = vsnprintf (&message[presize],
312                           MAX_LOG_MSG_LENGTH - presize,
313                           format, *varlist);
314 
315     message[MAX_LOG_MSG_LENGTH - 1] = '\0';
316 
317     if (logp->log_print != NULL)
318     {
319       logp->log_print (message);
320     }
321     else
322     {
323       fprintf (stdout, "%s", message);
324     }
325   }
326 
327   return retvalue;
328 } /* End of ms_log_main() */
329