1 /*
2 * Carla common utils
3 * Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
16 */
17
18 #ifndef CARLA_UTILS_HPP_INCLUDED
19 #define CARLA_UTILS_HPP_INCLUDED
20
21 #include "CarlaDefines.h"
22
23 #include <cassert>
24 #include <cstdarg>
25 #include <cstdio>
26 #include <cstdlib>
27 #include <cstring>
28
29 #ifdef CARLA_PROPER_CPP11_SUPPORT
30 # include <cxxabi.h>
31 # include <cstdint>
32 #else
33 # include <stdint.h>
34 #endif
35
36 #ifdef CARLA_OS_WIN
37 # define WIN32_LEAN_AND_MEAN 1
38 # include <winsock2.h>
39 # include <windows.h>
40 #else
41 # include <unistd.h>
42 #endif
43
44 // --------------------------------------------------------------------------------------------------------------------
45 // misc functions
46
47 /*
48 * Return "true" or "false" according to yesNo.
49 */
50 static inline
bool2str(const bool yesNo)51 const char* bool2str(const bool yesNo) noexcept
52 {
53 return yesNo ? "true" : "false";
54 }
55
56 /*
57 * Set a string as empty/null.
58 */
59 static inline
nullStrBuf(char * const strBuf)60 void nullStrBuf(char* const strBuf) noexcept
61 {
62 strBuf[0] = '\0';
63 }
64
65 /*
66 * Dummy function.
67 */
68 static inline
pass()69 void pass() noexcept {}
70
71 // --------------------------------------------------------------------------------------------------------------------
72 // string print functions
73
74 /*
75 * Internal noexcept-safe fopen function.
76 */
77 static inline
__carla_fopen(const char * const filename,FILE * const fallback)78 FILE* __carla_fopen(const char* const filename, FILE* const fallback) noexcept
79 {
80 #ifdef CARLA_OS_LINUX
81 if (std::getenv("CARLA_CAPTURE_CONSOLE_OUTPUT") == nullptr)
82 return fallback;
83
84 FILE* ret = nullptr;
85
86 try {
87 ret = std::fopen(filename, "a+");
88 } CARLA_CATCH_UNWIND catch (...) {}
89
90 if (ret == nullptr)
91 ret = fallback;
92
93 return ret;
94 #else
95 return fallback;
96 // unused
97 (void)filename;
98 #endif
99 }
100
101 /*
102 * Print a string to stdout with newline (gray color).
103 * Does nothing if DEBUG is not defined.
104 */
105 #ifndef DEBUG
106 # define carla_debug(...)
107 #else
108 static inline
carla_debug(const char * const fmt,...)109 void carla_debug(const char* const fmt, ...) noexcept
110 {
111 static FILE* const output = __carla_fopen("/tmp/carla.debug.log", stdout);
112
113 try {
114 ::va_list args;
115 ::va_start(args, fmt);
116
117 if (output == stdout)
118 {
119 #ifdef CARLA_OS_MAC
120 std::fprintf(output, "\x1b[37;1m");
121 #else
122 std::fprintf(output, "\x1b[30;1m");
123 #endif
124 std::vfprintf(output, fmt, args);
125 std::fprintf(output, "\x1b[0m\n");
126 }
127 else
128 {
129 std::vfprintf(output, fmt, args);
130 std::fprintf(output, "\n");
131 }
132
133 std::fflush(output);
134 ::va_end(args);
135 } CARLA_CATCH_UNWIND catch (...) {}
136 }
137 #endif
138
139 /*
140 * Print a string to stdout with newline.
141 */
142 static inline
carla_stdout(const char * const fmt,...)143 void carla_stdout(const char* const fmt, ...) noexcept
144 {
145 static FILE* const output = __carla_fopen("/tmp/carla.stdout.log", stdout);
146
147 try {
148 ::va_list args;
149 ::va_start(args, fmt);
150 std::vfprintf(output, fmt, args);
151 std::fprintf(output, "\n");
152 #ifndef DEBUG
153 if (output != stdout)
154 #endif
155 std::fflush(output);
156 ::va_end(args);
157 } CARLA_CATCH_UNWIND catch (...) {}
158 }
159
160 /*
161 * Print a string to stderr with newline.
162 */
163 static inline
carla_stderr(const char * const fmt,...)164 void carla_stderr(const char* const fmt, ...) noexcept
165 {
166 static FILE* const output = __carla_fopen("/tmp/carla.stderr.log", stderr);
167
168 try {
169 ::va_list args;
170 ::va_start(args, fmt);
171 std::vfprintf(output, fmt, args);
172 std::fprintf(output, "\n");
173 #ifndef DEBUG
174 if (output != stderr)
175 #endif
176 std::fflush(output);
177 ::va_end(args);
178 } CARLA_CATCH_UNWIND catch (...) {}
179 }
180
181 /*
182 * Print a string to stderr with newline (red color).
183 */
184 static inline
carla_stderr2(const char * const fmt,...)185 void carla_stderr2(const char* const fmt, ...) noexcept
186 {
187 static FILE* const output = __carla_fopen("/tmp/carla.stderr2.log", stderr);
188
189 try {
190 ::va_list args;
191 ::va_start(args, fmt);
192
193 if (output == stderr)
194 {
195 std::fprintf(output, "\x1b[31m");
196 std::vfprintf(output, fmt, args);
197 std::fprintf(output, "\x1b[0m\n");
198 }
199 else
200 {
201 std::vfprintf(output, fmt, args);
202 std::fprintf(output, "\n");
203 }
204
205 std::fflush(output);
206 ::va_end(args);
207 } CARLA_CATCH_UNWIND catch (...) {}
208 }
209
210 // --------------------------------------------------------------------------------------------------------------------
211 // carla_safe_assert*
212
213 /*
214 * Print a safe assertion error message.
215 */
216 static inline
carla_safe_assert(const char * const assertion,const char * const file,const int line)217 void carla_safe_assert(const char* const assertion, const char* const file, const int line) noexcept
218 {
219 carla_stderr2("Carla assertion failure: \"%s\" in file %s, line %i", assertion, file, line);
220 }
221
222 /*
223 * Print a safe assertion error message, with 1 extra signed integer value.
224 */
225 static inline
carla_safe_assert_int(const char * const assertion,const char * const file,const int line,const int value)226 void carla_safe_assert_int(const char* const assertion, const char* const file,
227 const int line, const int value) noexcept
228 {
229 carla_stderr2("Carla assertion failure: \"%s\" in file %s, line %i, value %i", assertion, file, line, value);
230 }
231
232 /*
233 * Print a safe assertion error message, with 1 extra unsigned integer value.
234 */
235 static inline
carla_safe_assert_uint(const char * const assertion,const char * const file,const int line,const uint value)236 void carla_safe_assert_uint(const char* const assertion, const char* const file,
237 const int line, const uint value) noexcept
238 {
239 carla_stderr2("Carla assertion failure: \"%s\" in file %s, line %i, value %u", assertion, file, line, value);
240 }
241
242 /*
243 * Print a safe assertion error message, with 2 extra signed integer values.
244 */
245 static inline
carla_safe_assert_int2(const char * const assertion,const char * const file,const int line,const int v1,const int v2)246 void carla_safe_assert_int2(const char* const assertion, const char* const file,
247 const int line, const int v1, const int v2) noexcept
248 {
249 carla_stderr2("Carla assertion failure: \"%s\" in file %s, line %i, v1 %i, v2 %i", assertion, file, line, v1, v2);
250 }
251
252 /*
253 * Print a safe assertion error message, with 2 extra unsigned integer values.
254 */
255 static inline
carla_safe_assert_uint2(const char * const assertion,const char * const file,const int line,const uint v1,const uint v2)256 void carla_safe_assert_uint2(const char* const assertion, const char* const file,
257 const int line, const uint v1, const uint v2) noexcept
258 {
259 carla_stderr2("Carla assertion failure: \"%s\" in file %s, line %i, v1 %u, v2 %u", assertion, file, line, v1, v2);
260 }
261
262 /*
263 * Print a safe assertion error message, with a custom error message.
264 */
265 static inline
carla_custom_safe_assert(const char * const message,const char * const assertion,const char * const file,const int line)266 void carla_custom_safe_assert(const char* const message,
267 const char* const assertion, const char* const file, const int line) noexcept
268 {
269 carla_stderr2("Carla assertion failure: %s, condition \"%s\" in file %s, line %i", message, assertion, file, line);
270 }
271
272 // --------------------------------------------------------------------------------------------------------------------
273 // carla_safe_exception*
274
275 /*
276 * Print a safe exception error message.
277 */
278 static inline
carla_safe_exception(const char * const exception,const char * const file,const int line)279 void carla_safe_exception(const char* const exception, const char* const file, const int line) noexcept
280 {
281 carla_stderr2("Carla exception caught: \"%s\" in file %s, line %i", exception, file, line);
282 }
283
284 // --------------------------------------------------------------------------------------------------------------------
285 // carla_*sleep
286
287 /*
288 * Sleep for 'secs' seconds.
289 */
290 static inline
carla_sleep(const uint secs)291 void carla_sleep(const uint secs) noexcept
292 {
293 CARLA_SAFE_ASSERT_RETURN(secs > 0,);
294
295 try {
296 #ifdef CARLA_OS_WIN
297 ::Sleep(secs * 1000);
298 #else
299 ::sleep(secs);
300 #endif
301 } CARLA_SAFE_EXCEPTION("carla_sleep");
302 }
303
304 /*
305 * Sleep for 'msecs' milliseconds.
306 */
307 static inline
carla_msleep(const uint msecs)308 void carla_msleep(const uint msecs) noexcept
309 {
310 CARLA_SAFE_ASSERT_RETURN(msecs > 0,);
311
312 try {
313 #ifdef CARLA_OS_WIN
314 ::Sleep(msecs);
315 #else
316 ::usleep(msecs * 1000);
317 #endif
318 } CARLA_SAFE_EXCEPTION("carla_msleep");
319 }
320
321 // --------------------------------------------------------------------------------------------------------------------
322 // carla_setenv
323
324 /*
325 * Set environment variable 'key' to 'value'.
326 */
327 static inline
carla_setenv(const char * const key,const char * const value)328 void carla_setenv(const char* const key, const char* const value) noexcept
329 {
330 CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
331 CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
332
333 #ifdef CARLA_OS_WIN
334 try {
335 ::SetEnvironmentVariableA(key, value);
336 } CARLA_SAFE_EXCEPTION("carla_setenv");
337 #else
338 ::setenv(key, value, 1);
339 #endif
340 }
341
342 /*
343 * Unset environment variable 'key'.
344 */
345 static inline
carla_unsetenv(const char * const key)346 void carla_unsetenv(const char* const key) noexcept
347 {
348 CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
349
350 #ifdef CARLA_OS_WIN
351 try {
352 ::SetEnvironmentVariableA(key, nullptr);
353 } CARLA_SAFE_EXCEPTION("carla_unsetenv");
354 #else
355 ::unsetenv(key);
356 #endif
357 }
358
359 // --------------------------------------------------------------------------------------------------------------------
360 // carla_strdup
361
362 /*
363 * Custom 'strdup' function.
364 * Returned value is always valid, and must be freed with "delete[] var".
365 * May throw.
366 */
367 static inline
carla_strdup(const char * const strBuf)368 const char* carla_strdup(const char* const strBuf)
369 {
370 CARLA_SAFE_ASSERT(strBuf != nullptr);
371
372 const std::size_t bufferLen = (strBuf != nullptr) ? std::strlen(strBuf) : 0;
373 char* const buffer = new char[bufferLen+1];
374
375 if (bufferLen > 0)
376 std::memcpy(buffer, strBuf, bufferLen);
377
378 buffer[bufferLen] = '\0';
379
380 return buffer;
381 }
382
383 /*
384 * Custom 'strdup' function.
385 * Calls "std::free(strBuf)".
386 * Returned value is always valid, and must be freed with "delete[] var".
387 * May throw.
388 */
389 static inline
carla_strdup_free(char * const strBuf)390 const char* carla_strdup_free(char* const strBuf)
391 {
392 const char* const buffer(carla_strdup(strBuf));
393 std::free(strBuf);
394 return buffer;
395 }
396
397 /*
398 * Custom 'strdup' function, safe version.
399 * Returned value may be null. It must be freed with "delete[] var".
400 */
401 static inline
carla_strdup_safe(const char * const strBuf)402 const char* carla_strdup_safe(const char* const strBuf) noexcept
403 {
404 CARLA_SAFE_ASSERT_RETURN(strBuf != nullptr, nullptr);
405
406 const std::size_t bufferLen = std::strlen(strBuf);
407 char* buffer;
408
409 try {
410 buffer = new char[bufferLen+1];
411 } CARLA_SAFE_EXCEPTION_RETURN("carla_strdup_safe", nullptr);
412
413 if (bufferLen > 0)
414 std::memcpy(buffer, strBuf, bufferLen);
415
416 buffer[bufferLen] = '\0';
417
418 return buffer;
419 }
420
421 // --------------------------------------------------------------------------------------------------------------------
422 // memory functions
423
424 /*
425 * Add array values to another array.
426 */
427 template<typename T>
428 static inline
carla_add(T dest[],const T src[],const std::size_t count)429 void carla_add(T dest[], const T src[], const std::size_t count) noexcept
430 {
431 CARLA_SAFE_ASSERT_RETURN(dest != nullptr,);
432 CARLA_SAFE_ASSERT_RETURN(src != nullptr,);
433 CARLA_SAFE_ASSERT_RETURN(dest != src,);
434 CARLA_SAFE_ASSERT_RETURN(count > 0,);
435
436 for (std::size_t i=0; i<count; ++i)
437 *dest++ += *src++;
438 }
439
440 /*
441 * Add array values to another array, with a multiplication factor.
442 */
443 template<typename T>
444 static inline
carla_addWithMultiply(T dest[],const T src[],const T & multiplier,const std::size_t count)445 void carla_addWithMultiply(T dest[], const T src[], const T& multiplier, const std::size_t count) noexcept
446 {
447 CARLA_SAFE_ASSERT_RETURN(dest != nullptr,);
448 CARLA_SAFE_ASSERT_RETURN(src != nullptr,);
449 CARLA_SAFE_ASSERT_RETURN(dest != src,);
450 CARLA_SAFE_ASSERT_RETURN(count > 0,);
451
452 for (std::size_t i=0; i<count; ++i)
453 *dest++ += *src++ * multiplier;
454 }
455
456 /*
457 * Copy array values to another array.
458 */
459 template<typename T>
460 static inline
carla_copy(T dest[],const T src[],const std::size_t count)461 void carla_copy(T dest[], const T src[], const std::size_t count) noexcept
462 {
463 CARLA_SAFE_ASSERT_RETURN(dest != nullptr,);
464 CARLA_SAFE_ASSERT_RETURN(src != nullptr,);
465 CARLA_SAFE_ASSERT_RETURN(dest != src,);
466 CARLA_SAFE_ASSERT_RETURN(count > 0,);
467
468 std::memcpy(dest, src, count*sizeof(T));
469 }
470
471 /*
472 * Copy array values to another array, with a multiplication factor.
473 */
474 template<typename T>
475 static inline
carla_copyWithMultiply(T dest[],const T src[],const T & multiplier,const std::size_t count)476 void carla_copyWithMultiply(T dest[], const T src[], const T& multiplier, const std::size_t count) noexcept
477 {
478 CARLA_SAFE_ASSERT_RETURN(dest != nullptr,);
479 CARLA_SAFE_ASSERT_RETURN(src != nullptr,);
480 CARLA_SAFE_ASSERT_RETURN(dest != src,);
481 CARLA_SAFE_ASSERT_RETURN(count > 0,);
482
483 for (std::size_t i=0; i<count; ++i)
484 *dest++ = *src++ * multiplier;
485 }
486
487 /*
488 * Fill an array with a fixed value.
489 */
490 template<typename T>
491 static inline
carla_fill(T data[],const T & value,const std::size_t count)492 void carla_fill(T data[], const T& value, const std::size_t count) noexcept
493 {
494 CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
495 CARLA_SAFE_ASSERT_RETURN(count > 0,);
496
497 if (value == 0)
498 {
499 std::memset(data, 0, count*sizeof(T));
500 }
501 else
502 {
503 for (std::size_t i=0; i<count; ++i)
504 *data++ = value;
505 }
506 }
507
508 /*
509 * Multiply an array with a fixed value.
510 */
511 template<typename T>
512 static inline
carla_multiply(T data[],const T & multiplier,const std::size_t count)513 void carla_multiply(T data[], const T& multiplier, const std::size_t count) noexcept
514 {
515 CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
516 CARLA_SAFE_ASSERT_RETURN(count > 0,);
517
518 if (multiplier == 0)
519 {
520 std::memset(data, 0, count*sizeof(T));
521 }
522 else
523 {
524 for (std::size_t i=0; i<count; ++i)
525 *data++ *= multiplier;
526 }
527 }
528
529 /*
530 * Clear a byte array.
531 */
532 static inline
carla_zeroBytes(uint8_t bytes[],const std::size_t count)533 void carla_zeroBytes(uint8_t bytes[], const std::size_t count) noexcept
534 {
535 CARLA_SAFE_ASSERT_RETURN(bytes != nullptr,);
536 CARLA_SAFE_ASSERT_RETURN(count > 0,);
537
538 std::memset(bytes, 0, count*sizeof(uint8_t));
539 }
540
541 /*
542 * Clear a char array.
543 */
544 static inline
carla_zeroChars(char chars[],const std::size_t count)545 void carla_zeroChars(char chars[], const std::size_t count) noexcept
546 {
547 CARLA_SAFE_ASSERT_RETURN(chars != nullptr,);
548 CARLA_SAFE_ASSERT_RETURN(count > 0,);
549
550 std::memset(chars, 0, count*sizeof(char));
551 }
552
553 /*
554 * Clear a pointer array.
555 */
556 template<typename T>
557 static inline
carla_zeroPointers(T * ptrs[],const std::size_t count)558 void carla_zeroPointers(T* ptrs[], const std::size_t count) noexcept
559 {
560 CARLA_SAFE_ASSERT_RETURN(ptrs != nullptr,);
561 CARLA_SAFE_ASSERT_RETURN(count > 0,);
562
563 std::memset(ptrs, 0, count*sizeof(T*));
564 }
565
566 /*
567 * Clear a single struct.
568 */
569 template <typename T>
570 static inline
carla_zeroStruct(T & s)571 void carla_zeroStruct(T& s) noexcept
572 {
573 std::memset(&s, 0, sizeof(T));
574 }
575
576 /*
577 * Clear a struct array.
578 */
579 template <typename T>
580 static inline
carla_zeroStructs(T structs[],const std::size_t count)581 void carla_zeroStructs(T structs[], const std::size_t count) noexcept
582 {
583 CARLA_SAFE_ASSERT_RETURN(structs != nullptr,);
584 CARLA_SAFE_ASSERT_RETURN(count > 0,);
585
586 std::memset(structs, 0, count*sizeof(T));
587 }
588
589 /*
590 * Copy a single struct.
591 */
592 template <typename T>
593 static inline
carla_copyStruct(T & dest,const T & src)594 void carla_copyStruct(T& dest, const T& src) noexcept
595 {
596 std::memcpy(&dest, &src, sizeof(T));
597 }
598
599 /*
600 * Copy a struct array.
601 */
602 template <typename T>
603 static inline
carla_copyStructs(T dest[],const T src[],const std::size_t count)604 void carla_copyStructs(T dest[], const T src[], const std::size_t count) noexcept
605 {
606 CARLA_SAFE_ASSERT_RETURN(dest != nullptr,);
607 CARLA_SAFE_ASSERT_RETURN(src != nullptr,);
608 CARLA_SAFE_ASSERT_RETURN(dest != src,);
609 CARLA_SAFE_ASSERT_RETURN(count > 0,);
610
611 std::memcpy(dest, src, count*sizeof(T));
612 }
613
614 // --------------------------------------------------------------------------------------------------------------------
615
616 #endif // CARLA_UTILS_HPP_INCLUDED
617