Fahad Mirza / Mbed 2 deprecated Nucleo_HXC900

Dependencies:   mbed

Revision:
5:53302861bfea
Parent:
0:a0c5877bd360
diff -r 511677d804ac -r 53302861bfea Utilities/tiny_vsnprintf.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Utilities/tiny_vsnprintf.c	Mon Jul 16 20:12:42 2018 +0000
@@ -0,0 +1,723 @@
+/******************************************************************************
+ * @file    tiny_vsnprintf.c
+ * @author  MCD Application Team
+ * @version V1.1.4
+ * @date    08-January-2018
+ * @brief   Tiny implementation of vsnprintf like function
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; Copyright (c) 2017 STMicroelectronics International N.V.
+ * All rights reserved.</center></h2>
+ *
+ * Copyright (c) 1990, 1993
+ *  The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted, provided that the following conditions are met:
+ *
+ * 1. Redistribution of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of other
+ *    contributors to this software may be used to endorse or promote products
+ *    derived from this software without specific written permission.
+ * 4. This software, including modifications and/or derivative works of this
+ *    software, must execute solely and exclusively on microcontroller or
+ *    microprocessor devices manufactured by or for STMicroelectronics.
+ * 5. Redistribution and use of this software other than as permitted under
+ *    this license is void and will automatically terminate your rights under
+ *    this license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
+ * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
+ * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* File : barebones/ee_printf.c
+  This file contains an implementation of ee_printf that only requires a method to output a char to a UART without pulling in library code.
+This code is based on a file that contains the following:
+ Copyright (C) 2002 Michael Ringgaard. All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 
+ 1. Redistributions of source code must retain the above copyright 
+    notice, this list of conditions and the following disclaimer.  
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.  
+ 3. Neither the name of the project nor the names of its contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission. 
+ 
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
+ SUCH DAMAGE.
+*/
+
+/*
+ * Following implementation is adapted from original one
+ *   https://github.com/jpbonn/coremark_lm32/blob/master/ee_printf.c
+ */
+
+#define TINY_PRINTF
+
+#include <stdarg.h>
+#include <string.h>
+#include "tiny_vsnprintf.h"
+
+#define ZEROPAD    (1<<0)  /* Pad with zero */
+#define SIGN      (1<<1)  /* Unsigned/signed long */
+#define UPPERCASE   (1<<6)  /* 'ABCDEF' */
+#ifdef TINY_PRINTF
+#else
+#define PLUS      (1<<2)  /* Show plus */
+#define HEX_PREP   (1<<5)  /* 0x */
+#define SPACE     (1<<3)  /* Spacer */
+#define LEFT      (1<<4)  /* Left justified */
+#endif
+
+#define is_digit(c) ((c) >= '0' && (c) <= '9')
+
+static char *lower_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+#ifdef TINY_PRINTF
+#else
+static size_t strnlen(const char *s, size_t count);
+
+static size_t strnlen(const char *s, size_t count)
+{
+  const char *sc;
+  for (sc = s; *sc != '\0' && count--; ++sc);
+  return sc - s;
+}
+#endif
+
+static int ee_skip_atoi(const char **s)
+{
+  int i = 0;
+  while (is_digit(**s)) i = i*10 + *((*s)++) - '0';
+  return i;
+}
+
+#define ASSIGN_STR(_c)  do { *str++ = (_c); max_size--; if (max_size == 0) return str; } while (0)
+
+static char *ee_number(char *str, int max_size, long num, int base, int size, int precision, int type)
+{
+  char c;
+  char sign, tmp[66];
+  char *dig = lower_digits;
+  int i;
+
+  if (type & UPPERCASE)  dig = upper_digits;
+#ifdef TINY_PRINTF
+#else
+  if (type & LEFT) type &= ~ZEROPAD;
+#endif
+  if (base < 2 || base > 36) return 0;
+  
+  c = (type & ZEROPAD) ? '0' : ' ';
+  sign = 0;
+  if (type & SIGN)
+  {
+    if (num < 0)
+    {
+      sign = '-';
+      num = -num;
+      size--;
+    }
+#ifdef TINY_PRINTF
+#else
+    else if (type & PLUS)
+    {
+      sign = '+';
+      size--;
+    }
+    else if (type & SPACE)
+    {
+      sign = ' ';
+      size--;
+    }
+#endif
+  }
+
+#ifdef TINY_PRINTF
+#else
+  if (type & HEX_PREP)
+  {
+    if (base == 16)
+      size -= 2;
+    else if (base == 8)
+      size--;
+  }
+#endif
+  
+  i = 0;
+
+  if (num == 0)
+    tmp[i++] = '0';
+  else
+  {
+    while (num != 0)
+    {
+      tmp[i++] = dig[((unsigned long) num) % (unsigned) base];
+      num = ((unsigned long) num) / (unsigned) base;
+    }
+  }
+
+  if (i > precision) precision = i;
+  size -= precision;
+  if (!(type & (ZEROPAD /* TINY option   | LEFT */))) while (size-- > 0) ASSIGN_STR(' ');
+  if (sign) ASSIGN_STR(sign);
+  
+#ifdef TINY_PRINTF
+#else
+  if (type & HEX_PREP)
+  {
+    if (base == 8)
+      ASSIGN_STR('0');
+    else if (base == 16)
+    {
+      ASSIGN_STR('0');
+      ASSIGN_STR(lower_digits[33]);
+    }
+  }
+#endif
+  
+#ifdef TINY_PRINTF
+  while (size-- > 0) ASSIGN_STR(c);
+#else
+  if (!(type & LEFT)) while (size-- > 0) ASSIGN_STR(c);
+#endif
+  while (i < precision--) ASSIGN_STR('0');
+  while (i-- > 0) ASSIGN_STR(tmp[i]);
+  while (size-- > 0) ASSIGN_STR(' ');
+
+  return str;
+}
+
+#ifdef TINY_PRINTF
+#else
+static char *eaddr(char *str, unsigned char *addr, int size, int precision, int type)
+{
+  char tmp[24];
+  char *dig = lower_digits;
+  int i, len;
+
+  if (type & UPPERCASE)  dig = upper_digits;
+  len = 0;
+  for (i = 0; i < 6; i++)
+  {
+    if (i != 0) tmp[len++] = ':';
+    tmp[len++] = dig[addr[i] >> 4];
+    tmp[len++] = dig[addr[i] & 0x0F];
+  }
+
+  if (!(type & LEFT)) while (len < size--) *str++ = ' ';
+  for (i = 0; i < len; ++i) *str++ = tmp[i];
+  while (len < size--) *str++ = ' ';
+
+  return str;
+}
+
+static char *iaddr(char *str, unsigned char *addr, int size, int precision, int type)
+{
+  char tmp[24];
+  int i, n, len;
+
+  len = 0;
+  for (i = 0; i < 4; i++)
+  {
+    if (i != 0) tmp[len++] = '.';
+    n = addr[i];
+    
+    if (n == 0)
+      tmp[len++] = lower_digits[0];
+    else
+    {
+      if (n >= 100) 
+      {
+        tmp[len++] = lower_digits[n / 100];
+        n = n % 100;
+        tmp[len++] = lower_digits[n / 10];
+        n = n % 10;
+      }
+      else if (n >= 10) 
+      {
+        tmp[len++] = lower_digits[n / 10];
+        n = n % 10;
+      }
+
+      tmp[len++] = lower_digits[n];
+    }
+  }
+
+  if (!(type & LEFT)) while (len < size--) *str++ = ' ';
+  for (i = 0; i < len; ++i) *str++ = tmp[i];
+  while (len < size--) *str++ = ' ';
+
+  return str;
+}
+#endif
+
+#ifdef HAS_FLOAT
+
+char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf);
+char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf);
+static void ee_bufcpy(char *d, char *s, int count); 
+ 
+void ee_bufcpy(char *pd, char *ps, int count) {
+  char *pe=ps+count;
+  while (ps!=pe)
+    *pd++=*ps++;
+}
+
+static void parse_float(double value, char *buffer, char fmt, int precision)
+{
+  int decpt, sign, exp, pos;
+  char *fdigits = NULL;
+  char cvtbuf[80];
+  int capexp = 0;
+  int magnitude;
+
+  if (fmt == 'G' || fmt == 'E')
+  {
+    capexp = 1;
+    fmt += 'a' - 'A';
+  }
+
+  if (fmt == 'g')
+  {
+    fdigits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf);
+    magnitude = decpt - 1;
+    if (magnitude < -4  ||  magnitude > precision - 1)
+    {
+      fmt = 'e';
+      precision -= 1;
+    }
+    else
+    {
+      fmt = 'f';
+      precision -= decpt;
+    }
+  }
+
+  if (fmt == 'e')
+  {
+    fdigits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf);
+
+    if (sign) *buffer++ = '-';
+    *buffer++ = *fdigits;
+    if (precision > 0) *buffer++ = '.';
+    ee_bufcpy(buffer, fdigits + 1, precision);
+    buffer += precision;
+    *buffer++ = capexp ? 'E' : 'e';
+
+    if (decpt == 0)
+    {
+      if (value == 0.0)
+        exp = 0;
+      else
+        exp = -1;
+    }
+    else
+      exp = decpt - 1;
+
+    if (exp < 0)
+    {
+      *buffer++ = '-';
+      exp = -exp;
+    }
+    else
+      *buffer++ = '+';
+
+    buffer[2] = (exp % 10) + '0';
+    exp = exp / 10;
+    buffer[1] = (exp % 10) + '0';
+    exp = exp / 10;
+    buffer[0] = (exp % 10) + '0';
+    buffer += 3;
+  }
+  else if (fmt == 'f')
+  {
+    fdigits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf);
+    if (sign) *buffer++ = '-';
+    if (*fdigits)
+    {
+      if (decpt <= 0)
+      {
+        *buffer++ = '0';
+        *buffer++ = '.';
+        for (pos = 0; pos < -decpt; pos++) *buffer++ = '0';
+        while (*fdigits) *buffer++ = *fdigits++;
+      }
+      else
+      {
+        pos = 0;
+        while (*fdigits)
+        {
+          if (pos++ == decpt) *buffer++ = '.';
+          *buffer++ = *fdigits++;
+        }
+      }
+    }
+    else
+    {
+      *buffer++ = '0';
+      if (precision > 0)
+      {
+        *buffer++ = '.';
+        for (pos = 0; pos < precision; pos++) *buffer++ = '0';
+      }
+    }
+  }
+
+  *buffer = '\0';
+}
+
+static void decimal_point(char *buffer)
+{
+  while (*buffer)
+  {
+    if (*buffer == '.') return;
+    if (*buffer == 'e' || *buffer == 'E') break;
+    buffer++;
+  }
+
+  if (*buffer)
+  {
+    int n = strnlen(buffer,256);
+    while (n > 0) 
+    {
+      buffer[n + 1] = buffer[n];
+      n--;
+    }
+
+    *buffer = '.';
+  }
+  else
+  {
+    *buffer++ = '.';
+    *buffer = '\0';
+  }
+}
+
+static void cropzeros(char *buffer)
+{
+  char *stop;
+
+  while (*buffer && *buffer != '.') buffer++;
+  if (*buffer++)
+  {
+    while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++;
+    stop = buffer--;
+    while (*buffer == '0') buffer--;
+    if (*buffer == '.') buffer--;
+    while (buffer!=stop)
+    *++buffer=0;
+  }
+}
+
+static char *flt(char *str, double num, int size, int precision, char fmt, int flags)
+{
+  char tmp[80];
+  char c, sign;
+  int n, i;
+
+  // Left align means no zero padding
+#ifdef TINY_PRINTF
+#else
+  if (flags & LEFT) flags &= ~ZEROPAD;
+#endif
+  
+  // Determine padding and sign char
+  c = (flags & ZEROPAD) ? '0' : ' ';
+  sign = 0;
+  if (flags & SIGN)
+  {
+    if (num < 0.0)
+    {
+      sign = '-';
+      num = -num;
+      size--;
+    }
+#ifdef TINY_PRINTF
+#else
+    else if (flags & PLUS)
+    {
+      sign = '+';
+      size--;
+    }
+    else if (flags & SPACE)
+    {
+      sign = ' ';
+      size--;
+    }
+#endif
+  }
+
+  // Compute the precision value
+  if (precision < 0)
+    precision = 6; // Default precision: 6
+
+  // Convert floating point number to text
+  parse_float(num, tmp, fmt, precision);
+
+#ifdef TINY_PRINTF
+#else
+  if ((flags & HEX_PREP) && precision == 0) decimal_point(tmp);
+#endif
+  if (fmt == 'g' && !(flags & HEX_PREP)) cropzeros(tmp);
+
+  n = strnlen(tmp,256);
+
+  // Output number with alignment and padding
+  size -= n;
+  if (!(flags & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' ';
+  if (sign) *str++ = sign;
+  if (!(flags & LEFT)) while (size-- > 0) *str++ = c;
+  for (i = 0; i < n; i++) *str++ = tmp[i];
+  while (size-- > 0) *str++ = ' ';
+
+  return str;
+}
+
+#endif
+
+#define CHECK_STR_SIZE(_buf, _str, _size) \
+  if ((((_str) - (_buf)) >= ((_size)-1))) { break; }
+
+int tiny_vsnprintf_like(char *buf, const int size, const char *fmt, va_list args)
+{
+  unsigned long num;
+  int base;
+  char *str;
+  int len;
+  int i;
+  char *s;
+  
+  int flags;            // Flags to number()
+
+  int field_width;      // Width of output field
+  int precision;        // Min. # of digits for integers; max number of chars for from string
+  int qualifier;        // 'h', 'l', or 'L' for integer fields
+
+  if (size <= 0)
+  {
+    return 0;
+  }
+  
+  for (str = buf; *fmt || ((str - buf) >= size-1); fmt++)
+  {
+    CHECK_STR_SIZE(buf, str, size);
+    
+    if (*fmt != '%')
+    {
+      *str++ = *fmt;
+      continue;
+    }
+                  
+    // Process flags
+    flags = 0;
+#ifdef TINY_PRINTF
+    /* Support %0, but not %-, %+, %space and %# */
+    fmt++;
+    if (*fmt == '0')
+    {
+      flags |= ZEROPAD;
+    }
+#else
+repeat:
+    fmt++; // This also skips first '%'
+    switch (*fmt)
+    {
+      case '-': flags |= LEFT; goto repeat;
+      case '+': flags |= PLUS; goto repeat;
+      case ' ': flags |= SPACE; goto repeat;
+      case '#': flags |= HEX_PREP; goto repeat;
+      case '0': flags |= ZEROPAD; goto repeat;
+    }
+#endif
+    
+    // Get field width
+    field_width = -1;
+    if (is_digit(*fmt))
+      field_width = ee_skip_atoi(&fmt);
+#ifdef TINY_PRINTF
+    /* Does not support %* */
+#else
+    else if (*fmt == '*')
+    {
+      fmt++;
+      field_width = va_arg(args, int);
+      if (field_width < 0)
+      {
+        field_width = -field_width;
+        flags |= LEFT;
+      }
+    }
+#endif
+    
+    // Get the precision
+    precision = -1;
+#ifdef TINY_PRINTF
+    /* Does not support %. */
+#else    
+    if (*fmt == '.')
+    {
+      ++fmt;    
+      if (is_digit(*fmt))
+        precision = ee_skip_atoi(&fmt);
+      else if (*fmt == '*')
+      {
+        ++fmt;
+        precision = va_arg(args, int);
+      }
+      if (precision < 0) precision = 0;
+    }
+#endif
+    
+    // Get the conversion qualifier
+    qualifier = -1;
+
+    if (*fmt == 'l' || *fmt == 'L')
+    {
+      qualifier = *fmt;
+      fmt++;
+    }
+
+    
+    // Default base
+    base = 10;
+
+    switch (*fmt)
+    {
+      case 'c':
+#ifdef TINY_PRINTF
+#else
+        if (!(flags & LEFT))
+#endif
+          while (--field_width > 0) *str++ = ' ';
+        *str++ = (unsigned char) va_arg(args, int);
+#ifdef TINY_PRINTF
+#else
+        while (--field_width > 0) *str++ = ' ';
+#endif
+        continue;
+
+      case 's':
+        s = va_arg(args, char *);
+        if (!s) s = "<NULL>";
+#ifdef TINY_PRINTF
+        len = strlen(s);
+#else
+        len = strnlen(s, precision);
+        if (!(flags & LEFT))
+#endif
+          while (len < field_width--) *str++ = ' ';
+        for (i = 0; i < len; ++i) *str++ = *s++;
+#ifdef TINY_PRINTF
+#else        
+        while (len < field_width--) *str++ = ' ';
+#endif
+        continue;
+
+#ifdef TINY_PRINTF
+      /* Does not support %p, %A, %a, %o */
+#else
+      case 'p':
+        if (field_width == -1)
+        {
+          field_width = 2 * sizeof(void *);
+          flags |= ZEROPAD;
+        }
+        str = ee_number(str, (size - (str - buf)), (unsigned long) va_arg(args, void *), 16, field_width, precision, flags);
+        continue;
+
+      case 'A':
+        flags |= UPPERCASE;
+
+      case 'a':
+        if (qualifier == 'l')
+          str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
+        else
+          str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
+        continue;
+
+      // Integer number formats - set up the flags and "break"
+      case 'o':
+        base = 8;
+        break;
+#endif
+      
+      case 'X':
+        flags |= UPPERCASE;
+
+      case 'x':
+        base = 16;
+        break;
+
+      case 'd':
+      case 'i':
+        flags |= SIGN;
+
+      case 'u':
+        break;
+
+#ifdef HAS_FLOAT
+
+      case 'f':
+        str = flt(str, va_arg(args, double), field_width, precision, *fmt, flags | SIGN);
+        continue;
+
+#endif
+
+      default:
+        if (*fmt != '%') *str++ = '%';
+        CHECK_STR_SIZE(buf, str, size);
+        if (*fmt)
+          *str++ = *fmt;
+        else
+          --fmt;
+        CHECK_STR_SIZE(buf, str, size);
+        continue;
+    }
+
+    if (qualifier == 'l')
+      num = va_arg(args, unsigned long);
+    else if (flags & SIGN)
+      num = va_arg(args, int);
+    else
+      num = va_arg(args, unsigned int);
+
+    str = ee_number(str, ((size - 1) - (str - buf)), num, base, field_width, precision, flags);
+  }
+
+  *str = '\0';
+  return str - buf;
+}
+