Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_printf_implementation.c Source File

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