Blender V4.3
report.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cerrno>
10#include <cstdarg>
11#include <cstdio>
12#include <cstring>
13#include <mutex>
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_blenlib.h"
18#include "BLI_dynstr.h"
19#include "BLI_listbase.h"
20#include "BLI_string_utils.hh"
21#include "BLI_utildefines.h"
22
23#include "BLT_translation.hh"
24
25#include "BKE_global.hh" /* G.background only */
26#include "BKE_report.hh"
27
29{
30 switch (type) {
31 case RPT_DEBUG:
32 return RPT_("Debug");
33 case RPT_INFO:
34 return RPT_("Info");
35 case RPT_OPERATOR:
36 return RPT_("Operator");
37 case RPT_PROPERTY:
38 return RPT_("Property");
39 case RPT_WARNING:
40 return RPT_("Warning");
41 case RPT_ERROR:
42 return RPT_("Error");
44 return RPT_("Invalid Input Error");
46 return RPT_("Invalid Context Error");
48 return RPT_("Out Of Memory Error");
49 default:
50 return RPT_("Undefined Type");
51 }
52}
53
54void BKE_reports_init(ReportList *reports, int flag)
55{
56 if (!reports) {
57 return;
58 }
59
60 memset(reports, 0, sizeof(ReportList));
61
62 reports->storelevel = RPT_INFO;
63 reports->printlevel = RPT_ERROR;
64 reports->flag = flag;
65
66 reports->lock = MEM_new<std::mutex>(__func__);
67}
68
70{
71 if (!reports) {
72 return;
73 }
74
75 BKE_reports_clear(reports);
76
77 MEM_delete(reports->lock);
78 reports->lock = nullptr;
79}
80
82{
83 Report *report, *report_next;
84
85 if (!reports) {
86 return;
87 }
88
89 std::scoped_lock lock(*reports->lock);
90
91 report = static_cast<Report *>(reports->list.first);
92
93 while (report) {
94 report_next = report->next;
95 MEM_freeN((void *)report->message);
96 MEM_freeN(report);
97 report = report_next;
98 }
99
100 BLI_listbase_clear(&reports->list);
101}
102
104{
105 reports->lock->lock();
106}
107
109{
110 reports->lock->unlock();
111}
112
113void BKE_reports_move_to_reports(ReportList *reports_dst, ReportList *reports_src)
114{
115 BLI_assert(reports_dst);
116 if (!reports_src) {
117 return;
118 }
119
120 std::scoped_lock lock(*reports_src->lock, *reports_dst->lock);
121
122 BLI_movelisttolist(&reports_dst->list, &reports_src->list);
123}
124
125void BKE_report(ReportList *reports, eReportType type, const char *_message)
126{
127 Report *report;
128 int len;
129 const char *message = RPT_(_message);
130
131 if (BKE_reports_print_test(reports, type)) {
132 printf("%s: %s\n", BKE_report_type_str(type), message);
133 fflush(stdout); /* this ensures the message is printed before a crash */
134 }
135
136 if (reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) {
137 std::scoped_lock lock(*reports->lock);
138
139 char *message_alloc;
140 report = static_cast<Report *>(MEM_callocN(sizeof(Report), "Report"));
141 report->type = type;
142 report->typestr = BKE_report_type_str(type);
143
144 len = strlen(message);
145 message_alloc = static_cast<char *>(MEM_mallocN(sizeof(char) * (len + 1), "ReportMessage"));
146 memcpy(message_alloc, message, sizeof(char) * (len + 1));
147 report->message = message_alloc;
148 report->len = len;
149 BLI_addtail(&reports->list, report);
150 }
151}
152
153void BKE_reportf(ReportList *reports, eReportType type, const char *_format, ...)
154{
155 Report *report;
156 va_list args;
157 const char *format = RPT_(_format);
158
159 if (BKE_reports_print_test(reports, type)) {
160 printf("%s: ", BKE_report_type_str(type));
161 va_start(args, _format);
162 vprintf(format, args);
163 va_end(args);
164 fprintf(stdout, "\n"); /* otherwise each report needs to include a \n */
165 fflush(stdout); /* this ensures the message is printed before a crash */
166 }
167
168 if (reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) {
169 std::scoped_lock lock(*reports->lock);
170
171 report = static_cast<Report *>(MEM_callocN(sizeof(Report), "Report"));
172
173 va_start(args, _format);
174 report->message = BLI_vsprintfN(format, args);
175 va_end(args);
176
177 report->len = strlen(report->message);
178 report->type = type;
179 report->typestr = BKE_report_type_str(type);
180
181 BLI_addtail(&reports->list, report);
182 }
183}
184
188static void reports_prepend_impl(ReportList *reports, const char *prepend)
189{
190 /* Caller must ensure. */
191 BLI_assert(reports && reports->list.first);
192
193 std::scoped_lock lock(*reports->lock);
194
195 const size_t prefix_len = strlen(prepend);
196 LISTBASE_FOREACH (Report *, report, &reports->list) {
197 char *message = BLI_string_joinN(prepend, report->message);
198 MEM_freeN((void *)report->message);
199 report->message = message;
200 report->len += prefix_len;
201 BLI_assert(report->len == strlen(message));
202 }
203}
204
205void BKE_reports_prepend(ReportList *reports, const char *prepend)
206{
207 if (!reports || !reports->list.first) {
208 return;
209 }
210 reports_prepend_impl(reports, RPT_(prepend));
211}
212
213void BKE_reports_prependf(ReportList *reports, const char *prepend_format, ...)
214{
215 if (!reports || !reports->list.first) {
216 return;
217 }
218 va_list args;
219 va_start(args, prepend_format);
220 char *prepend = BLI_vsprintfN(RPT_(prepend_format), args);
221 va_end(args);
222
223 reports_prepend_impl(reports, prepend);
224
225 MEM_freeN(prepend);
226}
227
229{
230 if (!reports) {
231 return RPT_ERROR;
232 }
233
234 return eReportType(reports->printlevel);
235}
236
238{
239 if (!reports) {
240 return;
241 }
242
243 std::scoped_lock lock(*reports->lock);
244
245 reports->printlevel = level;
246}
247
249{
250 if (!reports) {
251 return RPT_ERROR;
252 }
253
254 return eReportType(reports->storelevel);
255}
256
258{
259 if (!reports) {
260 return;
261 }
262
263 std::scoped_lock lock(*reports->lock);
264
265 reports->storelevel = level;
266}
267
269{
270 DynStr *ds;
271 char *cstring;
272
273 if (!reports || !reports->list.first) {
274 return nullptr;
275 }
276
277 std::scoped_lock lock(*reports->lock);
278
279 ds = BLI_dynstr_new();
280 LISTBASE_FOREACH (Report *, report, &reports->list) {
281 if (report->type >= level) {
282 BLI_dynstr_appendf(ds, "%s: %s\n", report->typestr, report->message);
283 }
284 }
285
286 if (BLI_dynstr_get_len(ds)) {
287 cstring = BLI_dynstr_get_cstring(ds);
288 }
289 else {
290 cstring = nullptr;
291 }
292
293 BLI_dynstr_free(ds);
294 return cstring;
295}
296
298{
299 if (reports == nullptr) {
300 return true;
301 }
302 if (reports->flag & RPT_PRINT_HANDLED_BY_OWNER) {
303 return false;
304 }
305 /* In background mode always print otherwise there are cases the errors won't be displayed,
306 * but still add to the report list since this is used for Python exception handling. */
307 if (G.background) {
308 return true;
309 }
310
311 /* Common case. */
312 return (reports->flag & RPT_PRINT) && (type >= reports->printlevel);
313}
314
316{
317 char *cstring = BKE_reports_string(reports, level);
318
319 if (cstring == nullptr) {
320 return;
321 }
322
323 /* A trailing newline is already part of `cstring`. */
324 fputs(cstring, stdout);
325 fflush(stdout);
326 MEM_freeN(cstring);
327}
328
330{
331 std::scoped_lock lock(*reports->lock);
332
333 LISTBASE_FOREACH_BACKWARD (Report *, report, &reports->list) {
334 if (ELEM(report->type, RPT_ERROR, RPT_WARNING, RPT_INFO)) {
335 return report;
336 }
337 }
338
339 return nullptr;
340}
341
343{
344 if (reports != nullptr) {
345 std::scoped_lock lock(*reports->lock);
346
347 LISTBASE_FOREACH (Report *, report, &reports->list) {
348 if (report->type >= level) {
349 return true;
350 }
351 }
352 }
353 return false;
354}
355
356bool BKE_report_write_file_fp(FILE *fp, ReportList *reports, const char *header)
357{
358 if (header) {
359 fputs(header, fp);
360 }
361
362 std::scoped_lock lock(*reports->lock);
363
364 LISTBASE_FOREACH (Report *, report, &reports->list) {
365 fprintf((FILE *)fp, "%s # %s\n", report->message, report->typestr);
366 }
367
368 return true;
369}
370
371bool BKE_report_write_file(const char *filepath, ReportList *reports, const char *header)
372{
373 FILE *fp;
374
375 errno = 0;
376 fp = BLI_fopen(filepath, "wb");
377 if (fp == nullptr) {
378 fprintf(stderr,
379 "Unable to save '%s': %s\n",
380 filepath,
381 errno ? strerror(errno) : "Unknown error opening file");
382 return false;
383 }
384
385 BKE_report_write_file_fp(fp, reports, header);
386
387 fclose(fp);
388
389 return true;
390}
#define BLI_assert(a)
Definition BLI_assert.h:50
A dynamically sized string ADT.
char * BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition BLI_dynstr.c:149
int BLI_dynstr_get_len(const DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition BLI_dynstr.c:128
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.c:37
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition BLI_dynstr.c:174
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
char char * BLI_vsprintfN(const char *__restrict format, va_list args) ATTR_NONNULL(1
#define BLI_string_joinN(...)
#define ELEM(...)
#define RPT_(msgid)
@ RPT_PRINT_HANDLED_BY_OWNER
@ RPT_ERROR_OUT_OF_MEMORY
@ RPT_ERROR_INVALID_INPUT
@ RPT_ERROR_INVALID_CONTEXT
Read Guarded memory(de)allocation.
volatile int lock
#define printf
int len
format
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define G(x, y, z)
bool BKE_reports_contain(ReportList *reports, eReportType level)
Definition report.cc:342
void BKE_reports_unlock(ReportList *reports)
Definition report.cc:108
bool BKE_reports_print_test(const ReportList *reports, eReportType type)
Definition report.cc:297
eReportType BKE_report_store_level(ReportList *reports)
Definition report.cc:248
bool BKE_report_write_file(const char *filepath, ReportList *reports, const char *header)
Definition report.cc:371
char * BKE_reports_string(ReportList *reports, eReportType level)
Definition report.cc:268
static void reports_prepend_impl(ReportList *reports, const char *prepend)
Definition report.cc:188
bool BKE_report_write_file_fp(FILE *fp, ReportList *reports, const char *header)
Definition report.cc:356
Report * BKE_reports_last_displayable(ReportList *reports)
Definition report.cc:329
void BKE_reports_free(ReportList *reports)
Definition report.cc:69
const char * BKE_report_type_str(eReportType type)
Definition report.cc:28
void BKE_reports_prepend(ReportList *reports, const char *prepend)
Definition report.cc:205
void BKE_report_print_level_set(ReportList *reports, eReportType level)
Definition report.cc:237
void BKE_report_store_level_set(ReportList *reports, eReportType level)
Definition report.cc:257
eReportType BKE_report_print_level(ReportList *reports)
Definition report.cc:228
void BKE_reports_clear(ReportList *reports)
Definition report.cc:81
void BKE_reportf(ReportList *reports, eReportType type, const char *_format,...)
Definition report.cc:153
void BKE_report(ReportList *reports, eReportType type, const char *_message)
Definition report.cc:125
void BKE_reports_prependf(ReportList *reports, const char *prepend_format,...)
Definition report.cc:213
void BKE_reports_lock(ReportList *reports)
Definition report.cc:103
void BKE_reports_init(ReportList *reports, int flag)
Definition report.cc:54
void BKE_reports_print(ReportList *reports, eReportType level)
Definition report.cc:315
void BKE_reports_move_to_reports(ReportList *reports_dst, ReportList *reports_src)
Definition report.cc:113
void * first
std_mutex_type * lock
struct Report * next
const char * typestr
const char * message
uint8_t flag
Definition wm_window.cc:138