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