/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * Contributor(s): Blender Foundation (2008). * * ***** END GPL LICENSE BLOCK ***** */ /** \file blender/blenkernel/intern/report.c * \ingroup bke */ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" #include "BLI_dynstr.h" #include "BLI_utildefines.h" #include "BKE_report.h" #include "BKE_global.h" /* G.background only */ #include #include #include #ifdef _WIN32 #ifndef vsnprintf #define vsnprintf _vsnprintf #endif #endif static const char *report_type_str(int type) { switch(type) { case RPT_DEBUG: return "Debug"; case RPT_INFO: return "Info"; case RPT_OPERATOR: return "Operator"; case RPT_WARNING: return "Warning"; case RPT_ERROR: return "Error"; case RPT_ERROR_INVALID_INPUT: return "Invalid Input Error"; case RPT_ERROR_INVALID_CONTEXT: return "Invalid Context Error"; case RPT_ERROR_OUT_OF_MEMORY: return "Out Of Memory Error"; default: return "Undefined Type"; } } void BKE_reports_init(ReportList *reports, int flag) { if(!reports) return; memset(reports, 0, sizeof(ReportList)); reports->storelevel= RPT_INFO; reports->printlevel= RPT_ERROR; reports->flag= flag; } void BKE_reports_clear(ReportList *reports) { Report *report, *report_next; if(!reports) return; report= reports->list.first; while (report) { report_next= report->next; MEM_freeN((void *)report->message); MEM_freeN(report); report= report_next; } reports->list.first= reports->list.last= NULL; } void BKE_report(ReportList *reports, ReportType type, const char *message) { Report *report; int len; /* in background mode always print otherwise there are cases the errors wont be displayed, * but still add to the report list since this is used for python exception handling */ if(G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) { printf("%s: %s\n", report_type_str(type), message); fflush(stdout); /* this ensures the message is printed before a crash */ } if(reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) { char *message_alloc; report= MEM_callocN(sizeof(Report), "Report"); report->type= type; report->typestr= report_type_str(type); len= strlen(message); message_alloc= MEM_callocN(sizeof(char)*(len+1), "ReportMessage"); memcpy(message_alloc, message, sizeof(char)*(len+1)); report->message= message_alloc; report->len= len; BLI_addtail(&reports->list, report); } } void BKE_reportf(ReportList *reports, ReportType type, const char *format, ...) { DynStr *ds; Report *report; va_list args; if(G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) { va_start(args, format); vprintf(format, args); va_end(args); fprintf(stdout, "\n"); /* otherise each report needs to include a \n */ fflush(stdout); /* this ensures the message is printed before a crash */ } if(reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) { report= MEM_callocN(sizeof(Report), "Report"); ds= BLI_dynstr_new(); va_start(args, format); BLI_dynstr_vappendf(ds, format, args); va_end(args); report->message= BLI_dynstr_get_cstring(ds); report->len= BLI_dynstr_get_len(ds); BLI_dynstr_free(ds); report->type= type; report->typestr= report_type_str(type); BLI_addtail(&reports->list, report); } } void BKE_reports_prepend(ReportList *reports, const char *prepend) { Report *report; DynStr *ds; if(!reports) return; for(report=reports->list.first; report; report=report->next) { ds= BLI_dynstr_new(); BLI_dynstr_append(ds, prepend); BLI_dynstr_append(ds, report->message); MEM_freeN((void *)report->message); report->message= BLI_dynstr_get_cstring(ds); report->len= BLI_dynstr_get_len(ds); BLI_dynstr_free(ds); } } void BKE_reports_prependf(ReportList *reports, const char *prepend, ...) { Report *report; DynStr *ds; va_list args; if(!reports) return; for(report=reports->list.first; report; report=report->next) { ds= BLI_dynstr_new(); va_start(args, prepend); BLI_dynstr_vappendf(ds, prepend, args); va_end(args); BLI_dynstr_append(ds, report->message); MEM_freeN((void *)report->message); report->message= BLI_dynstr_get_cstring(ds); report->len= BLI_dynstr_get_len(ds); BLI_dynstr_free(ds); } } ReportType BKE_report_print_level(ReportList *reports) { if(!reports) return RPT_ERROR; return reports->printlevel; } void BKE_report_print_level_set(ReportList *reports, ReportType level) { if(!reports) return; reports->printlevel= level; } ReportType BKE_report_store_level(ReportList *reports) { if(!reports) return RPT_ERROR; return reports->storelevel; } void BKE_report_store_level_set(ReportList *reports, ReportType level) { if(!reports) return; reports->storelevel= level; } char *BKE_reports_string(ReportList *reports, ReportType level) { Report *report; DynStr *ds; char *cstring; if(!reports || !reports->list.first) return NULL; ds= BLI_dynstr_new(); for(report=reports->list.first; report; report=report->next) if(report->type >= level) BLI_dynstr_appendf(ds, "%s: %s\n", report->typestr, report->message); if (BLI_dynstr_get_len(ds)) cstring= BLI_dynstr_get_cstring(ds); else cstring= NULL; BLI_dynstr_free(ds); return cstring; } void BKE_reports_print(ReportList *reports, ReportType level) { char *cstring = BKE_reports_string(reports, level); if (cstring == NULL) return; printf("%s", cstring); fflush(stdout); MEM_freeN(cstring); } Report *BKE_reports_last_displayable(ReportList *reports) { Report *report=NULL; for (report= (Report *)reports->list.last; report; report=report->prev) { if (ELEM3(report->type, RPT_ERROR, RPT_WARNING, RPT_INFO)) return report; } return NULL; }