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