summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/CMakeLists.txt1
-rw-r--r--core/format.cpp414
-rw-r--r--core/format.h29
-rw-r--r--core/plannernotes.c1
-rw-r--r--core/profile.c1
-rw-r--r--core/qthelper.cpp394
-rw-r--r--core/qthelper.h12
-rw-r--r--packaging/ios/Subsurface-mobile/Subsurface-mobile.pro1
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 \