text: /**************************************************************************
  *
  * Copyright (c) 2017, Pelion and affiliates.
  * SPDX-License-Identifier: Apache-2.0
  * Copyright 2011-2016 by Andrey Butok. FNET Community.
  * Copyright 2008-2010 by Freescale Semiconductor, Inc.
  * Copyright 2003 by Motorola SPS.
  *
  ***************************************************************************
  *
  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
  *  not use this file except in compliance with the License.
  *  You may obtain a copy of the License at
  *
  *  http://www.apache.org/licenses/LICENSE-2.0
  *
  *  Unless required by applicable law or agreed to in writing, software
  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  *
  **********************************************************************/
  /*!
  *
  * @file fnet_stdlib.c
  *
  * @brief Standard functions implementation.
  *
  ***************************************************************************/
  
  #include "fnet.h"
  
  static fnet_uint32_t fnet_rand_value;  /* Used by fnet_rand()*/
  
  #if !FNET_CFG_OVERLOAD_MEMCPY
  /************************************************************************
  * DESCRIPTION:
  *************************************************************************/
  #if 0
  /* Slowest && Smallest */
  void fnet_memcpy( FNET_COMP_PACKED_VAR void *dest, FNET_COMP_PACKED_VAR const void *src, fnet_size_t n )
  {
      const fnet_uint8_t  *p = (fnet_uint8_t *)src;
      fnet_uint8_t        *q = (fnet_uint8_t *)dest;
  
      for (n++; --n; )
      {
          *q++ = *p++;
      }
  }
  #elif 0 /* Faster. */
  void fnet_memcpy (FNET_COMP_PACKED_VAR void *dest, FNET_COMP_PACKED_VAR const void *src, fnet_size_t n)
  {
      fnet_size_t                         longs;
      fnet_size_t                         bytes;
      FNET_COMP_PACKED_VAR fnet_uint32_t  *dpl = (fnet_uint32_t *)dest;
      FNET_COMP_PACKED_VAR fnet_uint32_t  *spl = (fnet_uint32_t *)src;
      fnet_uint8_t                        *dpb, *spb;
  
      bytes = (n & 0x3);
      longs = ((n - bytes) >> 2);
  
      for (longs++; --longs;)
      {
          *dpl++ = *spl++;
      }
  
      dpb = (fnet_uint8_t *)dpl;
      spb = (fnet_uint8_t *)spl;
  
      for (bytes++; --bytes;)
      {
          *dpb++ = *spb++;
      }
  }
  #else /* Fastest & Biggest. */
  void fnet_memcpy(FNET_COMP_PACKED_VAR void *to_ptr, FNET_COMP_PACKED_VAR const void *from_ptr, fnet_size_t number_of_bytes)
  {
      const fnet_uint8_t                          *from8_ptr = (const fnet_uint8_t *) from_ptr;
      fnet_uint8_t                                *to8_ptr = (fnet_uint8_t *) to_ptr;
      FNET_COMP_PACKED_VAR const fnet_uint16_t    *from16_ptr = (const fnet_uint16_t *) from_ptr;
      FNET_COMP_PACKED_VAR fnet_uint16_t          *to16_ptr = (fnet_uint16_t *) to_ptr;
      FNET_COMP_PACKED_VAR const fnet_uint32_t    *from32_ptr = (const fnet_uint32_t *) from_ptr;
      FNET_COMP_PACKED_VAR fnet_uint32_t          *to32_ptr = (fnet_uint32_t *) to_ptr;
      fnet_index_t                                loops;
  
      /*
      * The copying is optimized to avoid alignment problems, and attempts
      *               to copy 32bit numbers optimally.
      */
      if (number_of_bytes > 3u)
      {
          /* Try to align source on word */
          if (((uintptr_t)from_ptr & 1u) != 0u)
          {
              from8_ptr = (const fnet_uint8_t *) from_ptr;
              to8_ptr = (fnet_uint8_t *) to_ptr;
  
              *to8_ptr++ = *from8_ptr++;
  
              from_ptr = from8_ptr;
              to_ptr = to8_ptr;
              --number_of_bytes;
          }
  
          /* Try to align source on longword */
          if ((((uintptr_t)from_ptr) & 2u) != 0u)
          {
              from16_ptr = (const fnet_uint16_t *) from_ptr;
              to16_ptr = (fnet_uint16_t *) to_ptr;
  
              *to16_ptr++ = *from16_ptr++;
  
              from_ptr = from16_ptr;
              to_ptr = to16_ptr;
              number_of_bytes -= 2u;
          }
  
          from32_ptr = (const fnet_uint32_t *) from_ptr;
          to32_ptr = (fnet_uint32_t *) to_ptr;
  
          /*
          ** To increase performance a bit, we will copy 64 bytes (16 * longwords) sequentially
          ** This gets less instruction cycles.
          */
          for (loops = (number_of_bytes >> 6u); loops > 0u; loops--)
          {
              /* copy 16 longwords */
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
              *to32_ptr++ = *from32_ptr++;
          }
  
          /* Now, write the rest of bytes */
          for (loops = ((number_of_bytes >> 2) & 0xFu); loops > 0u; loops--)
          {
              *to32_ptr++ = *from32_ptr++;
          }
  
          from_ptr = from32_ptr;
          to_ptr = to32_ptr;
      }
  
      /* Copy all remaining bytes */
      if ((number_of_bytes & 2u) != 0u)
      {
          from16_ptr = (const fnet_uint16_t *) from_ptr;
          to16_ptr = (fnet_uint16_t *) to_ptr;
  
          *to16_ptr++ = *from16_ptr++;
  
          from_ptr = from16_ptr;
          to_ptr = to16_ptr;
      }
  
      if ((number_of_bytes & 1u) != 0u)
      {
          * (fnet_uint8_t *) to_ptr = * (const fnet_uint8_t *) from_ptr;
      }
  }
  #endif
  
  #endif
  
  /************************************************************************
  * DESCRIPTION: Copy function to other location.
  *              Used for relocate function from Flash to RAM
  *
  *************************************************************************/
  void *fnet_memcpy_func(void *to_buf_ptr, const void *from_func_ptr, fnet_size_t to_buf_size)
  {
  
      fnet_memcpy(to_buf_ptr, (void *)FNET_CPU_INSTRUCTION_TO_ADDR(from_func_ptr), to_buf_size);
  
      return (void *)FNET_CPU_ADDR_TO_INSTRUCTION(to_buf_ptr);
  }
  
  /************************************************************************
  * DESCRIPTION:
  *************************************************************************/
  void fnet_memset( void *dest, fnet_uint8_t value, fnet_size_t n )
  {
      /* Not optimized */
      fnet_uint8_t *sp = (fnet_uint8_t *)dest;
  
      while(n)
      {
          *sp++ = (fnet_uint8_t)value;
          n--;
      }
  }
  
  /************************************************************************
  * DESCRIPTION: Same as "fnet_memset( void *s, 0, unsigned n )"
  *************************************************************************/
  void fnet_memset_zero( void *dest, fnet_size_t n )
  {
      /* Not optimized */
      fnet_uint8_t *sp = (fnet_uint8_t *)dest;
  
      while(n)
      {
          *sp++ = 0u;
          n--;
      }
  }
  
  /************************************************************************
  * DESCRIPTION: Compare two memory regions and return zero if they are identical,
  *              non-zero otherwise.  If count is zero, return zero.
  *************************************************************************/
  fnet_int32_t fnet_memcmp(const void *src1, const void *src2, fnet_size_t count )
  {
      const fnet_uint8_t *p1 = (const fnet_uint8_t *)src1;
      const fnet_uint8_t *p2 = (const fnet_uint8_t *)src2;
  
      while(count)
      {
          if(*p1++ != *p2++)
          {
              return 1;
          }
          count--;
      }
  
      return (0);
  }
  
  /************************************************************************
  * DESCRIPTION:
  *************************************************************************/
  fnet_int32_t fnet_strcmp( const fnet_char_t *str1, const fnet_char_t *str2 )
  {
      /* No checks for 0 */
      const fnet_char_t *s1p = str1;
      const fnet_char_t *s2p = str2;
  
      while(*s2p != '\0')
      {
          if(*s1p != *s2p)
          {
              break;
          }
  
          ++s1p;
          ++s2p;
      }
  
      return (fnet_int32_t)(*s1p - *s2p);
  }
  
  /************************************************************************
  * DESCRIPTION: Calculates the length of a string.
  *************************************************************************/
  fnet_size_t fnet_strlen (const fnet_char_t *str)
  {
      const fnet_char_t  *s = str;
      fnet_size_t         len = 0U;
  
      if (s == 0)
      {
          return 0U;
      }
  
      while (*s++ != '\0')
      {
          ++len;
      }
  
      return len;
  }
  
  /************************************************************************
  * DESCRIPTION:
  *************************************************************************/
  void fnet_strcat (fnet_char_t *dest, const fnet_char_t *src)
  {
      fnet_char_t        *dp;
      const fnet_char_t  *sp = src;
  
      if ((dest != 0) && (src != 0))
      {
          dp = &dest[fnet_strlen(dest)];
  
          while (*sp != '\0')
          {
              *dp++ = *sp++;
          }
          *dp = '\0';
      }
  }
  
  /************************************************************************
  * DESCRIPTION:
  *************************************************************************/
  void fnet_strncat (fnet_char_t *dest, const fnet_char_t *src, fnet_size_t n)
  {
      fnet_char_t        *dp;
      const fnet_char_t  *sp = src;
  
      if ((dest != 0) && (src != 0) && (n > 0U))
      {
          dp = &dest[fnet_strlen(dest)];
  
          while((*sp != '\0') && (n > 0u))
          {
              *dp++ = *sp++;
              n--;
          }
          *dp = '\0';
      }
  }
  
  /************************************************************************
  * DESCRIPTION:
  *************************************************************************/
  void fnet_strcpy (fnet_char_t *dest, const fnet_char_t *src)
  {
      fnet_char_t        *dp = dest;
      const fnet_char_t  *sp = src;
  
      if ((dest != 0) && (src != 0))
      {
          while (*sp != '\0')
          {
              *dp++ = *sp++;
          }
          *dp = '\0';
      }
  }
  
  /************************************************************************
  * DESCRIPTION:
  *************************************************************************/
  void fnet_strncpy( fnet_char_t *dest, const fnet_char_t *src, fnet_size_t n )
  {
      fnet_char_t        *dp = dest;
      const fnet_char_t  *sp = src;
  
      if((dest != 0) && (src != 0) && (n > 0u))
      {
          while((*sp != '\0') && (n-- > 0u))
          {
              *dp++ = *sp++;
          }
  
          *dp = '\0';
      }
  }
  
  /************************************************************************
  * DESCRIPTION: The function fnet_strrchr() returns a pointer to the last
  * occurrence of chr in str, or NULL if no match is found.
  *************************************************************************/
  fnet_char_t *fnet_strrchr(const fnet_char_t *str, fnet_char_t chr )
  {
      const fnet_char_t  *p = str;
      const fnet_char_t  *q = 0;
      fnet_char_t        c = chr;
      fnet_char_t        ch = *p++;
  
      while(ch)
      {
          if(ch == c)
          {
              q = p - 1;
          }
  
          ch = *p++;
      }
  
      if(q)
      {
          return (fnet_char_t *)(q);
      }
  
      return (c ? FNET_NULL : (fnet_char_t *)(p - 1));
  }
  /************************************************************************
  * DESCRIPTION: The function fnet_strchr() returns a pointer to the first
  * occurence of chr in str, or 0 if chr is not found.
  *************************************************************************/
  fnet_char_t *fnet_strchr( const fnet_char_t *str, fnet_char_t chr )
  {
      const fnet_char_t   *p = str;
      fnet_char_t         c = chr;
      fnet_char_t         ch = *p++;
  
      while(ch)
      {
          if(ch == c)
          {
              return (fnet_char_t *)(p - 1);
          }
  
          ch = *p++;
      }
  
      return (fnet_char_t *)(c ? FNET_NULL : (p - 1));
  }
  
  /************************************************************************
  * DESCRIPTION: The function fnet_strstr() returns a pointer to the first
  * occurrence of substr in str, or 0 if no match is found.
  * If the length of pat is zero, then fnet_strstr() will
  * simply return str.
  *************************************************************************/
  fnet_char_t *fnet_strstr( const fnet_char_t *str, const fnet_char_t *substr )
  {
      const fnet_char_t  *s1 = str;
      const fnet_char_t  *p1 = substr;
      fnet_uint8_t        firstc, c1, c2;
  
      if((substr == 0) || (!((firstc = *p1++) != 0u)) )
      {
          return (fnet_char_t *)(str);
      }
  
      c1 = *s1++;
  
      while(c1)
      {
          if(c1 == firstc)
          {
              const fnet_char_t *s2 = s1;
              const fnet_char_t *p2 = p1;
  
              while(((c1 = *s2++) == (c2 = *p2++)) && c1)
              {}
  
              if(!c2)
              {
                  return ((fnet_char_t *)(s1 - 1));
              }
          }
  
          c1 = *s1++;
      }
  
      return (0);
  }
  
  /************************************************************************
  * DESCRIPTION: The fnet_strncmp() function compares at most count characters
  * of str1 and str2.
  *************************************************************************/
  fnet_int32_t fnet_strncmp( const fnet_char_t *str1, const fnet_char_t *str2, fnet_size_t n )
  {
      const fnet_char_t  *p1 = str1;
      const fnet_char_t  *p2 = str2;
      fnet_uint8_t        c1, c2;
  
      n++;
  
      while(--n)
      {
          if((c1 = *p1++) != (c2 = *p2++))
          {
              return (fnet_int32_t)(c1 - c2);
          }
          else if(!c1)
          {
              break;
          }
          else
          {}
      }
  
      return (0);
  }
  
  /************************************************************************
  * DESCRIPTION:
  *************************************************************************/
  fnet_uint32_t fnet_strtoul (const fnet_char_t *str, fnet_char_t **ptr, fnet_size_t base)
  {
      fnet_uint32_t   rvalue;
      fnet_bool_t     err;
      fnet_bool_t     neg;
      fnet_char_t     c;
      fnet_char_t     *endp;
      fnet_char_t     *startp;
  
      rvalue = 0u;
      err = FNET_FALSE;
      neg = FNET_FALSE;
  
      /* Check for invalid arguments */
      if ((str == 0) || (base == 1u) || (base > 36u))
      {
          if (ptr != 0)
          {
              *ptr = (fnet_char_t *)str;
          }
          return 0u;
      }
  
      /* Skip leading white spaces */
      for (startp = (fnet_char_t *)str; ((*startp == ' ') || (*startp == '\t')) ; ++startp)
      {}
  
      /* Check for notations */
      switch (startp[0])
      {
          case '0':
              if ((startp[1] == 'x') || (startp[1] == 'X'))
              {
                  if ((base == 0u) || (base == 16u))
                  {
                      base = 16u;
                      startp = &startp[2];
                  }
              }
              break;
          case '-':
              neg = FNET_TRUE;
              startp = &startp[1];
              break;
          default:
              break;
      }
  
      if (base == 0u)
      {
          base = 10u;
      }
  
      /* Check for invalid chars in str */
      for ( endp = startp; (err == FNET_FALSE) && ((c = (*endp)) != '\0') && (!((*endp == ' ') || (*endp == '\t'))); ++endp)
      {
          /* Check for 0..9,Aa-Zz */
          if (!(((c >= '0') && (c <= '9')) ||
                ((c >= 'A') && (c <= 'Z')) ||
                ((c >= 'a') && (c <= 'z'))))
          {
              err = FNET_TRUE;
          }
          else
          {
              /* Convert fnet_char_t to num in 0..36 */
              if ((c >= '0') && (c <= '9')) /* Is digit.*/
              {
                  c = c - '0';
              }
              else
              {
                  if ((c >= 'A') && (c <= 'Z')) /* Is upper.*/
                  {
                      c = c - 'A' + 10u;
                  }
                  else
                  {
                      c = c - 'a' + 10u;
                  }
              }
  
              /* check c against base */
              if ((fnet_size_t)c >= base)
              {
                  err = FNET_TRUE;
              }
              else
              {
                  if (neg)
                  {
                      rvalue = (rvalue * base) - (fnet_uint32_t)c;
                  }
                  else
                  {
                      rvalue = (rvalue * base) + (fnet_uint32_t)c;
                  }
              }
          }
      }
  
      /* Upon exit, endp points to the character at which valid info */
      /* STOPS.  No chars including and beyond endp are used.        */
  
      if (ptr != 0)
      {
          *ptr = endp;
      }
  
      if (err)
      {
          if (ptr != 0)
          {
              *ptr = (fnet_char_t *)str;
          }
          return 0u;
      }
      else
      {
          return rvalue;
      }
  }
  
  /************************************************************************
  * DESCRIPTION: This function converts an uppercase letter to the corresponding
  * lowercase letter.
  *************************************************************************/
  fnet_char_t fnet_tolower( fnet_char_t to_lower )
  {
      if((to_lower >= 'A') && (to_lower <= 'Z'))
      {
          return (fnet_uint8_t)(to_lower + 0x20u);
      }
  
      return to_lower;
  }
  
  /************************************************************************
  * DESCRIPTION: The fnet_strcasecmp() function compares the two strings s1
  * and s2, ignoring the case of the characters. It returns an
  * integer less than, equal to, or greater than zero if s1 is found,
  * respectively, to be less than, to match, or be greater than s2.
  *************************************************************************/
  fnet_int32_t fnet_strcasecmp( const fnet_char_t *str1, const fnet_char_t *str2 )
  {
      fnet_uint8_t c1, c2;
  
      while(1)
      {
          c1 = fnet_tolower(*str1++);
          c2 = fnet_tolower(*str2++);
  
          if(c1 < c2)
          {
              return -1;
          }
  
          if(c1 > c2)
          {
              return 1;
          }
  
          if(c1 == 0u)
          {
              return 0;
          }
      }
  }
  
  /************************************************************************
  * DESCRIPTION:
  *************************************************************************/
  fnet_int32_t fnet_strcmp_splitter( const fnet_char_t *in_str, const fnet_char_t *name, fnet_char_t splitter)
  {
      fnet_int32_t result;
  
      /* No checks for 0 */
      const fnet_char_t *s1p = in_str;
      const fnet_char_t *s2p = name;
  
      while (*s1p == ' ')
      {
          s1p++;	    /* Strip leading spaces */
      }
      while (*s1p == splitter)
      {
          s1p++;	/* Strip heading slash */
      }
  
      while((*s2p != '\0') && (*s1p == *s2p))
      {
          ++s1p;
          ++s2p;
  
          if (*s1p == splitter)
          {
              break; /* next element */
          }
      }
  
      if(*s1p == splitter)
      {
          result = 0;
      }
      else
      {
          result = (fnet_int32_t )(*s1p - *s2p);
      }
  
      return result;
  }
  
  /************************************************************************
  * DESCRIPTION: Breaks a string into a sequence of tokens.
  *************************************************************************/
  fnet_char_t *fnet_strtok_r(fnet_char_t *str, const fnet_char_t *delimiter, fnet_char_t **last)
  {
      const fnet_char_t  *spanp;
      fnet_char_t        c;
      fnet_char_t        sc;
      fnet_char_t        *tok;
  
      if ((str == FNET_NULL) && ((str = *last) == FNET_NULL))
      {
          return (FNET_NULL);
      }
  
      /*
       * Skip leading delimiters.
       */
  CONT:
      c = (*str++);
      spanp = delimiter;
      while( (sc = (*spanp++)) != 0u)
      {
          if (c == sc)
          {
              goto CONT;
          }
      }
  
      if (c == 0u) /* No non-delimiter characters */
      {
          *last = FNET_NULL;
          return (FNET_NULL);
      }
      tok = str - 1;
  
      /*
       * Scan token.
       */
      for (;;)
      {
          c = (*str++);
          spanp = delimiter;
          do
          {
              if ((sc = (*spanp++)) == c)
              {
                  if (c == 0u)
                  {
                      str = FNET_NULL;
                  }
                  else
                  {
                      str[-1] = 0u;
                  }
                  *last = str;
                  return (tok);
              }
          }
          while (sc != 0u);
      }
      /* Not reached.*/
  }
  
  /************************************************************************
  * DESCRIPTION: Generates a pseudo-random number.
  *************************************************************************/
  fnet_uint32_t fnet_rand(void)
  {
      fnet_rand_value = fnet_rand_value * 1103515245u + 12345u;
      return((fnet_uint32_t)(fnet_rand_value >> 16u) % (FNET_RAND_MAX + 1u));
  }
  
  /************************************************************************
  * DESCRIPTION: Initializes the pseudo-random number generator.
  *************************************************************************/
  void fnet_srand(fnet_uint32_t seed)
  {
      fnet_rand_value += seed;
  }
  