vsnprintf() wrapper that is not sensitive to LC_NUMERIC settings. * * This function has the same contract as standard vsnprintf(), except that * formatting of floating-point numbers will use decimal point, whatever the * current locale is set. * * @param str output buffer * @param size size of the output buffer (including space for terminating nul) * @param fmt formatting string * @param
| 1126 | * for Visual Studio < 2015. |
| 1127 | */ |
| 1128 | int CPLvsnprintf(char *str, size_t size, CPL_FORMAT_STRING(const char *fmt), |
| 1129 | va_list args) |
| 1130 | { |
| 1131 | if (size == 0) |
| 1132 | return vsnprintf(str, size, fmt, args); |
| 1133 | |
| 1134 | va_list wrk_args; |
| 1135 | |
| 1136 | #ifdef va_copy |
| 1137 | va_copy(wrk_args, args); |
| 1138 | #else |
| 1139 | wrk_args = args; |
| 1140 | #endif |
| 1141 | |
| 1142 | const char *fmt_ori = fmt; |
| 1143 | size_t offset_out = 0; |
| 1144 | char ch = '\0'; |
| 1145 | bool bFormatUnknown = false; |
| 1146 | |
| 1147 | for (; (ch = *fmt) != '\0'; ++fmt) |
| 1148 | { |
| 1149 | if (ch == '%') |
| 1150 | { |
| 1151 | if (strncmp(fmt, "%.*f", 4) == 0) |
| 1152 | { |
| 1153 | const int precision = va_arg(wrk_args, int); |
| 1154 | const double val = va_arg(wrk_args, double); |
| 1155 | const int local_ret = |
| 1156 | snprintf(str + offset_out, size - offset_out, "%.*f", |
| 1157 | precision, val); |
| 1158 | // MSVC vsnprintf() returns -1. |
| 1159 | if (local_ret < 0 || offset_out + local_ret >= size) |
| 1160 | break; |
| 1161 | for (int j = 0; j < local_ret; ++j) |
| 1162 | { |
| 1163 | if (str[offset_out + j] == ',') |
| 1164 | { |
| 1165 | str[offset_out + j] = '.'; |
| 1166 | break; |
| 1167 | } |
| 1168 | } |
| 1169 | offset_out += local_ret; |
| 1170 | fmt += strlen("%.*f") - 1; |
| 1171 | continue; |
| 1172 | } |
| 1173 | |
| 1174 | const char *ptrend = CPLvsnprintf_get_end_of_formatting(fmt + 1); |
| 1175 | if (ptrend == nullptr || ptrend - fmt >= 20) |
| 1176 | { |
| 1177 | bFormatUnknown = true; |
| 1178 | break; |
| 1179 | } |
| 1180 | char end = *ptrend; |
| 1181 | char end_m1 = ptrend[-1]; |
| 1182 | |
| 1183 | char localfmt[22] = {}; |
| 1184 | memcpy(localfmt, fmt, ptrend - fmt + 1); |
| 1185 | localfmt[ptrend - fmt + 1] = '\0'; |
no test coverage detected