Remove splint tags.
[platform/upstream/rpm.git] / rpmio / rpmlog.c
1 /** \ingroup rpmio
2  * \file rpmio/rpmlog.c
3  */
4
5 #include "system.h"
6 #include <stdarg.h>
7 #include "rpmlog.h"
8 #include "debug.h"
9
10 #ifndef va_copy
11 # ifdef __va_copy
12 #  define va_copy(DEST,SRC) __va_copy((DEST),(SRC))
13 # else
14 #  ifdef HAVE_VA_LIST_AS_ARRAY
15 #   define va_copy(DEST,SRC) (*(DEST) = *(SRC))
16 #  else
17 #   define va_copy(DEST,SRC) ((DEST) = (SRC))
18 #  endif
19 # endif
20 #endif
21
22
23 static int nrecs = 0;
24 static rpmlogRec recs = NULL;
25
26 /**
27  * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
28  * @param p             memory to free
29  * @retval              NULL always
30  */
31 static inline void *
32 _free(const void * p)
33 {
34     if (p != NULL)      free((void *)p);
35     return NULL;
36 }
37
38 int rpmlogGetNrecs(void)
39 {
40     return nrecs;
41 }
42
43 int rpmlogCode(void)
44 {
45     if (recs != NULL && nrecs > 0)
46         return recs[nrecs-1].code;
47     return -1;
48 }
49
50
51 const char * rpmlogMessage(void)
52 {
53     if (recs != NULL && nrecs > 0)
54         return recs[nrecs-1].message;
55     return _("(no error)");
56 }
57
58 void rpmlogPrint(FILE *f)
59 {
60     int i;
61
62     if (f == NULL)
63         f = stderr;
64
65     if (recs)
66     for (i = 0; i < nrecs; i++) {
67         rpmlogRec rec = recs + i;
68         if (rec->message && *rec->message)
69             fprintf(f, "    %s", rec->message);
70     }
71 }
72
73 void rpmlogClose (void)
74 {
75     int i;
76
77     if (recs)
78     for (i = 0; i < nrecs; i++) {
79         rpmlogRec rec = recs + i;
80         rec->message = _free(rec->message);
81     }
82     recs = _free(recs);
83     nrecs = 0;
84 }
85
86 void rpmlogOpen (const char *ident, int option,
87                 int facility)
88 {
89 }
90
91 static unsigned rpmlogMask = RPMLOG_UPTO( RPMLOG_NOTICE );
92
93 #ifdef NOTYET
94 static unsigned rpmlogFacility = RPMLOG_USER;
95 #endif
96
97 int rpmlogSetMask (int mask)
98 {
99     int omask = rpmlogMask;
100     if (mask)
101         rpmlogMask = mask;
102     return omask;
103 }
104
105 static rpmlogCallback _rpmlogCallback = NULL;
106
107 rpmlogCallback rpmlogSetCallback(rpmlogCallback cb)
108 {
109     rpmlogCallback ocb = _rpmlogCallback;
110     _rpmlogCallback = cb;
111     return ocb;
112 }
113
114 static FILE * _stdlog = NULL;
115
116 FILE * rpmlogSetFile(FILE * fp)
117 {
118     FILE * ofp = _stdlog;
119     _stdlog = fp;
120     return ofp;
121 }
122
123 /*@-readonlytrans@*/    /* FIX: double indirection. */
124 static char *rpmlogMsgPrefix[] = {
125     N_("fatal error: "),/*!< RPMLOG_EMERG */
126     N_("fatal error: "),/*!< RPMLOG_ALERT */
127     N_("fatal error: "),/*!< RPMLOG_CRIT */
128     N_("error: "),      /*!< RPMLOG_ERR */
129     N_("warning: "),    /*!< RPMLOG_WARNING */
130     "",                 /*!< RPMLOG_NOTICE */
131     "",                 /*!< RPMLOG_INFO */
132     "D: ",              /*!< RPMLOG_DEBUG */
133 };
134
135 #if !defined(HAVE_VSNPRINTF)
136 static inline int vsnprintf(char * buf, int nb,
137         const char * fmt, va_list ap)
138 {
139     return vsprintf(buf, fmt, ap);
140 }
141 #endif
142
143 /* FIX: rpmlogMsgPrefix[] dependent, not unqualified */
144 /* FIX: rpmlogMsgPrefix[] may be NULL */
145 static void vrpmlog (unsigned code, const char *fmt, va_list ap)
146 {
147     unsigned pri = RPMLOG_PRI(code);
148     unsigned mask = RPMLOG_MASK(pri);
149 #ifdef NOTYET
150     unsigned fac = RPMLOG_FAC(code);
151 #endif
152     char *msgbuf, *msg;
153     int msgnb = BUFSIZ, nb;
154     FILE * msgout = (_stdlog ? _stdlog : stderr);
155
156     if ((mask & rpmlogMask) == 0)
157         return;
158
159     msgbuf = xmalloc(msgnb);
160     *msgbuf = '\0';
161
162     /* Allocate a sufficently large buffer for output. */
163     while (1) {
164         va_list apc;
165         va_copy(apc, ap);
166         nb = vsnprintf(msgbuf, msgnb, fmt, apc);
167         if (nb > -1 && nb < msgnb)
168             break;
169         if (nb > -1)            /* glibc 2.1 (and later) */
170             msgnb = nb+1;
171         else                    /* glibc 2.0 */
172             msgnb *= 2;
173         msgbuf = xrealloc(msgbuf, msgnb);
174         va_end(apc);
175     }
176     msgbuf[msgnb - 1] = '\0';
177     msg = msgbuf;
178
179     /* Save copy of all messages at warning (or below == "more important"). */
180     if (pri <= RPMLOG_WARNING) {
181
182         if (recs == NULL)
183             recs = xmalloc((nrecs+2) * sizeof(*recs));
184         else
185             recs = xrealloc(recs, (nrecs+2) * sizeof(*recs));
186         recs[nrecs].code = code;
187         recs[nrecs].message = msg = xrealloc(msgbuf, strlen(msgbuf)+1);
188         msgbuf = NULL;          /* XXX don't free at exit. */
189         recs[nrecs+1].code = 0;
190         recs[nrecs+1].message = NULL;
191         ++nrecs;
192
193         if (_rpmlogCallback) {
194             /* FIX: useless callback */
195             _rpmlogCallback();
196             return;     /* XXX Preserve legacy rpmError behavior. */
197         }
198     }
199
200     /* rpmMessage behavior */
201
202     switch (pri) {
203     case RPMLOG_INFO:
204     case RPMLOG_NOTICE:
205         msgout = (_stdlog ? _stdlog : stdout);
206         break;
207
208     case RPMLOG_EMERG:
209     case RPMLOG_ALERT:
210     case RPMLOG_CRIT:
211     case RPMLOG_ERR: /* XXX Legacy rpmError behavior used stdout w/o prefix. */
212     case RPMLOG_WARNING:
213     case RPMLOG_DEBUG:
214         break;
215     }
216
217     if (rpmlogMsgPrefix[pri] && *rpmlogMsgPrefix[pri])
218         (void) fputs(_(rpmlogMsgPrefix[pri]), msgout);
219
220     (void) fputs(msg, msgout);
221     (void) fflush(msgout);
222     msgbuf = _free(msgbuf);
223     if (pri <= RPMLOG_CRIT)
224         exit(EXIT_FAILURE);
225 }
226
227 void rpmlog (int code, const char *fmt, ...)
228 {
229     va_list ap;
230
231     va_start(ap, fmt);
232     /* FIX: shrug */
233     vrpmlog(code, fmt, ap);
234     va_end(ap);
235 }
236
237 int rpmErrorCode(void)
238 {
239     return rpmlogCode();
240 }
241
242 const char * rpmErrorString(void)
243 {
244     return rpmlogMessage();
245 }
246
247 rpmlogCallback rpmErrorSetCallback(rpmlogCallback cb)
248 {
249     return rpmlogSetCallback(cb);
250 }