1 #pragma once
2
3 #include <string>
4 #include <list>
5 #include <iostream>
6 #include <boost/format.hpp>
7 #include <boost/algorithm/string.hpp>
8 #include <utility>
9 #include <libintl.h>
10 #undef snprintf
11 #include <locale.h>
12 #include "AST.h"
13 #include <set>
_(const char * msgid)14 inline char * _( const char * msgid ) { return gettext( msgid ); }
_(const char * msgid,const char * msgctxt)15 inline const char * _( const char * msgid, const char *msgctxt) {
16 /* The separator between msgctxt and msgid in a .mo file. */
17 const char* GETTEXT_CONTEXT_GLUE = "\004";
18
19 std::string str = msgctxt;
20 str += GETTEXT_CONTEXT_GLUE;
21 str += msgid;
22 auto translation = dcgettext(NULL,str.c_str(), LC_MESSAGES);
23 if(translation==str){
24 return gettext(msgid);
25 }else{
26 return translation;
27 }
28 }
29
30 enum class message_group {
31 Error,Warning,UI_Warning,Font_Warning,Export_Warning,Export_Error,UI_Error,Parser_Error,Trace,Deprecated,None,Echo
32 };
33
34
35 std::string getGroupName(const enum message_group &group);
36 std::string getGroupColor(const enum message_group &group);
37 bool getGroupTextPlain(const enum message_group &group);
38
39 struct Message {
40 std::string msg;
41 Location loc;
42 std::string docPath;
43 enum message_group group;
44
MessageMessage45 Message()
46 : msg(""), loc(Location::NONE), docPath(""), group(message_group::None)
47 { }
48
MessageMessage49 Message(const std::string& msg, const Location& loc, const std::string& docPath, const message_group& group)
50 : msg(msg), loc(loc), docPath(docPath), group(group)
51 { }
52
strMessage53 std::string str() const {
54 const auto g = group == message_group::None ? "" : getGroupName(group) + ": ";
55 const auto l = loc.isNone() ? "" : " " + loc.toRelativeString(docPath);
56 return g + msg + l;
57 }
58 };
59
60 typedef void (OutputHandlerFunc)(const Message &msg,void *userdata);
61 typedef void (OutputHandlerFunc2)(const Message &msg, void *userdata);
62
63 extern OutputHandlerFunc *outputhandler;
64 extern void *outputhandler_data;
65
66 namespace OpenSCAD {
67 extern std::string debug;
68 extern bool quiet;
69 extern bool hardwarnings;
70 extern bool parameterCheck;
71 extern bool rangeCheck;
72 }
73
74 void set_output_handler(OutputHandlerFunc *newhandler, OutputHandlerFunc2 *newhandler2, void *userdata);
75 void no_exceptions_for_warnings();
76 bool would_have_thrown();
77
78 extern std::list<std::string> print_messages_stack;
79 void print_messages_push();
80 void print_messages_pop();
81 void resetSuppressedMessages();
82
83
84 /* PRINT statements come out in same window as ECHO.
85 usage: PRINTB("Var1: %s Var2: %i", var1 % var2 ); */
86 void PRINT(const Message &msgObj);
87
88 void PRINT_NOCACHE(const Message &msgObj);
89 #define PRINTB_NOCACHE(_fmt, _arg) do { } while (0)
90 // #define PRINTB_NOCACHE(_fmt, _arg) do { PRINT_NOCACHE(str(boost::format(_fmt) % _arg)); } while (0)
91
92 void PRINT_CONTEXT(const class Context *ctx, const class Module *mod, const class ModuleInstantiation *inst);
93
94 /*PRINTD: debugging/verbose output. Usage in code:
95 CGAL_Point_3 p0(0,0,0),p1(1,0,0),p2(0,1,0);
96 PRINTD(" Created 3 points: ");
97 PRINTDB("point0, point1, point2: %s %s %s", p0 % p1 % p2 );
98 Usage on command line:
99 openscad x.scad --debug=all # prints all debug messages
100 openscad x.scad --debug=<srcfile> # prints only debug msgs from srcfile.*.cc
101 (example: openscad --debug=export # prints only debug msgs from export.cc )
102
103 For a debug with heavy computation cost, you can guard so that the computation
104 only occurs when debugging is turned on. For example:
105 if (OpenSCAD::debug!="") PRINTDB("PolySet dump: %s",ps->dump());
106 */
107
108 void PRINTDEBUG(const std::string &filename,const std::string &msg);
109 #define PRINTD(_arg) do { PRINTDEBUG(std::string(__FILE__),_arg); } while (0)
110 #define PRINTDB(_fmt, _arg) do { try { PRINTDEBUG(std::string(__FILE__),str(boost::format(_fmt) % _arg)); } catch(const boost::io::format_error &e) { PRINTDEBUG(std::string(__FILE__),"bad PRINTDB usage"); } } while (0)
111
112 std::string two_digit_exp_format( std::string doublestr );
113 std::string two_digit_exp_format( double x );
114 const std::string& quoted_string(const std::string& str);
115
116 // extremely simple logging, eventually replace with something like boost.log
117 // usage: logstream out(5); openscad_loglevel=6; out << "hi";
118 static int openscad_loglevel = 0;
119 class logstream
120 {
121 public:
122 std::ostream *out;
123 int loglevel;
124 logstream( int level = 0 ) {
125 loglevel = level;
126 out = &(std::cout);
127 }
128 template <typename T> logstream & operator<<( T const &t ) {
129 if (out && loglevel <= openscad_loglevel) {
130 (*out) << t ;
131 out->flush();
132 }
133 return *this;
134 }
135 };
136
137 #define STR(s) static_cast<std::ostringstream&&>(std::ostringstream()<< s).str()
138
139 template <typename... Ts>
140 class MessageClass
141 {
142 private:
143 std::string fmt;
144 std::tuple<Ts...> args;
145 template <std::size_t... Is>
format(const std::index_sequence<Is...>)146 std::string format(const std::index_sequence<Is...>) const
147 {
148
149 std::string s;
150 for(int i=0; fmt[i]!='\0'; i++)
151 {
152 if(fmt[i] == '%' && !('0' <= fmt[i+1] && fmt[i+1] <= '9'))
153 {
154 s.append("%%");
155 }
156 else
157 {
158 s.push_back(fmt[i]);
159 }
160 }
161
162 boost::format f(s);
163 f.exceptions(boost::io::bad_format_string_bit);
164 static_cast<void>(std::initializer_list<char> {(static_cast<void>(f % std::get<Is>(args)), char{}) ...});
165 return boost::str(f);
166 }
167
168 public:
169 template <typename... Args>
MessageClass(std::string && fmt,Args &&...args)170 MessageClass(std::string&& fmt, Args&&... args) : fmt(std::forward<std::string>(fmt)), args(std::forward<Args>(args)...)
171 {
172 }
173
format()174 std::string format() const
175 {
176 return format(std::index_sequence_for<Ts...>{});
177 }
178 };
179
180 extern std::set<std::string> printedDeprecations;
181
182 template <typename F, typename... Args>
LOG(const message_group & msg_grp,const Location & loc,const std::string & docPath,F && f,Args &&...args)183 void LOG(const message_group &msg_grp,const Location &loc,const std::string &docPath,F&& f, Args&&... args)
184 {
185 const auto msg = MessageClass<Args...>(std::forward<F>(f), std::forward<Args>(args)...);
186 const auto formatted = msg.format();
187
188 //check for deprecations
189 if (msg_grp == message_group::Deprecated && printedDeprecations.find(formatted+loc.toRelativeString(docPath)) != printedDeprecations.end()) return;
190 if(msg_grp == message_group::Deprecated) printedDeprecations.insert(formatted+loc.toRelativeString(docPath));
191
192 Message msgObj = {formatted,loc,docPath,msg_grp};
193
194 PRINT(msgObj);
195 }
196