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