|
- /**************************************************************************
- *
- * Copyright 2008-2018 by Andrey Butok. FNET Community.
- *
- ***************************************************************************
- *
- * 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.
- *
- ***************************************************************************
- *
- * Standard functions implementation.
- *
- ***************************************************************************/
-
- #include "fnet.h"
- #include "fnet_stdlib.h"
-
- static fnet_uint32_t fnet_rand_seed; /* 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 (((fnet_uint32_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 ((((fnet_uint32_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;
- fnet_int32_t result = 0;
-
- while(count)
- {
- result = (fnet_int32_t)(*p1 - *p2);
-
- if(result != 0)
- {
- break;
- }
-
- count--;
- ++p1;
- ++p2;
- }
-
- return result;
- }
-
- /************************************************************************
- * 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)
- {
- while (*s++ != '\0')
- {
- len++;
- }
- }
- return len;
- }
-
- /************************************************************************
- * DESCRIPTION: Calculate the length of a fixed-size string.
- *************************************************************************/
- fnet_size_t fnet_strnlen (const fnet_char_t *str, fnet_size_t max_len)
- {
- const fnet_char_t *s = str;
- fnet_size_t len = 0U;
-
- if(s)
- {
- while (*s++ != '\0')
- {
- if(max_len == len)
- {
- break;
- }
- else
- {
- 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_strlcat (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_strlcpy( 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 (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 (*s2p == ' ')
- {
- s2p++; /* Strip leading spaces */
- }
- while (*s2p == splitter)
- {
- s2p++; /* Strip heading slash */
- }
-
- while (*s1p == ' ')
- {
- s1p++; /* Strip leading spaces */
- }
-
- /* Special case for root folder.*/
- if((*s2p == '\0') && (*s1p == splitter))
- {
- result = 0;
- }
- else
- {
- 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)
- {
- #if 0 /* original */
- fnet_rand_seed = fnet_rand_seed * 1103515245u + 12345u;
- return((fnet_uint32_t)(fnet_rand_seed >> 16u) % (FNET_RAND_MAX + 1u));
- #else /* Park-Miller minimum random number generator (Comm ACM Oct 1988 p1192-1201, Vol 31 Num 10) */
- fnet_uint64_t const a = 16807; /* 7^5 (a primitive root modulo M31) */
- fnet_uint64_t const m = 2147483647; /* 2^31-1 (a Mersenne prime M31) */
- fnet_uint64_t tmp;
-
- tmp = fnet_rand_seed * a;
- fnet_rand_seed = (fnet_uint32_t)(tmp % m);
- return(fnet_rand_seed);
- #endif
- }
-
- /************************************************************************
- * DESCRIPTION: Initializes the pseudo-random number generator.
- *************************************************************************/
- void fnet_srand(fnet_uint32_t seed)
- {
- fnet_rand_seed += seed;
- }
|