File indexing completed on 2024-05-12 15:27:00
0001 /*************************************************************************** 0002 File : macros.h 0003 Project : LabPlot 0004 Description : Various preprocessor macros 0005 -------------------------------------------------------------------- 0006 Copyright : (C) 2008 Tilman Benkert (thzs@gmx.net) 0007 Copyright : (C) 2013-2015 Alexander Semke (alexander.semke@web.de) 0008 Copyright : (C) 2016-2020 Stefan Gerlach (stefan.gerlach@uni.kn) 0009 0010 ***************************************************************************/ 0011 0012 /*************************************************************************** 0013 * * 0014 * This program is free software; you can redistribute it and/or modify * 0015 * it under the terms of the GNU General Public License as published by * 0016 * the Free Software Foundation; either version 2 of the License, or * 0017 * (at your option) any later version. * 0018 * * 0019 * This program is distributed in the hope that it will be useful, * 0020 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0021 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0022 * GNU General Public License for more details. * 0023 * * 0024 * You should have received a copy of the GNU General Public License * 0025 * along with this program; if not, write to the Free Software * 0026 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0027 * Boston, MA 02110-1301 USA * 0028 * * 0029 ***************************************************************************/ 0030 0031 #ifndef MACROS_H 0032 #define MACROS_H 0033 0034 // SET_NUMBER_LOCALE 0035 #include <KSharedConfig> 0036 #include <KConfigGroup> 0037 0038 #include <QApplication> 0039 #include <QMetaEnum> 0040 0041 // C++ style warning (works on Windows) 0042 #include <iostream> 0043 #define WARN(x) std::cout << x << std::endl; 0044 0045 #ifndef NDEBUG 0046 #include <QDebug> 0047 #define QDEBUG(x) qDebug() << x; 0048 // C++ style debugging (works on Windows) 0049 #include <iomanip> 0050 #define DEBUG(x) std::cout << x << std::endl; 0051 #else 0052 #define QDEBUG(x) {} 0053 #define DEBUG(x) {} 0054 #endif 0055 0056 #if QT_VERSION < 0x050700 0057 template <class T> 0058 constexpr std::add_const_t<T>& qAsConst(T& t) noexcept { 0059 return t; 0060 } 0061 #endif 0062 0063 #define WAIT_CURSOR QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)) 0064 #define RESET_CURSOR QApplication::restoreOverrideCursor() 0065 0066 #define UTF8_QSTRING(str) QString::fromUtf8(str) 0067 #define STDSTRING(qstr) qstr.toUtf8().constData() 0068 0069 #define ENUM_TO_STRING(class, enum, value) \ 0070 (class::staticMetaObject.enumerator(class::staticMetaObject.indexOfEnumerator(#enum)).valueToKey(static_cast<int>(value))) 0071 #define ENUM_COUNT(class, enum) \ 0072 (class::staticMetaObject.enumerator(class::staticMetaObject.indexOfEnumerator(#enum)).keyCount()) 0073 0074 // define number locale from setting (using system locale when QLocale::AnyLanguage) 0075 #define SET_NUMBER_LOCALE \ 0076 QLocale::Language numberLocaleLanguage = static_cast<QLocale::Language>(KSharedConfig::openConfig()->group("Settings_General").readEntry( QLatin1String("DecimalSeparatorLocale"), static_cast<int>(QLocale::Language::AnyLanguage) )); \ 0077 QLocale numberLocale(numberLocaleLanguage == QLocale::AnyLanguage ? QLocale() : numberLocaleLanguage); \ 0078 if (numberLocale.language() == QLocale::Language::C) \ 0079 numberLocale.setNumberOptions(QLocale::DefaultNumberOptions); 0080 0081 //////////////////////// LineEdit Access /////////////////////////////// 0082 #define SET_INT_FROM_LE(var, le) { \ 0083 bool ok; \ 0084 SET_NUMBER_LOCALE \ 0085 const int tmp = numberLocale.toInt((le)->text(), &ok); \ 0086 if (ok) \ 0087 var = tmp; \ 0088 } 0089 0090 #define SET_DOUBLE_FROM_LE(var, le) { \ 0091 bool ok; \ 0092 SET_NUMBER_LOCALE \ 0093 const double tmp = numberLocale.toDouble((le)->text(), &ok); \ 0094 if (ok) \ 0095 var = tmp; \ 0096 } 0097 0098 //////////////////////// Accessor /////////////////////////////// 0099 0100 #define BASIC_ACCESSOR(type, var, method, Method) \ 0101 type method() const { return var; }; \ 0102 void set ## Method(const type value) { var = value; } 0103 #define CLASS_ACCESSOR(type, var, method, Method) \ 0104 type method() const { return var; }; \ 0105 void set ## Method(const type & value) { var = value; } 0106 0107 #define BASIC_D_ACCESSOR_DECL(type, method, Method) \ 0108 type method() const; \ 0109 void set ## Method(const type value); 0110 0111 #define BASIC_D_ACCESSOR_IMPL(classname, type, method, Method, var) \ 0112 void classname::set ## Method(const type value) \ 0113 { \ 0114 d->var = value; \ 0115 } \ 0116 type classname::method() const \ 0117 { \ 0118 return d->var; \ 0119 } 0120 0121 #define BASIC_D_READER_IMPL(classname, type, method, var) \ 0122 type classname::method() const \ 0123 { \ 0124 return d->var; \ 0125 } 0126 0127 #define BASIC_SHARED_D_READER_IMPL(classname, type, method, var) \ 0128 type classname::method() const \ 0129 { \ 0130 Q_D(const classname); \ 0131 return d->var; \ 0132 } 0133 0134 #define CLASS_D_ACCESSOR_DECL(type, method, Method) \ 0135 type method() const; \ 0136 void set ## Method(const type & value); 0137 0138 #define CLASS_D_ACCESSOR_IMPL(classname, type, method, Method, var) \ 0139 void classname::set ## Method(const type & value) \ 0140 { \ 0141 d->var = value; \ 0142 } \ 0143 type classname::method() const \ 0144 { \ 0145 return d->var; \ 0146 } 0147 0148 #define CLASS_D_READER_IMPL(classname, type, method, var) \ 0149 type classname::method() const \ 0150 { \ 0151 return d->var; \ 0152 } 0153 0154 #define CLASS_SHARED_D_READER_IMPL(classname, type, method, var) \ 0155 type classname::method() const \ 0156 { \ 0157 Q_D(const classname); \ 0158 return d->var; \ 0159 } 0160 0161 #define POINTER_D_ACCESSOR_DECL(type, method, Method) \ 0162 type *method() const; \ 0163 void set ## Method(type *ptr); 0164 0165 #define FLAG_D_ACCESSOR_DECL(Method) \ 0166 bool is ## Method() const; \ 0167 bool has ## Method() const; \ 0168 void set ## Method(const bool value = true); \ 0169 void enable ## Method(const bool value = true); 0170 0171 #define FLAG_D_ACCESSOR_IMPL(classname, Method, var) \ 0172 void classname::set ## Method(const bool value) \ 0173 { \ 0174 d->var = value; \ 0175 } \ 0176 void classname::enable ## Method(const bool value) \ 0177 { \ 0178 d->var = value; \ 0179 } \ 0180 bool classname::is ## Method() const \ 0181 { \ 0182 return d->var; \ 0183 } \ 0184 bool classname::has ## Method() const \ 0185 { \ 0186 return d->var; \ 0187 } 0188 0189 //////////////////////// Standard Setter ///////////////////// 0190 0191 #define STD_SETTER_CMD_IMPL(class_name, cmd_name, value_type, field_name) \ 0192 class class_name ## cmd_name ## Cmd: public StandardSetterCmd<class_name::Private, value_type> { \ 0193 public: \ 0194 class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \ 0195 : StandardSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \ 0196 }; 0197 0198 #define STD_SETTER_CMD_IMPL_F(class_name, cmd_name, value_type, field_name, finalize_method) \ 0199 class class_name ## cmd_name ## Cmd: public StandardSetterCmd<class_name::Private, value_type> { \ 0200 public: \ 0201 class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \ 0202 : StandardSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \ 0203 virtual void finalize() override { m_target->finalize_method(); } \ 0204 }; 0205 0206 // setter class with finalize() and signal emitting. 0207 #define STD_SETTER_CMD_IMPL_S(class_name, cmd_name, value_type, field_name) \ 0208 class class_name ## cmd_name ## Cmd: public StandardSetterCmd<class_name::Private, value_type> { \ 0209 public: \ 0210 class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \ 0211 : StandardSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \ 0212 virtual void finalize() override { emit m_target->q->field_name##Changed(m_target->*m_field); } \ 0213 }; 0214 0215 #define STD_SETTER_CMD_IMPL_F_S(class_name, cmd_name, value_type, field_name, finalize_method) \ 0216 class class_name ## cmd_name ## Cmd: public StandardSetterCmd<class_name::Private, value_type> { \ 0217 public: \ 0218 class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \ 0219 : StandardSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \ 0220 virtual void finalize() override { m_target->finalize_method(); emit m_target->q->field_name##Changed(m_target->*m_field); } \ 0221 }; 0222 0223 // setter class with finalize() and signal emitting for changing several properties in one single step (embedded in beginMacro/endMacro) 0224 #define STD_SETTER_CMD_IMPL_M_F_S(class_name, cmd_name, value_type, field_name, finalize_method) \ 0225 class class_name ## cmd_name ## Cmd: public StandardMacroSetterCmd<class_name::Private, value_type> { \ 0226 public: \ 0227 class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \ 0228 : StandardMacroSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \ 0229 virtual void finalize() override { m_target->finalize_method(); emit m_target->q->field_name##Changed(m_target->*m_field); } \ 0230 virtual void finalizeUndo() override { emit m_target->q->field_name##Changed(m_target->*m_field); } \ 0231 }; 0232 0233 #define STD_SETTER_CMD_IMPL_I(class_name, cmd_name, value_type, field_name, init_method) \ 0234 class class_name ## cmd_name ## Cmd: public StandardSetterCmd<class_name::Private, value_type> { \ 0235 public: \ 0236 class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \ 0237 : StandardSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \ 0238 virtual void initialize() { m_target->init_method(); } \ 0239 }; 0240 0241 #define STD_SETTER_CMD_IMPL_IF(class_name, cmd_name, value_type, field_name, init_method, finalize_method) \ 0242 class class_name ## cmd_name ## Cmd: public StandardSetterCmd<class_name::Private, value_type> { \ 0243 public: \ 0244 class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \ 0245 : StandardSetterCmd<class_name::Private, value_type>(target, &class_name::Private::field_name, newValue, description) {} \ 0246 virtual void initialize() { m_target->init_method(); } \ 0247 virtual void finalize() { m_target->finalize_method(); } \ 0248 }; 0249 0250 #define STD_SWAP_METHOD_SETTER_CMD_IMPL(class_name, cmd_name, value_type, method_name) \ 0251 class class_name ## cmd_name ## Cmd: public StandardSwapMethodSetterCmd<class_name::Private, value_type> { \ 0252 public: \ 0253 class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \ 0254 : StandardSwapMethodSetterCmd<class_name::Private, value_type>(target, &class_name::Private::method_name, newValue, description) {} \ 0255 }; 0256 0257 #define STD_SWAP_METHOD_SETTER_CMD_IMPL_F(class_name, cmd_name, value_type, method_name, finalize_method) \ 0258 class class_name ## cmd_name ## Cmd: public StandardSwapMethodSetterCmd<class_name::Private, value_type> { \ 0259 public: \ 0260 class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \ 0261 : StandardSwapMethodSetterCmd<class_name::Private, value_type>(target, &class_name::Private::method_name, newValue, description) {} \ 0262 virtual void finalize() override { m_target->finalize_method(); } \ 0263 }; 0264 0265 #define STD_SWAP_METHOD_SETTER_CMD_IMPL_I(class_name, cmd_name, value_type, method_name, init_method) \ 0266 class class_name ## cmd_name ## Cmd: public StandardSwapMethodSetterCmd<class_name::Private, value_type> { \ 0267 public: \ 0268 class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \ 0269 : StandardSwapMethodSetterCmd<class_name::Private, value_type>(target, &class_name::Private::method_name, newValue, description) {} \ 0270 virtual void initialize() { m_target->init_method(); } \ 0271 }; 0272 0273 #define STD_SWAP_METHOD_SETTER_CMD_IMPL_IF(class_name, cmd_name, value_type, method_name, init_method, finalize_method) \ 0274 class class_name ## cmd_name ## Cmd: public StandardSwapMethodSetterCmd<class_name::Private, value_type> { \ 0275 public: \ 0276 class_name ## cmd_name ## Cmd(class_name::Private *target, value_type newValue, const KLocalizedString &description) \ 0277 : StandardSwapMethodSetterCmd<class_name::Private, value_type>(target, &class_name::Private::method_name, newValue, description) {} \ 0278 virtual void initialize() { m_target->init_method(); } \ 0279 virtual void finalize() { m_target->finalize_method(); } \ 0280 }; 0281 0282 0283 //////////////////////// XML - serialization/deserialization ///// 0284 0285 //QColor 0286 #define WRITE_QCOLOR(color) \ 0287 do { \ 0288 writer->writeAttribute( "color_r", QString::number(color.red()) ); \ 0289 writer->writeAttribute( "color_g", QString::number(color.green()) ); \ 0290 writer->writeAttribute( "color_b", QString::number(color.blue()) ); \ 0291 } while (0) 0292 0293 #define READ_QCOLOR(color) \ 0294 do { \ 0295 str = attribs.value("color_r").toString(); \ 0296 if(str.isEmpty()) \ 0297 reader->raiseWarning(attributeWarning.subs("color_r").toString()); \ 0298 else \ 0299 color.setRed( str.toInt() ); \ 0300 \ 0301 str = attribs.value("color_g").toString(); \ 0302 if(str.isEmpty()) \ 0303 reader->raiseWarning(attributeWarning.subs("color_g").toString()); \ 0304 else \ 0305 color.setGreen( str.toInt() ); \ 0306 \ 0307 str = attribs.value("color_b").toString(); \ 0308 if(str.isEmpty()) \ 0309 reader->raiseWarning(attributeWarning.subs("color_b").toString()); \ 0310 else \ 0311 color.setBlue( str.toInt() ); \ 0312 } while(0) 0313 0314 //QPen 0315 #define WRITE_QPEN(pen) \ 0316 do { \ 0317 writer->writeAttribute( "style", QString::number(pen.style()) ); \ 0318 writer->writeAttribute( "color_r", QString::number(pen.color().red()) ); \ 0319 writer->writeAttribute( "color_g", QString::number(pen.color().green()) ); \ 0320 writer->writeAttribute( "color_b", QString::number(pen.color().blue()) ); \ 0321 writer->writeAttribute( "width", QString::number(pen.widthF()) ); \ 0322 } while (0) 0323 0324 #define READ_QPEN(pen) \ 0325 do { \ 0326 str = attribs.value("style").toString(); \ 0327 if(str.isEmpty()) \ 0328 reader->raiseWarning(attributeWarning.subs("style").toString()); \ 0329 else \ 0330 pen.setStyle( (Qt::PenStyle)str.toInt() ); \ 0331 \ 0332 QColor color; \ 0333 str = attribs.value("color_r").toString(); \ 0334 if(str.isEmpty()) \ 0335 reader->raiseWarning(attributeWarning.subs("color_r").toString()); \ 0336 else \ 0337 color.setRed( str.toInt() ); \ 0338 \ 0339 str = attribs.value("color_g").toString(); \ 0340 if(str.isEmpty()) \ 0341 reader->raiseWarning(attributeWarning.subs("color_g").toString()); \ 0342 else \ 0343 color.setGreen( str.toInt() ); \ 0344 \ 0345 str = attribs.value("color_b").toString(); \ 0346 if(str.isEmpty()) \ 0347 reader->raiseWarning(attributeWarning.subs("color_b").toString()); \ 0348 else \ 0349 color.setBlue( str.toInt() ); \ 0350 \ 0351 pen.setColor(color); \ 0352 \ 0353 str = attribs.value("width").toString(); \ 0354 if(str.isEmpty()) \ 0355 reader->raiseWarning(attributeWarning.subs("width").toString()); \ 0356 else \ 0357 pen.setWidthF( str.toDouble() ); \ 0358 } while(0) 0359 0360 //QFont 0361 #define WRITE_QFONT(font) \ 0362 do { \ 0363 writer->writeAttribute( "fontFamily", font.family() ); \ 0364 writer->writeAttribute( "fontSize", QString::number(font.pixelSize()) ); \ 0365 writer->writeAttribute( "fontPointSize", QString::number(font.pointSize()));\ 0366 writer->writeAttribute( "fontWeight", QString::number(font.weight()) ); \ 0367 writer->writeAttribute( "fontItalic", QString::number(font.italic()) ); \ 0368 } while(0) 0369 0370 #define READ_QFONT(font) \ 0371 do { \ 0372 str = attribs.value("fontFamily").toString(); \ 0373 if(str.isEmpty()) \ 0374 reader->raiseWarning(attributeWarning.subs("fontFamily").toString()); \ 0375 else \ 0376 font.setFamily( str ); \ 0377 \ 0378 str = attribs.value("fontSize").toString(); \ 0379 if(str.isEmpty()) \ 0380 reader->raiseWarning(attributeWarning.subs("fontSize").toString()); \ 0381 else { \ 0382 int size = str.toInt(); \ 0383 if (size != -1) \ 0384 font.setPixelSize(size); \ 0385 } \ 0386 \ 0387 str = attribs.value("fontPointSize").toString(); \ 0388 if(str.isEmpty()) \ 0389 reader->raiseWarning(attributeWarning.subs("fontPointSize").toString()); \ 0390 else { \ 0391 int size = str.toInt(); \ 0392 if (size != -1) \ 0393 font.setPointSize(size); \ 0394 } \ 0395 \ 0396 str = attribs.value("fontWeight").toString(); \ 0397 if(str.isEmpty()) \ 0398 reader->raiseWarning(attributeWarning.subs("fontWeight").toString()); \ 0399 else \ 0400 font.setWeight( str.toInt() ); \ 0401 \ 0402 str = attribs.value("fontItalic").toString(); \ 0403 if(str.isEmpty()) \ 0404 reader->raiseWarning(attributeWarning.subs("fontItalic").toString()); \ 0405 else \ 0406 font.setItalic( str.toInt() ); \ 0407 } while(0) 0408 0409 //QBrush 0410 #define WRITE_QBRUSH(brush) \ 0411 do { \ 0412 writer->writeAttribute("brush_style", QString::number(brush.style()) ); \ 0413 writer->writeAttribute("brush_color_r", QString::number(brush.color().red())); \ 0414 writer->writeAttribute("brush_color_g", QString::number(brush.color().green()));\ 0415 writer->writeAttribute("brush_color_b", QString::number(brush.color().blue())); \ 0416 } while(0) 0417 0418 #define READ_QBRUSH(brush) \ 0419 do { \ 0420 str = attribs.value("brush_style").toString(); \ 0421 if(str.isEmpty()) \ 0422 reader->raiseWarning(attributeWarning.subs("brush_style").toString()); \ 0423 else \ 0424 brush.setStyle( (Qt::BrushStyle)str.toInt() ); \ 0425 \ 0426 QColor color; \ 0427 str = attribs.value("brush_color_r").toString(); \ 0428 if(str.isEmpty()) \ 0429 reader->raiseWarning(attributeWarning.subs("brush_color_r").toString()); \ 0430 else \ 0431 color.setRed( str.toInt() ); \ 0432 \ 0433 str = attribs.value("brush_color_g").toString(); \ 0434 if(str.isEmpty()) \ 0435 reader->raiseWarning(attributeWarning.subs("brush_color_g").toString()); \ 0436 else \ 0437 color.setGreen( str.toInt() ); \ 0438 \ 0439 str = attribs.value("brush_color_b").toString(); \ 0440 if(str.isEmpty()) \ 0441 reader->raiseWarning(attributeWarning.subs("brush_color_b").toString()); \ 0442 else \ 0443 color.setBlue( str.toInt() ); \ 0444 \ 0445 brush.setColor(color); \ 0446 } while(0) 0447 0448 0449 0450 //Column 0451 #define WRITE_COLUMN(column, columnName) \ 0452 do { \ 0453 if (column){ \ 0454 writer->writeAttribute( #columnName, column->path() ); \ 0455 } else { \ 0456 writer->writeAttribute( #columnName, QString() ); \ 0457 } \ 0458 } while(0) 0459 0460 //column names can be empty in case no columns were used before save 0461 //the actual pointers to the x- and y-columns are restored in Project::load() 0462 #define READ_COLUMN(columnName) \ 0463 do { \ 0464 str = attribs.value(#columnName).toString(); \ 0465 d->columnName ##Path = str; \ 0466 } while(0) 0467 0468 #define READ_INT_VALUE(name, var, type) \ 0469 str = attribs.value(name).toString(); \ 0470 if (str.isEmpty()) \ 0471 reader->raiseWarning(attributeWarning.subs(name).toString()); \ 0472 else \ 0473 d->var = (type)str.toInt(); 0474 0475 #define READ_DOUBLE_VALUE(name, var) \ 0476 str = attribs.value(name).toString(); \ 0477 if (str.isEmpty()) \ 0478 reader->raiseWarning(attributeWarning.subs(name).toString()); \ 0479 else \ 0480 d->var = str.toDouble(); 0481 0482 #define READ_STRING_VALUE(name, var) \ 0483 str = attribs.value(name).toString(); \ 0484 if (str.isEmpty()) \ 0485 reader->raiseWarning(attributeWarning.subs(name).toString()); \ 0486 else \ 0487 d->var = str; 0488 0489 //used in Project::load() 0490 #define RESTORE_COLUMN_POINTER(obj, col, Col) \ 0491 do { \ 0492 if (!obj->col ##Path().isEmpty()) { \ 0493 for (Column* column : columns) { \ 0494 if (!column) continue; \ 0495 if (column->path() == obj->col ##Path()) { \ 0496 obj->set## Col(column); \ 0497 break; \ 0498 } \ 0499 } \ 0500 } \ 0501 } while(0) 0502 0503 0504 0505 #define WRITE_PATH(obj, name) \ 0506 do { \ 0507 if (obj){ \ 0508 writer->writeAttribute( #name, obj->path() ); \ 0509 } else { \ 0510 writer->writeAttribute( #name, QString() ); \ 0511 } \ 0512 } while(0) 0513 0514 #define READ_PATH(name) \ 0515 do { \ 0516 str = attribs.value(#name).toString(); \ 0517 d->name ##Path = str; \ 0518 } while(0) 0519 0520 #define RESTORE_POINTER(obj, name, Name, Type, list) \ 0521 do { \ 0522 if (!obj->name ##Path().isEmpty()) { \ 0523 for (AbstractAspect* aspect : list) { \ 0524 if (aspect->path() == obj->name ##Path()) { \ 0525 auto a = dynamic_cast<Type*>(aspect); \ 0526 if (!a) continue; \ 0527 obj->set## Name(a); \ 0528 break; \ 0529 } \ 0530 } \ 0531 } \ 0532 } while(0) 0533 0534 #endif // MACROS_H