ClangFormat: apply to source, most of intern
[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,
322             "Unable to save '%s': %s\n",
323             filepath,
324             errno ? strerror(errno) : "Unknown error opening file");
325     return false;
326   }
327
328   BKE_report_write_file_fp(fp, reports, header);
329
330   fclose(fp);
331
332   return true;
333 }