- use package version 3 if --nodirtokens is specified.
[platform/upstream/rpm.git] / rpmio / rpmlog.c
1 /** \ingroup rpmio
2  * \file rpmio/rpmlog.c
3  */
4
5 #include "system.h"
6
7 #include <stdarg.h>
8
9 #include "rpmlog.h"
10
11 /*@access rpmlogRec @*/
12
13 static int nrecs = 0;
14 static /*@only@*/ /*@null@*/ rpmlogRec recs = NULL;
15
16 int rpmlogGetNrecs(void)
17 {
18     return nrecs;
19 }
20
21 const char * rpmlogMessage(void)
22 {
23     if (nrecs > 0)
24         return recs[nrecs-1].message;
25     return _("(no error)");
26 }
27
28 void rpmlogPrint(FILE *f)
29 {
30     int i;
31
32     if (f == NULL)
33         f = stderr;
34
35     for (i = 0; i < nrecs; i++) {
36         rpmlogRec rec = recs + i;
37         if (rec->message && *rec->message)
38             fprintf(f, "    %s\n", rec->message);
39     }
40 }
41
42 void rpmlogClose (void)
43 {
44     int i;
45
46     for (i = 0; i < nrecs; i++) {
47         rpmlogRec rec = recs + i;
48         if (rec->message) {
49             free((void *)rec->message);
50             rec->message = NULL;
51         }
52     }
53     free(recs);
54     recs = NULL;
55     nrecs = 0;
56 }
57
58 void rpmlogOpen (/*@unused@*/ const char *ident, /*@unused@*/ int option,
59                 /*@unused@*/ int facility)
60 {
61 }
62
63 static int rpmlogMask = RPMLOG_UPTO( RPMLOG_NOTICE );
64 static /*@unused@*/ int rpmlogFacility = RPMLOG_USER;
65
66 int rpmlogSetMask (int mask)
67 {
68     int omask = rpmlogMask;
69     if (mask)
70         rpmlogMask = mask;
71     return omask;
72 }
73
74 static /*@null@*/ rpmlogCallback _rpmlogCallback = NULL;
75
76 rpmlogCallback rpmlogSetCallback(rpmlogCallback cb)
77 {
78     rpmlogCallback ocb = _rpmlogCallback;
79     _rpmlogCallback = cb;
80     return ocb;
81 }
82
83 static char *rpmlogMsgPrefix[] = {
84     N_("fatal error: "),/*!< RPMLOG_EMERG */
85     N_("fatal error: "),/*!< RPMLOG_ALERT */
86     N_("fatal error: "),/*!< RPMLOG_CRIT */
87     N_("error: "),      /*!< RPMLOG_ERR */
88     N_("warning: "),    /*!< RPMLOG_WARNING */
89     "",                 /*!< RPMLOG_NOTICE */
90     "",                 /*!< RPMLOG_INFO */
91     "D: ",              /*!< RPMLOG_DEBUG */
92 };
93
94 static void vrpmlog (unsigned code, const char *fmt, va_list ap)
95 {
96     int pri = RPMLOG_PRI(code);
97     int mask = RPMLOG_MASK(pri);
98     /*@unused@*/ int fac = RPMLOG_FAC(code);
99     char msgbuf[BUFSIZ], *msg;
100     FILE * msgout = stderr;
101     rpmlogRec rec;
102
103     if ((mask & rpmlogMask) == 0)
104         return;
105
106     /*@-unrecog@*/ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); /*@=unrecog@*/
107     msgbuf[sizeof(msgbuf) - 1] = '\0';
108     msg = msgbuf;
109
110     /* Save copy of all messages at warning (or below == "more important"). */
111     if (pri <= RPMLOG_WARNING) {
112
113         if (recs == NULL)
114             recs = xmalloc((nrecs+2) * sizeof(*recs));
115         else
116             recs = xrealloc(recs, (nrecs+2) * sizeof(*recs));
117         recs[nrecs+1].code = 0;
118         recs[nrecs+1].message = NULL;
119         rec = recs + nrecs;
120         ++nrecs;
121
122         rec->code = code;
123         rec->message = xstrdup(msg);
124
125         if (_rpmlogCallback) {
126             _rpmlogCallback();
127             return;     /* XXX Preserve legacy rpmError behavior. */
128         }
129     }
130
131     /* rpmMessage behavior */
132
133     switch (pri) {
134     case RPMLOG_INFO:
135     case RPMLOG_NOTICE:
136         msgout = stdout;
137         break;
138
139     case RPMLOG_EMERG:
140     case RPMLOG_ALERT:
141     case RPMLOG_CRIT:
142     case RPMLOG_ERR: /* XXX Legacy rpmError behavior used stdout w/o prefix. */
143     case RPMLOG_WARNING:
144     case RPMLOG_DEBUG:
145         break;
146     }
147
148     /* Silly FORTRAN-like carriage control. */
149     if (*msg == '+')
150         msg++;
151     else if (rpmlogMsgPrefix[pri] && *rpmlogMsgPrefix[pri])
152         fputs(_(rpmlogMsgPrefix[pri]), msgout);
153
154     fputs(msg, msgout);
155     if (pri == RPMLOG_ERR) /* XXX Legacy rpmError behavior appends newline. */
156         fputs("\n", msgout);
157     fflush(msgout);
158     if (pri <= RPMLOG_CRIT)
159         exit(EXIT_FAILURE);
160 }
161
162 void rpmlog (int code, const char *fmt, ...)
163 {
164     va_list ap;
165
166     va_start(ap, fmt);
167     vrpmlog(code, fmt, ap);
168     va_end(ap);
169 }