diff options
-rw-r--r-- | core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | core/format.cpp | 414 | ||||
-rw-r--r-- | core/format.h | 29 | ||||
-rw-r--r-- | core/plannernotes.c | 1 | ||||
-rw-r--r-- | core/profile.c | 1 | ||||
-rw-r--r-- | core/qthelper.cpp | 394 | ||||
-rw-r--r-- | core/qthelper.h | 12 | ||||
-rw-r--r-- | packaging/ios/Subsurface-mobile/Subsurface-mobile.pro | 1 |
8 files changed, 448 insertions, 405 deletions
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 34e12c59b..62d756950 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -77,6 +77,7 @@ set(SUBSURFACE_CORE_LIB_SRCS # dirk ported some core functionality to c++. qthelper.cpp metadata.cpp + format.cpp divecomputer.cpp exif.cpp subsurfacesysinfo.cpp diff --git a/core/format.cpp b/core/format.cpp new file mode 100644 index 000000000..5793bff02 --- /dev/null +++ b/core/format.cpp @@ -0,0 +1,414 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "format.h" +#include "membuffer.h" + +QString qasprintf_loc(const char *cformat, ...) +{ + va_list ap; + va_start(ap, cformat); + QString res = vqasprintf_loc(cformat, ap); + va_end(ap); + return res; +} + +struct vasprintf_flags { + bool alternate_form : 1; // TODO: unsupported + bool zero : 1; + bool left : 1; + bool space : 1; + bool sign : 1; + bool thousands : 1; // ignored +}; + +enum length_modifier_t { + LM_NONE, + LM_CHAR, + LM_SHORT, + LM_LONG, + LM_LONGLONG, + LM_LONGDOUBLE, + LM_INTMAX, + LM_SIZET, + LM_PTRDIFF +}; + +// Helper function to insert '+' or ' ' after last space +static QString insert_sign(QString s, char sign) +{ + // For space we can take a shortcut: insert in front + if (sign == ' ') + return sign + s; + int size = s.size(); + int pos; + for (pos = 0; pos < size && s[pos].isSpace(); ++pos) + ; // Pass + return s.left(pos) + '+' + s.mid(pos); +} + +static QString fmt_string(const QString &s, vasprintf_flags flags, int field_width, int precision) +{ + int size = s.size(); + if (precision >= 0 && size > precision) + return s.left(precision); + return flags.left ? s.leftJustified(field_width) : + s.rightJustified(field_width); +} + +// Formatting of integers and doubles using Qt's localized functions. +// The code is somewhat complex because Qt doesn't support all stdio +// format options, notably '+' and ' '. +// TODO: Since this is a templated function, remove common code +template <typename T> +static QString fmt_int(T i, vasprintf_flags flags, int field_width, int precision, int base) +{ + // If precision is given, things are a bit different: we have to pad with zero *and* space. + // Therefore, treat this case separately. + if (precision > 1) { + // For negative numbers, increase precision by one, so that we get + // the correct number of printed digits + if (i < 0) + ++precision; + QChar fillChar = '0'; + QString res = QStringLiteral("%L1").arg(i, precision, base, fillChar); + if (i >= 0 && flags.space) + res = ' ' + res; + else if (i >= 0 && flags.sign) + res = '+' + res; + return fmt_string(res, flags, field_width, -1); + } + + // If we have to prepend a '+' or a space character, remove that from the field width + char sign = 0; + if (i >= 0 && (flags.space || flags.sign) && field_width > 0) { + sign = flags.sign ? '+' : ' '; + --field_width; + } + if (flags.left) + field_width = -field_width; + QChar fillChar = flags.zero && !flags.left ? '0' : ' '; + QString res = QStringLiteral("%L1").arg(i, field_width, base, fillChar); + return sign ? insert_sign(res, sign) : res; +} + +static QString fmt_float(double d, char type, vasprintf_flags flags, int field_width, int precision) +{ + // If we have to prepend a '+' or a space character, remove that from the field width + char sign = 0; + if (d >= 0.0 && (flags.space || flags.sign) && field_width > 0) { + sign = flags.sign ? '+' : ' '; + --field_width; + } + if (flags.left) + field_width = -field_width; + QChar fillChar = flags.zero && !flags.left ? '0' : ' '; + QString res = QStringLiteral("%L1").arg(d, field_width, type, precision, fillChar); + return sign ? insert_sign(res, sign) : res; +} + +// Helper to extract integers from C-style format strings. +// The default returned value, if no digits are found is 0. +static int parse_fmt_int(const char **act) +{ + if (!isdigit(**act)) + return 0; + int res = 0; + while (isdigit(**act)) { + res = res * 10 + **act - '0'; + ++(*act); + } + return res; +} + +QString vqasprintf_loc(const char *fmt, va_list ap) +{ + const char *act = fmt; + QString ret; + for (;;) { + // Get all bytes up to next '%' character and add them as UTF-8 + const char *begin = act; + while (*act && *act != '%') + ++act; + int len = act - begin; + if (len > 0) + ret += QString::fromUtf8(begin, len); + + // We found either a '%' or the end of the format string + if (!*act) + break; + ++act; // Jump over '%' + + if (*act == '%') { + ++act; + ret += '%'; + continue; + } + // Flags + vasprintf_flags flags = { 0 }; + for (;; ++act) { + switch(*act) { + case '#': + flags.alternate_form = true; + continue; + case '0': + flags.zero = true; + continue; + case '-': + flags.left = true; + continue; + case ' ': + flags.space = true; + continue; + case '+': + flags.sign = true; + continue; + case '\'': + flags.thousands = true; + continue; + } + break; + } + + // Field width + int field_width; + if (*act == '*') { + field_width = va_arg(ap, int); + ++act; + } else { + field_width = parse_fmt_int(&act); + } + + // Precision + int precision = -1; + if (*act == '.') { + ++act; + if (*act == '*') { + precision = va_arg(ap, int); + ++act; + } else { + precision = parse_fmt_int(&act); + } + } + + // Length modifier + enum length_modifier_t length_modifier = LM_NONE; + switch(*act) { + case 'h': + ++act; + length_modifier = LM_CHAR; + if (*act == 'h') { + length_modifier = LM_SHORT; + ++act; + } + break; + case 'l': + ++act; + length_modifier = LM_LONG; + if (*act == 'l') { + length_modifier = LM_LONGLONG; + ++act; + } + break; + case 'q': + ++act; + length_modifier = LM_LONGLONG; + break; + case 'L': + ++act; + length_modifier = LM_LONGDOUBLE; + break; + case 'j': + ++act; + length_modifier = LM_INTMAX; + break; + case 'z': + case 'Z': + ++act; + length_modifier = LM_SIZET; + break; + case 't': + ++act; + length_modifier = LM_PTRDIFF; + break; + } + + char type = *act++; + // Bail out if we reached end of the format string + if (!type) + break; + + int base = 10; + if (type == 'o') + base = 8; + else if (type == 'x' || type == 'X') + base = 16; + + switch(type) { + case 'd': case 'i': { + switch(length_modifier) { + case LM_LONG: + ret += fmt_int(va_arg(ap, long), flags, field_width, precision, base); + break; + case LM_LONGLONG: + ret += fmt_int(va_arg(ap, long long), flags, field_width, precision, base); + break; + case LM_INTMAX: + ret += fmt_int(va_arg(ap, intmax_t), flags, field_width, precision, base); + break; + case LM_SIZET: + ret += fmt_int(va_arg(ap, ssize_t), flags, field_width, precision, base); + break; + case LM_PTRDIFF: + ret += fmt_int(va_arg(ap, ptrdiff_t), flags, field_width, precision, base); + break; + case LM_CHAR: + // char is promoted to int when passed through '...' + ret += fmt_int(static_cast<char>(va_arg(ap, int)), flags, field_width, precision, base); + break; + case LM_SHORT: + // short is promoted to int when passed through '...' + ret += fmt_int(static_cast<short>(va_arg(ap, int)), flags, field_width, precision, base); + break; + default: + ret += fmt_int(va_arg(ap, int), flags, field_width, precision, base); + break; + } + break; + } + case 'o': case 'u': case 'x': case 'X': { + QString s; + switch(length_modifier) { + case LM_LONG: + s = fmt_int(va_arg(ap, unsigned long), flags, field_width, precision, base); + break; + case LM_LONGLONG: + s = fmt_int(va_arg(ap, unsigned long long), flags, field_width, precision, base); + break; + case LM_INTMAX: + s = fmt_int(va_arg(ap, uintmax_t), flags, field_width, precision, base); + break; + case LM_SIZET: + s = fmt_int(va_arg(ap, size_t), flags, field_width, precision, base); + break; + case LM_PTRDIFF: + s = fmt_int(va_arg(ap, ptrdiff_t), flags, field_width, precision, base); + break; + case LM_CHAR: + // char is promoted to int when passed through '...' + s = fmt_int(static_cast<unsigned char>(va_arg(ap, int)), flags, field_width, precision, base); + break; + case LM_SHORT: + // short is promoted to int when passed through '...' + s = fmt_int(static_cast<unsigned short>(va_arg(ap, int)), flags, field_width, precision, base); + break; + default: + s = fmt_int(va_arg(ap, unsigned int), flags, field_width, precision, base); + break; + } + if (type == 'X') + s = s.toUpper(); + ret += s; + break; + } + case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': { + // It seems that Qt is not able to format long doubles, + // therefore we have to cast down to double. + double f = length_modifier == LM_LONGDOUBLE ? + static_cast<double>(va_arg(ap, long double)) : + va_arg(ap, double); + ret += fmt_float(f, type, flags, field_width, precision); + break; + } + case 'c': + if (length_modifier == LM_LONG) { + // Cool, on some platforms wint_t is short, on some int. +#if WINT_MAX < UINT_MAX + wint_t wc = static_cast<wint_t>(va_arg(ap, int)); +#else + wint_t wc = va_arg(ap, wint_t); +#endif + ret += QChar(wc); + } else { + ret += static_cast<char>(va_arg(ap, int)); + } + break; + case 's': { + QString s = length_modifier == LM_LONG ? + QString::fromWCharArray(va_arg(ap, wchar_t *)) : + QString::fromUtf8(va_arg(ap, char *)); + ret += fmt_string(s, flags, field_width, precision); + break; + } + case 'p': + ret += QString("0x%1").arg(reinterpret_cast<long long>(va_arg(ap, void *)), field_width, 16); + break; + } + } + return ret; +} + +// Put a formated string respecting the default locale into a C-style array in UTF-8 encoding. +// The only complication arises from the fact that we don't want to cut through multi-byte UTF-8 code points. +extern "C" int snprintf_loc(char *dst, size_t size, const char *cformat, ...) +{ + va_list ap; + va_start(ap, cformat); + int res = vsnprintf_loc(dst, size, cformat, ap); + va_end(ap); + return res; +} + +extern "C" int vsnprintf_loc(char *dst, size_t size, const char *cformat, va_list ap) +{ + QByteArray utf8 = vqasprintf_loc(cformat, ap).toUtf8(); + const char *data = utf8.constData(); + size_t utf8_size = utf8.size(); + if (size == 0) + return utf8_size; + if (size < utf8_size + 1) { + memcpy(dst, data, size - 1); + if ((data[size - 1] & 0xC0) == 0x80) { + // We truncated a multi-byte UTF-8 encoding. + --size; + // Jump to last copied byte. + if (size > 0) + --size; + while(size > 0 && (dst[size] & 0xC0) == 0x80) + --size; + dst[size] = 0; + } else { + dst[size - 1] = 0; + } + } else { + memcpy(dst, data, utf8_size + 1); // QByteArray guarantees a trailing 0 + } + return utf8_size; +} + +int asprintf_loc(char **dst, const char *cformat, ...) +{ + va_list ap; + va_start(ap, cformat); + int res = vasprintf_loc(dst, cformat, ap); + va_end(ap); + return res; +} + +int vasprintf_loc(char **dst, const char *cformat, va_list ap) +{ + QByteArray utf8 = vqasprintf_loc(cformat, ap).toUtf8(); + *dst = strdup(utf8.constData()); + return utf8.size(); +} + +// This function is defined here instead of membuffer.c, because it needs to access QString. +extern "C" void put_vformat_loc(struct membuffer *b, const char *fmt, va_list args) +{ + QByteArray utf8 = vqasprintf_loc(fmt, args).toUtf8(); + const char *data = utf8.constData(); + size_t utf8_size = utf8.size(); + + make_room(b, utf8_size); + memcpy(b->buffer + b->len, data, utf8_size); + b->len += utf8_size; +} + diff --git a/core/format.h b/core/format.h new file mode 100644 index 000000000..0498fe2be --- /dev/null +++ b/core/format.h @@ -0,0 +1,29 @@ +#ifndef FORMAT_H +#define FORMAT_H + +#ifdef __GNUC__ +#define __printf(x, y) __attribute__((__format__(__printf__, x, y))) +#else +#define __printf(x, y) +#endif + +#ifdef __cplusplus +#include <QString> +__printf(1, 2) QString qasprintf_loc(const char *cformat, ...); +__printf(1, 0) QString vqasprintf_loc(const char *cformat, va_list ap); +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +__printf(3, 4) int snprintf_loc(char *dst, size_t size, const char *cformat, ...); +__printf(3, 0) int vsnprintf_loc(char *dst, size_t size, const char *cformat, va_list ap); +__printf(2, 3) int asprintf_loc(char **dst, const char *cformat, ...); +__printf(2, 0) int vasprintf_loc(char **dst, const char *cformat, va_list ap); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/core/plannernotes.c b/core/plannernotes.c index 96a1f1b9c..d7c0de898 100644 --- a/core/plannernotes.c +++ b/core/plannernotes.c @@ -16,6 +16,7 @@ #include "gettext.h" #include "libdivecomputer/parser.h" #include "qthelper.h" +#include "format.h" #include "version.h" int diveplan_duration(struct diveplan *diveplan) diff --git a/core/profile.c b/core/profile.c index d9dbfed51..2fbc3a892 100644 --- a/core/profile.c +++ b/core/profile.c @@ -18,6 +18,7 @@ #include "libdivecomputer/version.h" #include "membuffer.h" #include "qthelper.h" +#include "format.h" //#define DEBUG_GAS 1 diff --git a/core/qthelper.cpp b/core/qthelper.cpp index d63ee3568..6c4fc099c 100644 --- a/core/qthelper.cpp +++ b/core/qthelper.cpp @@ -1722,400 +1722,6 @@ extern "C" void unlock_planner() planLock.unlock(); } -QString asprintf_loc(const char *cformat, ...) -{ - va_list ap; - va_start(ap, cformat); - QString res = vasprintf_loc(cformat, ap); - va_end(ap); - return res; -} - -struct vasprintf_flags { - bool alternate_form : 1; // TODO: unsupported - bool zero : 1; - bool left : 1; - bool space : 1; - bool sign : 1; - bool thousands : 1; // ignored -}; - -enum length_modifier_t { - LM_NONE, - LM_CHAR, - LM_SHORT, - LM_LONG, - LM_LONGLONG, - LM_LONGDOUBLE, - LM_INTMAX, - LM_SIZET, - LM_PTRDIFF -}; - -// Helper function to insert '+' or ' ' after last space -static QString insert_sign(QString s, char sign) -{ - // For space we can take a shortcut: insert in front - if (sign == ' ') - return sign + s; - int size = s.size(); - int pos; - for (pos = 0; pos < size && s[pos].isSpace(); ++pos) - ; // Pass - return s.left(pos) + '+' + s.mid(pos); -} - -static QString fmt_string(const QString &s, vasprintf_flags flags, int field_width, int precision) -{ - int size = s.size(); - if (precision >= 0 && size > precision) - return s.left(precision); - return flags.left ? s.leftJustified(field_width) : - s.rightJustified(field_width); -} - -// Formatting of integers and doubles using Qt's localized functions. -// The code is somewhat complex because Qt doesn't support all stdio -// format options, notably '+' and ' '. -// TODO: Since this is a templated function, remove common code -template <typename T> -static QString fmt_int(T i, vasprintf_flags flags, int field_width, int precision, int base) -{ - // If precision is given, things are a bit different: we have to pad with zero *and* space. - // Therefore, treat this case separately. - if (precision > 1) { - // For negative numbers, increase precision by one, so that we get - // the correct number of printed digits - if (i < 0) - ++precision; - QChar fillChar = '0'; - QString res = QStringLiteral("%L1").arg(i, precision, base, fillChar); - if (i >= 0 && flags.space) - res = ' ' + res; - else if (i >= 0 && flags.sign) - res = '+' + res; - return fmt_string(res, flags, field_width, -1); - } - - // If we have to prepend a '+' or a space character, remove that from the field width - char sign = 0; - if (i >= 0 && (flags.space || flags.sign) && field_width > 0) { - sign = flags.sign ? '+' : ' '; - --field_width; - } - if (flags.left) - field_width = -field_width; - QChar fillChar = flags.zero && !flags.left ? '0' : ' '; - QString res = QStringLiteral("%L1").arg(i, field_width, base, fillChar); - return sign ? insert_sign(res, sign) : res; -} - -static QString fmt_float(double d, char type, vasprintf_flags flags, int field_width, int precision) -{ - // If we have to prepend a '+' or a space character, remove that from the field width - char sign = 0; - if (d >= 0.0 && (flags.space || flags.sign) && field_width > 0) { - sign = flags.sign ? '+' : ' '; - --field_width; - } - if (flags.left) - field_width = -field_width; - QChar fillChar = flags.zero && !flags.left ? '0' : ' '; - QString res = QStringLiteral("%L1").arg(d, field_width, type, precision, fillChar); - return sign ? insert_sign(res, sign) : res; -} - -// Helper to extract integers from C-style format strings. -// The default returned value, if no digits are found is 0. -static int parse_fmt_int(const char **act) -{ - if (!isdigit(**act)) - return 0; - int res = 0; - while (isdigit(**act)) { - res = res * 10 + **act - '0'; - ++(*act); - } - return res; -} - -QString vasprintf_loc(const char *fmt, va_list ap) -{ - const char *act = fmt; - QString ret; - for (;;) { - // Get all bytes up to next '%' character and add them as UTF-8 - const char *begin = act; - while (*act && *act != '%') - ++act; - int len = act - begin; - if (len > 0) - ret += QString::fromUtf8(begin, len); - - // We found either a '%' or the end of the format string - if (!*act) - break; - ++act; // Jump over '%' - - if (*act == '%') { - ++act; - ret += '%'; - continue; - } - // Flags - vasprintf_flags flags = { 0 }; - for (;; ++act) { - switch(*act) { - case '#': - flags.alternate_form = true; - continue; - case '0': - flags.zero = true; - continue; - case '-': - flags.left = true; - continue; - case ' ': - flags.space = true; - continue; - case '+': - flags.sign = true; - continue; - case '\'': - flags.thousands = true; - continue; - } - break; - } - - // Field width - int field_width; - if (*act == '*') { - field_width = va_arg(ap, int); - ++act; - } else { - field_width = parse_fmt_int(&act); - } - - // Precision - int precision = -1; - if (*act == '.') { - ++act; - if (*act == '*') { - precision = va_arg(ap, int); - ++act; - } else { - precision = parse_fmt_int(&act); - } - } - - // Length modifier - enum length_modifier_t length_modifier = LM_NONE; - switch(*act) { - case 'h': - ++act; - length_modifier = LM_CHAR; - if (*act == 'h') { - length_modifier = LM_SHORT; - ++act; - } - break; - case 'l': - ++act; - length_modifier = LM_LONG; - if (*act == 'l') { - length_modifier = LM_LONGLONG; - ++act; - } - break; - case 'q': - ++act; - length_modifier = LM_LONGLONG; - break; - case 'L': - ++act; - length_modifier = LM_LONGDOUBLE; - break; - case 'j': - ++act; - length_modifier = LM_INTMAX; - break; - case 'z': - case 'Z': - ++act; - length_modifier = LM_SIZET; - break; - case 't': - ++act; - length_modifier = LM_PTRDIFF; - break; - } - - char type = *act++; - // Bail out if we reached end of the format string - if (!type) - break; - - int base = 10; - if (type == 'o') - base = 8; - else if (type == 'x' || type == 'X') - base = 16; - - switch(type) { - case 'd': case 'i': { - switch(length_modifier) { - case LM_LONG: - ret += fmt_int(va_arg(ap, long), flags, field_width, precision, base); - break; - case LM_LONGLONG: - ret += fmt_int(va_arg(ap, long long), flags, field_width, precision, base); - break; - case LM_INTMAX: - ret += fmt_int(va_arg(ap, intmax_t), flags, field_width, precision, base); - break; - case LM_SIZET: - ret += fmt_int(va_arg(ap, ssize_t), flags, field_width, precision, base); - break; - case LM_PTRDIFF: - ret += fmt_int(va_arg(ap, ptrdiff_t), flags, field_width, precision, base); - break; - case LM_CHAR: - // char is promoted to int when passed through '...' - ret += fmt_int(static_cast<char>(va_arg(ap, int)), flags, field_width, precision, base); - break; - case LM_SHORT: - // short is promoted to int when passed through '...' - ret += fmt_int(static_cast<short>(va_arg(ap, int)), flags, field_width, precision, base); - break; - default: - ret += fmt_int(va_arg(ap, int), flags, field_width, precision, base); - break; - } - break; - } - case 'o': case 'u': case 'x': case 'X': { - QString s; - switch(length_modifier) { - case LM_LONG: - s = fmt_int(va_arg(ap, unsigned long), flags, field_width, precision, base); - break; - case LM_LONGLONG: - s = fmt_int(va_arg(ap, unsigned long long), flags, field_width, precision, base); - break; - case LM_INTMAX: - s = fmt_int(va_arg(ap, uintmax_t), flags, field_width, precision, base); - break; - case LM_SIZET: - s = fmt_int(va_arg(ap, size_t), flags, field_width, precision, base); - break; - case LM_PTRDIFF: - s = fmt_int(va_arg(ap, ptrdiff_t), flags, field_width, precision, base); - break; - case LM_CHAR: - // char is promoted to int when passed through '...' - s = fmt_int(static_cast<unsigned char>(va_arg(ap, int)), flags, field_width, precision, base); - break; - case LM_SHORT: - // short is promoted to int when passed through '...' - s = fmt_int(static_cast<unsigned short>(va_arg(ap, int)), flags, field_width, precision, base); - break; - default: - s = fmt_int(va_arg(ap, unsigned int), flags, field_width, precision, base); - break; - } - if (type == 'X') - s = s.toUpper(); - ret += s; - break; - } - case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': { - // It seems that Qt is not able to format long doubles, - // therefore we have to cast down to double. - double f = length_modifier == LM_LONGDOUBLE ? - static_cast<double>(va_arg(ap, long double)) : - va_arg(ap, double); - ret += fmt_float(f, type, flags, field_width, precision); - break; - } - case 'c': - if (length_modifier == LM_LONG) { - // Cool, on some platforms wint_t is short, on some int. -#if WINT_MAX < UINT_MAX - wint_t wc = static_cast<wint_t>(va_arg(ap, int)); -#else - wint_t wc = va_arg(ap, wint_t); -#endif - ret += QChar(wc); - } else { - ret += static_cast<char>(va_arg(ap, int)); - } - break; - case 's': { - QString s = length_modifier == LM_LONG ? - QString::fromWCharArray(va_arg(ap, wchar_t *)) : - QString::fromUtf8(va_arg(ap, char *)); - ret += fmt_string(s, flags, field_width, precision); - break; - } - case 'p': - ret += QString("0x%1").arg(reinterpret_cast<long long>(va_arg(ap, void *)), field_width, 16); - break; - } - } - return ret; -} - -// Put a formated string respecting the default locale into a C-style array in UTF-8 encoding. -// The only complication arises from the fact that we don't want to cut through multi-byte UTF-8 code points. -extern "C" int snprintf_loc(char *dst, size_t size, const char *cformat, ...) -{ - va_list ap; - va_start(ap, cformat); - int res = vsnprintf_loc(dst, size, cformat, ap); - va_end(ap); - return res; -} - -extern "C" int vsnprintf_loc(char *dst, size_t size, const char *cformat, va_list ap) -{ - QByteArray utf8 = vasprintf_loc(cformat, ap).toUtf8(); - const char *data = utf8.constData(); - size_t utf8_size = utf8.size(); - if (size == 0) - return utf8_size; - if (size < utf8_size + 1) { - memcpy(dst, data, size - 1); - if ((data[size - 1] & 0xC0) == 0x80) { - // We truncated a multi-byte UTF-8 encoding. - --size; - // Jump to last copied byte. - if (size > 0) - --size; - while(size > 0 && (dst[size] & 0xC0) == 0x80) - --size; - dst[size] = 0; - } else { - dst[size - 1] = 0; - } - } else { - memcpy(dst, data, utf8_size + 1); // QByteArray guarantees a trailing 0 - } - return utf8_size; -} - -// This function is defined here instead of membuffer.c, because it needs to access QString. -extern "C" void put_vformat_loc(struct membuffer *b, const char *fmt, va_list args) -{ - QByteArray utf8 = vasprintf_loc(fmt, args).toUtf8(); - const char *data = utf8.constData(); - size_t utf8_size = utf8.size(); - - make_room(b, utf8_size); - memcpy(b->buffer + b->len, data, utf8_size); - b->len += utf8_size; -} - char *copy_qstring(const QString &s) { return strdup(qPrintable(s)); diff --git a/core/qthelper.h b/core/qthelper.h index c699c5653..02fc629f8 100644 --- a/core/qthelper.h +++ b/core/qthelper.h @@ -6,13 +6,7 @@ #include "dive.h" #include "divelist.h" -// 1) Types and macros - -#ifdef __GNUC__ -#define __printf(x, y) __attribute__((__format__(__printf__, x, y))) -#else -#define __printf(x, y) -#endif +// 1) Types enum inertgas {N2, HE}; @@ -56,8 +50,6 @@ QString getUUID(); QStringList imageExtensionFilters(); char *intdup(int index); char *copy_qstring(const QString &); -__printf(1, 2) QString asprintf_loc(const char *cformat, ...); -__printf(1, 0) QString vasprintf_loc(const char *cformat, va_list ap); #endif // 3) Functions visible to C and C++ @@ -93,8 +85,6 @@ void cache_insert(int tissue, int timestep, enum inertgas gas, double value); void print_qt_versions(); void lock_planner(); void unlock_planner(); -__printf(3, 4) int snprintf_loc(char *dst, size_t size, const char *cformat, ...); -__printf(3, 0) int vsnprintf_loc(char *dst, size_t size, const char *cformat, va_list ap); #ifdef __cplusplus } diff --git a/packaging/ios/Subsurface-mobile/Subsurface-mobile.pro b/packaging/ios/Subsurface-mobile/Subsurface-mobile.pro index 2ff93243b..c43f13930 100644 --- a/packaging/ios/Subsurface-mobile/Subsurface-mobile.pro +++ b/packaging/ios/Subsurface-mobile/Subsurface-mobile.pro @@ -27,6 +27,7 @@ SOURCES += ../../../subsurface-mobile-main.cpp \ ../../../core/divesitehelpers.cpp \ ../../../core/errorhelper.c \ ../../../core/exif.cpp \ + ../../../core/format.cpp \ ../../../core/gettextfromc.cpp \ ../../../core/isocialnetworkintegration.cpp \ ../../../core/metrics.cpp \ |