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