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