Merged changes in the trunk up to revision 51448.
[blender.git] / source / blender / blenkernel / intern / report.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program 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
12  * GNU 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, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation (2008).
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/blenkernel/intern/report.c
27  *  \ingroup bke
28  */
29
30
31 #include "MEM_guardedalloc.h"
32
33 #include "BLI_blenlib.h"
34 #include "BLI_dynstr.h"
35 #include "BLI_utildefines.h"
36
37 #include "BLF_translation.h"
38
39 #include "BKE_report.h"
40 #include "BKE_global.h" /* G.background only */
41
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <string.h>
45
46 static const char *report_type_str(int type)
47 {
48         switch (type) {
49                 case RPT_DEBUG:
50                         return TIP_("Debug");
51                 case RPT_INFO:
52                         return TIP_("Info");
53                 case RPT_OPERATOR:
54                         return TIP_("Operator");
55                 case RPT_WARNING:
56                         return TIP_("Warning");
57                 case RPT_ERROR:
58                         return TIP_("Error");
59                 case RPT_ERROR_INVALID_INPUT:
60                         return TIP_("Invalid Input Error");
61                 case RPT_ERROR_INVALID_CONTEXT:
62                         return TIP_("Invalid Context Error");
63                 case RPT_ERROR_OUT_OF_MEMORY:
64                         return TIP_("Out Of Memory Error");
65                 default:
66                         return TIP_("Undefined Type");
67         }
68 }
69
70 void BKE_reports_init(ReportList *reports, int flag)
71 {
72         if (!reports)
73                 return;
74
75         memset(reports, 0, sizeof(ReportList));
76
77         reports->storelevel = RPT_INFO;
78         reports->printlevel = RPT_ERROR;
79         reports->flag = flag;
80 }
81
82 void BKE_reports_clear(ReportList *reports)
83 {
84         Report *report, *report_next;
85
86         if (!reports)
87                 return;
88
89         report = reports->list.first;
90
91         while (report) {
92                 report_next = report->next;
93                 MEM_freeN((void *)report->message);
94                 MEM_freeN(report);
95                 report = report_next;
96         }
97
98         reports->list.first = reports->list.last = NULL;
99 }
100
101 void BKE_report(ReportList *reports, ReportType type, const char *_message)
102 {
103         Report *report;
104         int len;
105         const char *message = TIP_(_message);
106
107         /* in background mode always print otherwise there are cases the errors wont be displayed,
108          * but still add to the report list since this is used for python exception handling */
109         if (G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) {
110                 printf("%s: %s\n", report_type_str(type), message);
111                 fflush(stdout); /* this ensures the message is printed before a crash */
112         }
113
114         if (reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) {
115                 char *message_alloc;
116                 report = MEM_callocN(sizeof(Report), "Report");
117                 report->type = type;
118                 report->typestr = report_type_str(type);
119
120                 len = strlen(message);
121                 message_alloc = MEM_callocN(sizeof(char) * (len + 1), "ReportMessage");
122                 memcpy(message_alloc, message, sizeof(char) * (len + 1));
123                 report->message = message_alloc;
124                 report->len = len;
125                 BLI_addtail(&reports->list, report);
126         }
127 }
128
129 void BKE_reportf(ReportList *reports, ReportType type, const char *_format, ...)
130 {
131         DynStr *ds;
132         Report *report;
133         va_list args;
134         const char *format = TIP_(_format);
135
136         if (G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) {
137                 printf("%s: ", report_type_str(type));
138                 va_start(args, _format);
139                 vprintf(format, args);
140                 va_end(args);
141                 fprintf(stdout, "\n"); /* otherise each report needs to include a \n */
142                 fflush(stdout); /* this ensures the message is printed before a crash */
143         }
144
145         if (reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) {
146                 report = MEM_callocN(sizeof(Report), "Report");
147
148                 ds = BLI_dynstr_new();
149                 va_start(args, _format);
150                 BLI_dynstr_vappendf(ds, format, args);
151                 va_end(args);
152
153                 report->message = BLI_dynstr_get_cstring(ds);
154                 report->len = BLI_dynstr_get_len(ds);
155                 BLI_dynstr_free(ds);
156
157                 report->type = type;
158                 report->typestr = report_type_str(type);
159
160                 BLI_addtail(&reports->list, report);
161         }
162 }
163
164 void BKE_reports_prepend(ReportList *reports, const char *_prepend)
165 {
166         Report *report;
167         DynStr *ds;
168         const char *prepend = TIP_(_prepend);
169
170         if (!reports)
171                 return;
172
173         for (report = reports->list.first; report; report = report->next) {
174                 ds = BLI_dynstr_new();
175
176                 BLI_dynstr_append(ds, prepend);
177                 BLI_dynstr_append(ds, report->message);
178                 MEM_freeN((void *)report->message);
179
180                 report->message = BLI_dynstr_get_cstring(ds);
181                 report->len = BLI_dynstr_get_len(ds);
182
183                 BLI_dynstr_free(ds);
184         }
185 }
186
187 void BKE_reports_prependf(ReportList *reports, const char *_prepend, ...)
188 {
189         Report *report;
190         DynStr *ds;
191         va_list args;
192         const char *prepend = TIP_(_prepend);
193
194         if (!reports)
195                 return;
196
197         for (report = reports->list.first; report; report = report->next) {
198                 ds = BLI_dynstr_new();
199                 va_start(args, _prepend);
200                 BLI_dynstr_vappendf(ds, prepend, args);
201                 va_end(args);
202
203                 BLI_dynstr_append(ds, report->message);
204                 MEM_freeN((void *)report->message);
205
206                 report->message = BLI_dynstr_get_cstring(ds);
207                 report->len = BLI_dynstr_get_len(ds);
208
209                 BLI_dynstr_free(ds);
210         }
211 }
212
213 ReportType BKE_report_print_level(ReportList *reports)
214 {
215         if (!reports)
216                 return RPT_ERROR;
217
218         return reports->printlevel;
219 }
220
221 void BKE_report_print_level_set(ReportList *reports, ReportType level)
222 {
223         if (!reports)
224                 return;
225
226         reports->printlevel = level;
227 }
228
229 ReportType BKE_report_store_level(ReportList *reports)
230 {
231         if (!reports)
232                 return RPT_ERROR;
233
234         return reports->storelevel;
235 }
236
237 void BKE_report_store_level_set(ReportList *reports, ReportType level)
238 {
239         if (!reports)
240                 return;
241
242         reports->storelevel = level;
243 }
244
245 char *BKE_reports_string(ReportList *reports, ReportType level)
246 {
247         Report *report;
248         DynStr *ds;
249         char *cstring;
250
251         if (!reports || !reports->list.first)
252                 return NULL;
253
254         ds = BLI_dynstr_new();
255         for (report = reports->list.first; report; report = report->next)
256                 if (report->type >= level)
257                         BLI_dynstr_appendf(ds, "%s: %s\n", report->typestr, report->message);
258
259         if (BLI_dynstr_get_len(ds))
260                 cstring = BLI_dynstr_get_cstring(ds);
261         else
262                 cstring = NULL;
263
264         BLI_dynstr_free(ds);
265         return cstring;
266 }
267
268 void BKE_reports_print(ReportList *reports, ReportType level)
269 {
270         char *cstring = BKE_reports_string(reports, level);
271         
272         if (cstring == NULL)
273                 return;
274         
275         puts(cstring);
276         fflush(stdout);
277         MEM_freeN(cstring);
278 }
279
280 Report *BKE_reports_last_displayable(ReportList *reports)
281 {
282         Report *report;
283         
284         for (report = reports->list.last; report; report = report->prev) {
285                 if (ELEM3(report->type, RPT_ERROR, RPT_WARNING, RPT_INFO))
286                         return report;
287         }
288         
289         return NULL;
290 }
291
292 int BKE_reports_contain(ReportList *reports, ReportType level)
293 {
294         Report *report;
295         if (reports != NULL) {
296                 for (report = reports->list.first; report; report = report->next)
297                         if (report->type >= level)
298                                 return TRUE;
299         }
300         return FALSE;
301 }
302