Merge pull request #78 from ffontaine/master
[olsrd.git] / lib / pud / nmealib / src / context.c
1 /*
2  * This file is part of nmealib.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <nmealib/context.h>
19
20 #include <nmealib/util.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 /**
26  * The structure with the nmealib context.
27  */
28 typedef struct _NmeaContext {
29   volatile NmeaContextPrintFunction traceFunction;
30   volatile NmeaContextPrintFunction errorFunction;
31 } NmeaContext;
32
33 /** The nmealib context */
34 static NmeaContext nmealibContext = {
35     .traceFunction = NULL,
36     .errorFunction = NULL };
37
38 NmeaContextPrintFunction nmeaContextSetTraceFunction(NmeaContextPrintFunction traceFunction) {
39   NmeaContextPrintFunction r = nmealibContext.traceFunction;
40   nmealibContext.traceFunction = traceFunction;
41   return r;
42 }
43
44 NmeaContextPrintFunction nmeaContextSetErrorFunction(NmeaContextPrintFunction errorFunction) {
45   NmeaContextPrintFunction r = nmealibContext.errorFunction;
46   nmealibContext.errorFunction = errorFunction;
47   return r;
48 }
49
50 void nmeaContextTraceBuffer(const char *s, size_t sz) {
51   NmeaContextPrintFunction f = nmealibContext.traceFunction;
52   if (f && s && sz) {
53     (*f)(s, sz);
54   }
55 }
56
57 #define nmeaContextBufferEnlarge(buf, sz) { \
58   if (!(buf = realloc(buf, sz))) { \
59     /* can't be covered in a test */ \
60     goto out; \
61   } \
62 }
63
64 void nmeaContextTrace(const char *s, ...) {
65   NmeaContextPrintFunction f = nmealibContext.traceFunction;
66   if (s && f) {
67     va_list args;
68     va_list argsCopy;
69     char *buf = NULL;
70     size_t bufSz = NMEALIB_BUFFER_CHUNK_SIZE;
71     int printedChars;
72
73     va_start(args, s);
74     va_copy(argsCopy, args);
75
76     nmeaContextBufferEnlarge(buf, bufSz);
77     buf[0] = '\0';
78
79     printedChars = vsnprintf(buf, bufSz, s, args);
80     if (printedChars <= 0) {
81       goto out;
82     }
83     if ((size_t) printedChars >= bufSz) {
84       bufSz = (size_t) printedChars + 1;
85       nmeaContextBufferEnlarge(buf, bufSz);
86       printedChars = vsnprintf(buf, bufSz, s, argsCopy);
87     }
88
89     buf[bufSz - 1] = '\0';
90
91     (*f)(buf, (size_t) printedChars);
92
93 out:
94     va_end(argsCopy);
95     va_end(args);
96     free(buf);
97   }
98 }
99
100 void nmeaContextError(const char *s, ...) {
101   NmeaContextPrintFunction f = nmealibContext.errorFunction;
102   if (s && f) {
103     va_list args;
104     va_list argsCopy;
105     char *buf = NULL;
106     size_t bufSz = NMEALIB_BUFFER_CHUNK_SIZE;
107     int printedChars;
108
109     va_start(args, s);
110     va_copy(argsCopy, args);
111
112     nmeaContextBufferEnlarge(buf, bufSz);
113     buf[0] = '\0';
114
115     printedChars = vsnprintf(buf, bufSz, s, args);
116     if (printedChars <= 0) {
117       goto out;
118     }
119     if ((size_t) printedChars >= bufSz) {
120       bufSz = (size_t) printedChars + 1;
121       nmeaContextBufferEnlarge(buf, bufSz);
122       printedChars = vsnprintf(buf, bufSz, s, argsCopy);
123     }
124
125     buf[bufSz - 1] = '\0';
126
127     (*f)(buf, (size_t) printedChars);
128
129 out:
130     va_end(argsCopy);
131     va_end(args);
132     free(buf);
133   }
134 }