Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
mbed_printf_implementation.c
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2017 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "mbed_printf_implementation.h" 00018 00019 #include <stdbool.h> 00020 #include <limits.h> 00021 #include <stdint.h> 00022 #include <stddef.h> 00023 00024 /***************************/ 00025 /* MBED */ 00026 /***************************/ 00027 #if TARGET_LIKE_MBED 00028 00029 #if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES 00030 static char mbed_stdio_out_prev = 0; 00031 #endif 00032 00033 00034 /***************************/ 00035 /* Linux */ 00036 /***************************/ 00037 #else 00038 /* Linux implementation is for debug only */ 00039 #define MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT 1 00040 #define MBED_CONF_PLATFORM_MINIMAL_PRINTF_SET_FLOATING_POINT_MAX_DECIMALS 6 00041 #define MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_64_BIT 1 00042 #endif 00043 00044 #ifndef MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT 00045 #define MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT 0 00046 #endif 00047 00048 #ifndef MBED_CONF_PLATFORM_MINIMAL_PRINTF_SET_FLOATING_POINT_MAX_DECIMALS 00049 #define MBED_CONF_PLATFORM_MINIMAL_PRINTF_SET_FLOATING_POINT_MAX_DECIMALS 6 00050 #endif 00051 00052 #ifndef MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_64_BIT 00053 #define MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_64_BIT 1 00054 #endif 00055 00056 /** 00057 * Check architecture and choose storage data type. 00058 * On 32 bit machines, the default storage type is 32 bit wide 00059 * unless 64 bit integers are enabled in the configuration. 00060 */ 00061 #if INTPTR_MAX == INT32_MAX 00062 #define MBED_SIGNED_NATIVE_TYPE int32_t 00063 #define MBED_UNSIGNED_NATIVE_TYPE uint32_t 00064 #if MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_64_BIT 00065 #define MBED_SIGNED_STORAGE int64_t 00066 #define MBED_UNSIGNED_STORAGE uint64_t 00067 #else 00068 #define MBED_SIGNED_STORAGE int32_t 00069 #define MBED_UNSIGNED_STORAGE uint32_t 00070 #endif 00071 00072 #elif INTPTR_MAX == INT64_MAX 00073 #define MBED_SIGNED_NATIVE_TYPE int64_t 00074 #define MBED_UNSIGNED_NATIVE_TYPE uint64_t 00075 #define MBED_SIGNED_STORAGE int64_t 00076 #define MBED_UNSIGNED_STORAGE uint64_t 00077 #else 00078 #error unsupported architecture 00079 #endif 00080 00081 /** 00082 * Precision defines 00083 */ 00084 #define PRECISION_DEFAULT (INT_MAX) 00085 00086 /** 00087 * Enum for storing width modifier. 00088 */ 00089 typedef enum { 00090 LENGTH_NONE = 0x00, 00091 LENGTH_H = 0x11, 00092 LENGTH_L = 0x21, 00093 LENGTH_J = 0x31, 00094 LENGTH_Z = 0x41, 00095 LENGTH_T = 0x51, 00096 LENGTH_CAPITAL_L = 0x61, 00097 LENGTH_HH = 0x72, 00098 LENGTH_LL = 0x82 00099 } length_t; 00100 00101 /** 00102 * Prototypes 00103 */ 00104 static void mbed_minimal_formatted_string_signed(char *buffer, size_t length, int *result, MBED_SIGNED_STORAGE value, FILE *stream); 00105 static void mbed_minimal_formatted_string_unsigned(char *buffer, size_t length, int *result, MBED_UNSIGNED_STORAGE value, FILE *stream); 00106 static void mbed_minimal_formatted_string_hexadecimal(char *buffer, size_t length, int *result, MBED_UNSIGNED_STORAGE value, FILE *stream, bool upper); 00107 static void mbed_minimal_formatted_string_void_pointer(char *buffer, size_t length, int *result, const void *value, FILE *stream); 00108 static void mbed_minimal_formatted_string_character(char *buffer, size_t length, int *result, char character, FILE *stream); 00109 static void mbed_minimal_formatted_string_string(char *buffer, size_t length, int *result, const char *string, size_t precision, FILE *stream); 00110 00111 00112 /** 00113 * @brief Print a single character, checking for buffer and size overflows. 00114 * 00115 * @param buffer The buffer to store output (NULL for stdout). 00116 * @param[in] length The length of the buffer. 00117 * @param result The current output location. 00118 * @param[in] data The char to be printed. 00119 */ 00120 static void mbed_minimal_putchar(char *buffer, size_t length, int *result, char data, FILE *stream) 00121 { 00122 /* only continue if 'result' doesn't overflow */ 00123 if ((*result >= 0) && (*result <= INT_MAX - 1)) { 00124 /* write data only if there's enough space */ 00125 if ((size_t)*result < length) { 00126 if (buffer) { 00127 buffer[*result] = data; 00128 } else { 00129 fputc(data, stream); 00130 } 00131 } 00132 /* increment 'result' even if data was not written. This ensures that 00133 'mbed_minimal_formatted_string' returns the correct value. */ 00134 *result += 1; 00135 } 00136 } 00137 00138 /** 00139 * @brief Print signed integer. 00140 * 00141 * @param buffer The buffer to store output (NULL for stdout). 00142 * @param[in] length The length of the buffer. 00143 * @param result The current output location. 00144 * @param[in] value The value to be printed. 00145 */ 00146 static void mbed_minimal_formatted_string_signed(char *buffer, size_t length, int *result, MBED_SIGNED_STORAGE value, FILE *stream) 00147 { 00148 MBED_UNSIGNED_STORAGE new_value = 0; 00149 00150 /* if value is negative print sign and treat as positive number */ 00151 if (value < 0) { 00152 /* write sign */ 00153 mbed_minimal_putchar(buffer, length, result, '-', stream); 00154 00155 /* get absolute value using two's complement */ 00156 new_value = ~((MBED_UNSIGNED_STORAGE) value) + 1; 00157 } else { 00158 new_value = value; 00159 } 00160 00161 /* use unsigned long int function */ 00162 mbed_minimal_formatted_string_unsigned(buffer, length, result, new_value, stream); 00163 } 00164 00165 /** 00166 * @brief Print unsigned integer. 00167 * 00168 * @param buffer The buffer to store output (NULL for stdout). 00169 * @param[in] length The length of the buffer. 00170 * @param result The current output location. 00171 * @param[in] value The value to be printed. 00172 */ 00173 static void mbed_minimal_formatted_string_unsigned(char *buffer, size_t length, int *result, MBED_UNSIGNED_STORAGE value, FILE *stream) 00174 { 00175 /* treat 0 as a corner case */ 00176 if (value == 0) { 00177 mbed_minimal_putchar(buffer, length, result, '0', stream); 00178 } else { 00179 /* allocate 3 digits per byte */ 00180 char scratch[sizeof(MBED_UNSIGNED_STORAGE) * 3] = { 0 }; 00181 00182 size_t index = 0; 00183 00184 /* write numbers in reverse order to scratch pad */ 00185 for (; value > 0; index++) { 00186 /* use '0' as base and add digit */ 00187 scratch[index] = '0' + (value % 10); 00188 00189 /* shift value one decimal position */ 00190 value = value / 10; 00191 } 00192 00193 /* write scratch pad to buffer or output */ 00194 for (; index > 0; index--) { 00195 mbed_minimal_putchar(buffer, length, result, scratch[index - 1], stream); 00196 } 00197 } 00198 } 00199 00200 /** 00201 * @brief Print hexadecimal. 00202 * 00203 * @param buffer The buffer to store output (NULL for stdout). 00204 * @param[in] length The length of the buffer. 00205 * @param result The current output location. 00206 * @param[in] value The value to be printed. 00207 * @param upper Flag to print the hexadecimal in upper or lower case. 00208 */ 00209 static void mbed_minimal_formatted_string_hexadecimal(char *buffer, size_t length, int *result, MBED_UNSIGNED_STORAGE value, FILE *stream, bool upper) 00210 { 00211 bool print_leading_zero = false; 00212 00213 for (int index = 7; index >= 0; index--) { 00214 /* get most significant byte */ 00215 uint8_t output = value >> (8 * index); 00216 00217 /* only print leading zeros when set */ 00218 if (print_leading_zero || (output != 0) || (index == 0)) { 00219 unsigned int nibble_one = (output >> 4); 00220 unsigned int nibble_two = (output & 0x0F); 00221 00222 const char int2hex_lower[16] = { '0', '1', '2', '3', '4', '5', '6', '7', 00223 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' 00224 }; 00225 const char int2hex_upper[16] = { '0', '1', '2', '3', '4', '5', '6', '7', 00226 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 00227 }; 00228 const char *int2hex = upper ? int2hex_upper : int2hex_lower; 00229 00230 if (print_leading_zero || nibble_one != 0) { 00231 mbed_minimal_putchar(buffer, length, result, int2hex[nibble_one], stream); 00232 } 00233 mbed_minimal_putchar(buffer, length, result, int2hex[nibble_two], stream); 00234 00235 /* print zeroes after the first non-zero byte */ 00236 print_leading_zero = true; 00237 } 00238 } 00239 } 00240 00241 /** 00242 * @brief Print pointer. 00243 * 00244 * @param buffer The buffer to store output (NULL for stdout). 00245 * @param[in] length The length of the buffer. 00246 * @param result The current output location. 00247 * @param[in] value The pointer to be printed. 00248 */ 00249 static void mbed_minimal_formatted_string_void_pointer(char *buffer, size_t length, int *result, const void *value, FILE *stream) 00250 { 00251 /* write leading 0x */ 00252 mbed_minimal_putchar(buffer, length, result, '0', stream); 00253 mbed_minimal_putchar(buffer, length, result, 'x', stream); 00254 00255 /* write rest as a regular hexadecimal number */ 00256 mbed_minimal_formatted_string_hexadecimal(buffer, length, result, (ptrdiff_t) value, stream, true); 00257 } 00258 00259 #if MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT 00260 /** 00261 * @brief Write double. 00262 * 00263 * @param buffer The buffer to store output (NULL for stdout). 00264 * @param[in] length The length of the buffer. 00265 * @param result The current output location. 00266 * @param[in] value The value to be printed. 00267 */ 00268 static void mbed_minimal_formatted_string_double(char *buffer, size_t length, int *result, double value, FILE *stream) 00269 { 00270 /* get integer part */ 00271 MBED_SIGNED_STORAGE integer = value; 00272 00273 /* write integer part */ 00274 mbed_minimal_formatted_string_signed(buffer, length, result, integer, stream); 00275 00276 /* write decimal point */ 00277 mbed_minimal_formatted_string_character(buffer, length, result, '.', stream); 00278 00279 /* get decimal part */ 00280 double precision = 1.0; 00281 00282 for (size_t index = 0; index < MBED_CONF_PLATFORM_MINIMAL_PRINTF_SET_FLOATING_POINT_MAX_DECIMALS; index++) { 00283 precision *= 10; 00284 } 00285 00286 value = (value - integer) * precision; 00287 00288 /* convert to unsigned integer */ 00289 MBED_UNSIGNED_STORAGE decimal = 0; 00290 00291 if (value < 0) { 00292 MBED_SIGNED_STORAGE temp = value; 00293 decimal = ~((MBED_UNSIGNED_STORAGE) temp) + 1; 00294 } else { 00295 decimal = value; 00296 } 00297 00298 /* round up or down */ 00299 value -= decimal; 00300 00301 if (!((value > -0.5) && (value < 0.5))) { 00302 decimal++; 00303 } 00304 00305 /* convert precision to unsigned integer */ 00306 MBED_UNSIGNED_STORAGE precision_in_uint = precision; 00307 precision_in_uint /= 10; 00308 00309 /* ensure that leading zeros are printed if decimal equals 0 */ 00310 MBED_UNSIGNED_STORAGE val = decimal ? decimal : decimal + 1; 00311 while (precision_in_uint > val) { 00312 /* print leading zeros */ 00313 mbed_minimal_putchar(buffer, length, result, '0', stream); 00314 precision_in_uint /= 10; 00315 } 00316 00317 /* write decimal part */ 00318 mbed_minimal_formatted_string_unsigned(buffer, length, result, decimal, stream); 00319 } 00320 #endif 00321 00322 /** 00323 * @brief Print character. 00324 * 00325 * @param buffer The buffer to store output (NULL for stdout). 00326 * @param[in] length The length of the buffer. 00327 * @param result The current output location. 00328 * @param[in] value The character to be printed. 00329 */ 00330 static void mbed_minimal_formatted_string_character(char *buffer, size_t length, int *result, char character, FILE *stream) 00331 { 00332 /* write character */ 00333 if (buffer) { 00334 mbed_minimal_putchar(buffer, length, result, character, stream); 00335 } else { 00336 /* convert \n to \r\n if enabled in platform configuration */ 00337 #if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES 00338 if (character == '\n' && mbed_stdio_out_prev != '\r') { 00339 mbed_minimal_putchar(buffer, length, result, '\r', stream); 00340 } 00341 00342 /* cache character */ 00343 mbed_stdio_out_prev = character; 00344 #endif 00345 mbed_minimal_putchar(buffer, length, result, character, stream); 00346 } 00347 } 00348 00349 /** 00350 * @brief Print string with precision. 00351 * 00352 * @param buffer The buffer to store output (NULL for stdout). 00353 * @param[in] length The length of the buffer. 00354 * @param result The current output location. 00355 * @param[in] value The string to be printed. 00356 * @param[in] precision The maximum number of characters to be printed. 00357 */ 00358 static void mbed_minimal_formatted_string_string(char *buffer, size_t length, int *result, const char *string, size_t precision, FILE *stream) 00359 { 00360 while ((*string != '\0') && (precision)) { 00361 mbed_minimal_putchar(buffer, length, result, *string, stream); 00362 string++; 00363 precision--; 00364 } 00365 } 00366 00367 /** 00368 * @brief Parse formatted string and invoke write handlers based on type. 00369 * 00370 * @param buffer The buffer to write to, write to stdout if NULL. 00371 * @param[in] length The length of the buffer. 00372 * @param[in] format The formatted string. 00373 * @param[in] arguments The va_list arguments. 00374 * 00375 * @return Number of characters written. 00376 */ 00377 int mbed_minimal_formatted_string(char *buffer, size_t length, const char *format, va_list arguments, FILE *stream) 00378 { 00379 int result = 0; 00380 bool empty_buffer = false; 00381 00382 /* ensure that function wasn't called with an empty buffer, or with or with 00383 a buffer size that is larger than the maximum 'int' value, or with 00384 a NULL format specifier */ 00385 if (format && length <= INT_MAX) { 00386 /* Make sure that there's always space for the NULL terminator */ 00387 if (length > 0) { 00388 length --; 00389 } else { 00390 /* the buffer is empty, there's no place to write the terminator */ 00391 empty_buffer = true; 00392 } 00393 /* parse string */ 00394 for (size_t index = 0; format[index] != '\0'; index++) { 00395 /* format specifier begin */ 00396 if (format[index] == '%') { 00397 size_t next_index = index + 1; 00398 00399 /************************************************************** 00400 * skip and ignore flags [-+(space)#0] 00401 *************************************************************/ 00402 if ((format[next_index] == '-') || 00403 (format[next_index] == '+') || 00404 (format[next_index] == ' ') || 00405 (format[next_index] == '#') || 00406 (format[next_index] == '0')) { 00407 /* skip to next character */ 00408 next_index++; 00409 } 00410 00411 /************************************************************** 00412 * skip and ignore width [(number)*] 00413 *************************************************************/ 00414 if (format[next_index] == '*') { 00415 /* skip to next character */ 00416 next_index++; 00417 00418 /* discard argument */ 00419 va_arg(arguments, MBED_SIGNED_NATIVE_TYPE); 00420 } else { 00421 while ((format[next_index] >= '0') && 00422 (format[next_index] <= '9')) { 00423 /* skip to next character */ 00424 next_index++; 00425 } 00426 } 00427 00428 /************************************************************** 00429 * look for precision modifier 00430 *************************************************************/ 00431 int precision = PRECISION_DEFAULT; 00432 00433 if ((format[next_index] == '.') && 00434 (format[next_index + 1] == '*')) { 00435 next_index += 2; 00436 00437 /* read precision from argument list */ 00438 precision = va_arg(arguments, MBED_SIGNED_NATIVE_TYPE); 00439 } else if (format[next_index] == '.') { 00440 /* precision modifier found, reset default to 0 and increment index */ 00441 next_index++; 00442 precision = 0; 00443 00444 /* parse precision until not a decimal */ 00445 size_t inner_index = 0; 00446 00447 while ((format[next_index + inner_index] >= '0') && 00448 (format[next_index + inner_index] <= '9')) { 00449 precision = precision * 10 + (format[next_index + inner_index] - '0'); 00450 00451 inner_index++; 00452 } 00453 00454 /* move index forward to point at next character */ 00455 next_index += inner_index; 00456 } 00457 00458 /************************************************************** 00459 * look for length modifier, default to NONE 00460 *************************************************************/ 00461 length_t length_modifier = LENGTH_NONE; 00462 00463 /* look for two character length modifier */ 00464 if ((format[next_index] == 'h') && (format[next_index + 1] == 'h')) { 00465 length_modifier = LENGTH_HH; 00466 } else if ((format[next_index] == 'l') && (format[next_index + 1] == 'l')) { 00467 length_modifier = LENGTH_LL; 00468 } 00469 /* look for one character length modifier if two character search failed */ 00470 else if (format[next_index] == 'h') { 00471 length_modifier = LENGTH_H; 00472 } else if (format[next_index] == 'l') { 00473 length_modifier = LENGTH_L; 00474 } else if (format[next_index] == 'j') { 00475 length_modifier = LENGTH_J; 00476 } else if (format[next_index] == 'z') { 00477 length_modifier = LENGTH_Z; 00478 } else if (format[next_index] == 't') { 00479 length_modifier = LENGTH_T; 00480 } else if (format[next_index] == 'L') { 00481 length_modifier = LENGTH_CAPITAL_L; 00482 } 00483 00484 /* increment index, length is encoded in modifier enum */ 00485 next_index += (length_modifier & 0x0F); 00486 00487 /************************************************************** 00488 * read out character - this is a supported format character, 00489 * '\0', or a not suported character 00490 *************************************************************/ 00491 char next = format[next_index]; 00492 00493 /* signed integer */ 00494 if ((next == 'd') || (next == 'i')) { 00495 MBED_SIGNED_STORAGE value = 0; 00496 00497 #if MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_64_BIT 00498 /* if 64 bit is enabled and the integer types are larger than the native type */ 00499 if (((length_modifier == LENGTH_LL) && (sizeof(long long int) > sizeof(MBED_SIGNED_NATIVE_TYPE))) || 00500 ((length_modifier == LENGTH_L) && (sizeof(long int) > sizeof(MBED_SIGNED_NATIVE_TYPE))) || 00501 ((length_modifier == LENGTH_NONE) && (sizeof(int) > sizeof(MBED_SIGNED_NATIVE_TYPE)))) { 00502 /* use 64 bit storage type for readout */ 00503 value = va_arg(arguments, MBED_SIGNED_STORAGE); 00504 } else 00505 #endif 00506 { 00507 /* use native storage type (which can be 32 or 64 bit) */ 00508 value = va_arg(arguments, MBED_SIGNED_NATIVE_TYPE); 00509 } 00510 00511 /* constrict value based on lenght modifier */ 00512 switch (length_modifier) { 00513 case LENGTH_NONE: 00514 value = (int) value; 00515 break; 00516 case LENGTH_HH: 00517 value = (signed char) value; 00518 break; 00519 case LENGTH_H: 00520 value = (short int) value; 00521 break; 00522 case LENGTH_L: 00523 value = (long int) value; 00524 break; 00525 case LENGTH_LL: 00526 value = (long long int) value; 00527 break; 00528 case LENGTH_J: 00529 value = (intmax_t) value; 00530 break; 00531 case LENGTH_T: 00532 value = (ptrdiff_t) value; 00533 break; 00534 default: 00535 break; 00536 } 00537 00538 index = next_index; 00539 00540 mbed_minimal_formatted_string_signed(buffer, length, &result, value, stream); 00541 } 00542 /* unsigned integer */ 00543 else if ((next == 'u') || (next == 'x') || (next == 'X')) { 00544 MBED_UNSIGNED_STORAGE value = 0; 00545 00546 #if MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_64_BIT 00547 /* if 64 bit is enabled and the integer types are larger than the native type */ 00548 if (((length_modifier == LENGTH_LL) && (sizeof(unsigned long long int) > sizeof(MBED_UNSIGNED_NATIVE_TYPE))) || 00549 ((length_modifier == LENGTH_L) && (sizeof(unsigned long int) > sizeof(MBED_UNSIGNED_NATIVE_TYPE))) || 00550 ((length_modifier == LENGTH_NONE) && (sizeof(unsigned int) > sizeof(MBED_UNSIGNED_NATIVE_TYPE)))) { 00551 /* use 64 bit storage type for readout */ 00552 value = va_arg(arguments, MBED_UNSIGNED_STORAGE); 00553 } else 00554 #endif 00555 { 00556 /* use native storage type (which can be 32 or 64 bit) */ 00557 value = va_arg(arguments, MBED_UNSIGNED_NATIVE_TYPE); 00558 } 00559 00560 /* constrict value based on lenght modifier */ 00561 switch (length_modifier) { 00562 case LENGTH_NONE: 00563 value = (unsigned int) value; 00564 break; 00565 case LENGTH_HH: 00566 value = (unsigned char) value; 00567 break; 00568 case LENGTH_H: 00569 value = (unsigned short int) value; 00570 break; 00571 case LENGTH_L: 00572 value = (unsigned long int) value; 00573 break; 00574 case LENGTH_LL: 00575 value = (unsigned long long int) value; 00576 break; 00577 case LENGTH_J: 00578 value = (uintmax_t) value; 00579 break; 00580 case LENGTH_Z: 00581 value = (size_t) value; 00582 break; 00583 case LENGTH_T: 00584 value = (ptrdiff_t) value; 00585 break; 00586 default: 00587 break; 00588 } 00589 00590 index = next_index; 00591 00592 /* write unsigned or hexadecimal */ 00593 if (next == 'u') { 00594 mbed_minimal_formatted_string_unsigned(buffer, length, &result, value, stream); 00595 } else { 00596 mbed_minimal_formatted_string_hexadecimal(buffer, length, &result, value, stream, next == 'X'); 00597 } 00598 } 00599 #if MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT 00600 /* treat all floating points the same */ 00601 else if ((next == 'f') || (next == 'F') || (next == 'g') || (next == 'G')) { 00602 double value = va_arg(arguments, double); 00603 index = next_index; 00604 00605 mbed_minimal_formatted_string_double(buffer, length, &result, value, stream); 00606 } 00607 #endif 00608 /* character */ 00609 else if (next == 'c') { 00610 char value = va_arg(arguments, MBED_SIGNED_NATIVE_TYPE); 00611 index = next_index; 00612 00613 mbed_minimal_formatted_string_character(buffer, length, &result, value, stream); 00614 } 00615 /* string */ 00616 else if (next == 's') { 00617 char *value = va_arg(arguments, char *); 00618 index = next_index; 00619 00620 mbed_minimal_formatted_string_string(buffer, length, &result, value, precision, stream); 00621 } 00622 /* pointer */ 00623 else if (next == 'p') { 00624 void *value = va_arg(arguments, void *); 00625 index = next_index; 00626 00627 mbed_minimal_formatted_string_void_pointer(buffer, length, &result, value, stream); 00628 } else { 00629 // Unrecognised, or `%%`. Print the `%` that led us in. 00630 mbed_minimal_formatted_string_character(buffer, length, &result, '%', stream); 00631 if (next == '%') { 00632 // Continue printing loop after `%%` 00633 index = next_index; 00634 } 00635 // Otherwise we continue the printing loop after the leading `%`, so an 00636 // unrecognised thing like "Blah = %a" will just come out as "Blah = %a" 00637 } 00638 } else 00639 /* not a format specifier */ 00640 { 00641 /* write normal character */ 00642 mbed_minimal_formatted_string_character(buffer, length, &result, format[index], stream); 00643 } 00644 } 00645 00646 if (buffer && !empty_buffer) { 00647 /* NULL-terminate the buffer no matter what. We use '<=' to compare instead of '<' 00648 because we know that we initially reserved space for '\0' by decrementing length */ 00649 if ((size_t)result <= length) { 00650 buffer[result] = '\0'; 00651 } else { 00652 buffer[length] = '\0'; 00653 } 00654 } 00655 } 00656 00657 return result; 00658 } 00659
Generated on Tue Jul 12 2022 13:54:33 by
