695 lines
15 KiB
C
695 lines
15 KiB
C
/*
|
|
* Milkymist SoC (Software)
|
|
* Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq
|
|
* Copyright (C) Linus Torvalds and Linux kernel developers
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
int errno;
|
|
|
|
/**
|
|
* strchr - Find the first occurrence of a character in a string
|
|
* @s: The string to be searched
|
|
* @c: The character to search for
|
|
*/
|
|
char *strchr(const char *s, int c)
|
|
{
|
|
for (; *s != (char)c; ++s)
|
|
if (*s == '\0')
|
|
return NULL;
|
|
return (char *)s;
|
|
}
|
|
|
|
/**
|
|
* strpbrk - Find the first occurrence of a set of characters
|
|
* @cs: The string to be searched
|
|
* @ct: The characters to search for
|
|
*/
|
|
char *strpbrk(const char *cs, const char *ct)
|
|
{
|
|
const char *sc1, *sc2;
|
|
|
|
for (sc1 = cs; *sc1 != '\0'; ++sc1) {
|
|
for (sc2 = ct; *sc2 != '\0'; ++sc2) {
|
|
if (*sc1 == *sc2)
|
|
return (char *)sc1;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* strrchr - Find the last occurrence of a character in a string
|
|
* @s: The string to be searched
|
|
* @c: The character to search for
|
|
*/
|
|
char *strrchr(const char *s, int c)
|
|
{
|
|
const char *p = s + strlen(s);
|
|
do {
|
|
if (*p == (char)c)
|
|
return (char *)p;
|
|
} while (--p >= s);
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* strnchr - Find a character in a length limited string
|
|
* @s: The string to be searched
|
|
* @count: The number of characters to be searched
|
|
* @c: The character to search for
|
|
*/
|
|
char *strnchr(const char *s, size_t count, int c)
|
|
{
|
|
for (; count-- && *s != '\0'; ++s)
|
|
if (*s == (char)c)
|
|
return (char *)s;
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* strcpy - Copy a %NUL terminated string
|
|
* @dest: Where to copy the string to
|
|
* @src: Where to copy the string from
|
|
*/
|
|
char *strcpy(char *dest, const char *src)
|
|
{
|
|
char *tmp = dest;
|
|
|
|
while ((*dest++ = *src++) != '\0')
|
|
/* nothing */;
|
|
return tmp;
|
|
}
|
|
|
|
/**
|
|
* strncpy - Copy a length-limited, %NUL-terminated string
|
|
* @dest: Where to copy the string to
|
|
* @src: Where to copy the string from
|
|
* @count: The maximum number of bytes to copy
|
|
*
|
|
* The result is not %NUL-terminated if the source exceeds
|
|
* @count bytes.
|
|
*
|
|
* In the case where the length of @src is less than that of
|
|
* count, the remainder of @dest will be padded with %NUL.
|
|
*
|
|
*/
|
|
char *strncpy(char *dest, const char *src, size_t count)
|
|
{
|
|
char *tmp = dest;
|
|
|
|
while (count) {
|
|
if ((*tmp = *src) != 0)
|
|
src++;
|
|
tmp++;
|
|
count--;
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
/**
|
|
* strcmp - Compare two strings
|
|
* @cs: One string
|
|
* @ct: Another string
|
|
*/
|
|
int strcmp(const char *cs, const char *ct)
|
|
{
|
|
signed char __res;
|
|
|
|
while (1) {
|
|
if ((__res = *cs - *ct++) != 0 || !*cs++)
|
|
break;
|
|
}
|
|
return __res;
|
|
}
|
|
|
|
/**
|
|
* strncmp - Compare two strings using the first characters only
|
|
* @cs: One string
|
|
* @ct: Another string
|
|
* @count: Number of characters
|
|
*/
|
|
int strncmp(const char *cs, const char *ct, size_t count)
|
|
{
|
|
signed char __res;
|
|
size_t n;
|
|
|
|
n = 0;
|
|
__res = 0;
|
|
while (n < count) {
|
|
if ((__res = *cs - *ct++) != 0 || !*cs++)
|
|
break;
|
|
n++;
|
|
}
|
|
return __res;
|
|
}
|
|
|
|
/**
|
|
* strlen - Find the length of a string
|
|
* @s: The string to be sized
|
|
*/
|
|
size_t strlen(const char *s)
|
|
{
|
|
const char *sc;
|
|
|
|
for (sc = s; *sc != '\0'; ++sc)
|
|
/* nothing */;
|
|
return sc - s;
|
|
}
|
|
|
|
/**
|
|
* strnlen - Find the length of a length-limited string
|
|
* @s: The string to be sized
|
|
* @count: The maximum number of bytes to search
|
|
*/
|
|
size_t strnlen(const char *s, size_t count)
|
|
{
|
|
const char *sc;
|
|
|
|
for (sc = s; count-- && *sc != '\0'; ++sc)
|
|
/* nothing */;
|
|
return sc - s;
|
|
}
|
|
|
|
/**
|
|
* strspn - Calculate the length of the initial substring of @s which only contain letters in @accept
|
|
* @s: The string to be searched
|
|
* @accept: The string to search for
|
|
*/
|
|
size_t strspn(const char *s, const char *accept)
|
|
{
|
|
const char *p;
|
|
const char *a;
|
|
size_t count = 0;
|
|
|
|
for (p = s; *p != '\0'; ++p) {
|
|
for (a = accept; *a != '\0'; ++a) {
|
|
if (*p == *a)
|
|
break;
|
|
}
|
|
if (*a == '\0')
|
|
return count;
|
|
++count;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* memcmp - Compare two areas of memory
|
|
* @cs: One area of memory
|
|
* @ct: Another area of memory
|
|
* @count: The size of the area.
|
|
*/
|
|
int memcmp(const void *cs, const void *ct, size_t count)
|
|
{
|
|
const unsigned char *su1, *su2;
|
|
int res = 0;
|
|
|
|
for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
|
|
if ((res = *su1 - *su2) != 0)
|
|
break;
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* memset - Fill a region of memory with the given value
|
|
* @s: Pointer to the start of the area.
|
|
* @c: The byte to fill the area with
|
|
* @count: The size of the area.
|
|
*/
|
|
void *memset(void *s, int c, size_t count)
|
|
{
|
|
char *xs = s;
|
|
|
|
while (count--)
|
|
*xs++ = c;
|
|
return s;
|
|
}
|
|
|
|
/**
|
|
* memcpy - Copies one area of memory to another
|
|
* @dest: Destination
|
|
* @src: Source
|
|
* @n: The size to copy.
|
|
*/
|
|
void *memcpy(void *to, const void *from, size_t n)
|
|
{
|
|
void *xto = to;
|
|
size_t temp;
|
|
|
|
if(!n)
|
|
return xto;
|
|
if((long)to & 1) {
|
|
char *cto = to;
|
|
const char *cfrom = from;
|
|
*cto++ = *cfrom++;
|
|
to = cto;
|
|
from = cfrom;
|
|
n--;
|
|
}
|
|
if((long)from & 1) {
|
|
char *cto = to;
|
|
const char *cfrom = from;
|
|
for (; n; n--)
|
|
*cto++ = *cfrom++;
|
|
return xto;
|
|
}
|
|
if(n > 2 && (long)to & 2) {
|
|
short *sto = to;
|
|
const short *sfrom = from;
|
|
*sto++ = *sfrom++;
|
|
to = sto;
|
|
from = sfrom;
|
|
n -= 2;
|
|
}
|
|
if((long)from & 2) {
|
|
short *sto = to;
|
|
const short *sfrom = from;
|
|
temp = n >> 1;
|
|
for (; temp; temp--)
|
|
*sto++ = *sfrom++;
|
|
to = sto;
|
|
from = sfrom;
|
|
if(n & 1) {
|
|
char *cto = to;
|
|
const char *cfrom = from;
|
|
*cto = *cfrom;
|
|
}
|
|
return xto;
|
|
}
|
|
temp = n >> 2;
|
|
if(temp) {
|
|
long *lto = to;
|
|
const long *lfrom = from;
|
|
for(; temp; temp--)
|
|
*lto++ = *lfrom++;
|
|
to = lto;
|
|
from = lfrom;
|
|
}
|
|
if(n & 2) {
|
|
short *sto = to;
|
|
const short *sfrom = from;
|
|
*sto++ = *sfrom++;
|
|
to = sto;
|
|
from = sfrom;
|
|
}
|
|
if(n & 1) {
|
|
char *cto = to;
|
|
const char *cfrom = from;
|
|
*cto = *cfrom;
|
|
}
|
|
return xto;
|
|
}
|
|
|
|
/**
|
|
* memmove - Copies one area of memory to another, overlap possible
|
|
* @dest: Destination
|
|
* @src: Source
|
|
* @n: The size to copy.
|
|
*/
|
|
void *memmove(void *dest, const void *src, size_t count)
|
|
{
|
|
char *tmp, *s;
|
|
|
|
if(dest <= src) {
|
|
tmp = (char *) dest;
|
|
s = (char *) src;
|
|
while(count--)
|
|
*tmp++ = *s++;
|
|
} else {
|
|
tmp = (char *)dest + count;
|
|
s = (char *)src + count;
|
|
while(count--)
|
|
*--tmp = *--s;
|
|
}
|
|
|
|
return dest;
|
|
}
|
|
|
|
/**
|
|
* strstr - Find the first substring in a %NUL terminated string
|
|
* @s1: The string to be searched
|
|
* @s2: The string to search for
|
|
*/
|
|
char *strstr(const char *s1, const char *s2)
|
|
{
|
|
size_t l1, l2;
|
|
|
|
l2 = strlen(s2);
|
|
if (!l2)
|
|
return (char *)s1;
|
|
l1 = strlen(s1);
|
|
while (l1 >= l2) {
|
|
l1--;
|
|
if (!memcmp(s1, s2, l2))
|
|
return (char *)s1;
|
|
s1++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* memchr - Find a character in an area of memory.
|
|
* @s: The memory area
|
|
* @c: The byte to search for
|
|
* @n: The size of the area.
|
|
*
|
|
* returns the address of the first occurrence of @c, or %NULL
|
|
* if @c is not found
|
|
*/
|
|
void *memchr(const void *s, int c, size_t n)
|
|
{
|
|
const unsigned char *p = s;
|
|
while (n-- != 0) {
|
|
if ((unsigned char)c == *p++) {
|
|
return (void *)(p - 1);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* strtoul - convert a string to an unsigned long
|
|
* @nptr: The start of the string
|
|
* @endptr: A pointer to the end of the parsed string will be placed here
|
|
* @base: The number base to use
|
|
*/
|
|
unsigned long strtoul(const char *nptr, char **endptr, int base)
|
|
{
|
|
unsigned long result = 0,value;
|
|
|
|
if (!base) {
|
|
base = 10;
|
|
if (*nptr == '0') {
|
|
base = 8;
|
|
nptr++;
|
|
if ((toupper(*nptr) == 'X') && isxdigit(nptr[1])) {
|
|
nptr++;
|
|
base = 16;
|
|
}
|
|
}
|
|
} else if (base == 16) {
|
|
if (nptr[0] == '0' && toupper(nptr[1]) == 'X')
|
|
nptr += 2;
|
|
}
|
|
while (isxdigit(*nptr) &&
|
|
(value = isdigit(*nptr) ? *nptr-'0' : toupper(*nptr)-'A'+10) < base) {
|
|
result = result*base + value;
|
|
nptr++;
|
|
}
|
|
if (endptr)
|
|
*endptr = (char *)nptr;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* strtol - convert a string to a signed long
|
|
* @nptr: The start of the string
|
|
* @endptr: A pointer to the end of the parsed string will be placed here
|
|
* @base: The number base to use
|
|
*/
|
|
long strtol(const char *nptr, char **endptr, int base)
|
|
{
|
|
if(*nptr=='-')
|
|
return -strtoul(nptr+1,endptr,base);
|
|
return strtoul(nptr,endptr,base);
|
|
}
|
|
|
|
int skip_atoi(const char **s)
|
|
{
|
|
int i=0;
|
|
|
|
while (isdigit(**s))
|
|
i = i*10 + *((*s)++) - '0';
|
|
return i;
|
|
}
|
|
|
|
char *number(char *buf, char *end, unsigned long num, int base, int size, int precision, int type)
|
|
{
|
|
char c,sign,tmp[66];
|
|
const char *digits;
|
|
static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
int i;
|
|
|
|
digits = (type & PRINTF_LARGE) ? large_digits : small_digits;
|
|
if (type & PRINTF_LEFT)
|
|
type &= ~PRINTF_ZEROPAD;
|
|
if (base < 2 || base > 36)
|
|
return NULL;
|
|
c = (type & PRINTF_ZEROPAD) ? '0' : ' ';
|
|
sign = 0;
|
|
if (type & PRINTF_SIGN) {
|
|
if ((signed long) num < 0) {
|
|
sign = '-';
|
|
num = - (signed long) num;
|
|
size--;
|
|
} else if (type & PRINTF_PLUS) {
|
|
sign = '+';
|
|
size--;
|
|
} else if (type & PRINTF_SPACE) {
|
|
sign = ' ';
|
|
size--;
|
|
}
|
|
}
|
|
if (type & PRINTF_SPECIAL) {
|
|
if (base == 16)
|
|
size -= 2;
|
|
else if (base == 8)
|
|
size--;
|
|
}
|
|
i = 0;
|
|
if (num == 0)
|
|
tmp[i++]='0';
|
|
else while (num != 0) {
|
|
tmp[i++] = digits[num % base];
|
|
num = num / base;
|
|
}
|
|
if (i > precision)
|
|
precision = i;
|
|
size -= precision;
|
|
if (!(type&(PRINTF_ZEROPAD+PRINTF_LEFT))) {
|
|
while(size-->0) {
|
|
if (buf < end)
|
|
*buf = ' ';
|
|
++buf;
|
|
}
|
|
}
|
|
if (sign) {
|
|
if (buf < end)
|
|
*buf = sign;
|
|
++buf;
|
|
}
|
|
if (type & PRINTF_SPECIAL) {
|
|
if (base==8) {
|
|
if (buf < end)
|
|
*buf = '0';
|
|
++buf;
|
|
} else if (base==16) {
|
|
if (buf < end)
|
|
*buf = '0';
|
|
++buf;
|
|
if (buf < end)
|
|
*buf = digits[33];
|
|
++buf;
|
|
}
|
|
}
|
|
if (!(type & PRINTF_LEFT)) {
|
|
while (size-- > 0) {
|
|
if (buf < end)
|
|
*buf = c;
|
|
++buf;
|
|
}
|
|
}
|
|
while (i < precision--) {
|
|
if (buf < end)
|
|
*buf = '0';
|
|
++buf;
|
|
}
|
|
while (i-- > 0) {
|
|
if (buf < end)
|
|
*buf = tmp[i];
|
|
++buf;
|
|
}
|
|
while (size-- > 0) {
|
|
if (buf < end)
|
|
*buf = ' ';
|
|
++buf;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
/**
|
|
* vscnprintf - Format a string and place it in a buffer
|
|
* @buf: The buffer to place the result into
|
|
* @size: The size of the buffer, including the trailing null space
|
|
* @fmt: The format string to use
|
|
* @args: Arguments for the format string
|
|
*
|
|
* The return value is the number of characters which have been written into
|
|
* the @buf not including the trailing '\0'. If @size is <= 0 the function
|
|
* returns 0.
|
|
*
|
|
* Call this function if you are already dealing with a va_list.
|
|
* You probably want scnprintf() instead.
|
|
*/
|
|
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
|
{
|
|
int i;
|
|
|
|
i=vsnprintf(buf,size,fmt,args);
|
|
return (i >= size) ? (size - 1) : i;
|
|
}
|
|
|
|
|
|
/**
|
|
* snprintf - Format a string and place it in a buffer
|
|
* @buf: The buffer to place the result into
|
|
* @size: The size of the buffer, including the trailing null space
|
|
* @fmt: The format string to use
|
|
* @...: Arguments for the format string
|
|
*
|
|
* The return value is the number of characters which would be
|
|
* generated for the given input, excluding the trailing null,
|
|
* as per ISO C99. If the return is greater than or equal to
|
|
* @size, the resulting string is truncated.
|
|
*/
|
|
int snprintf(char * buf, size_t size, const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
int i;
|
|
|
|
va_start(args, fmt);
|
|
i=vsnprintf(buf,size,fmt,args);
|
|
va_end(args);
|
|
return i;
|
|
}
|
|
|
|
/**
|
|
* scnprintf - Format a string and place it in a buffer
|
|
* @buf: The buffer to place the result into
|
|
* @size: The size of the buffer, including the trailing null space
|
|
* @fmt: The format string to use
|
|
* @...: Arguments for the format string
|
|
*
|
|
* The return value is the number of characters written into @buf not including
|
|
* the trailing '\0'. If @size is <= 0 the function returns 0.
|
|
*/
|
|
|
|
int scnprintf(char * buf, size_t size, const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
int i;
|
|
|
|
va_start(args, fmt);
|
|
i = vsnprintf(buf, size, fmt, args);
|
|
va_end(args);
|
|
return (i >= size) ? (size - 1) : i;
|
|
}
|
|
|
|
/**
|
|
* vsprintf - Format a string and place it in a buffer
|
|
* @buf: The buffer to place the result into
|
|
* @fmt: The format string to use
|
|
* @args: Arguments for the format string
|
|
*
|
|
* The function returns the number of characters written
|
|
* into @buf. Use vsnprintf() or vscnprintf() in order to avoid
|
|
* buffer overflows.
|
|
*
|
|
* Call this function if you are already dealing with a va_list.
|
|
* You probably want sprintf() instead.
|
|
*/
|
|
int vsprintf(char *buf, const char *fmt, va_list args)
|
|
{
|
|
return vsnprintf(buf, INT_MAX, fmt, args);
|
|
}
|
|
|
|
/**
|
|
* sprintf - Format a string and place it in a buffer
|
|
* @buf: The buffer to place the result into
|
|
* @fmt: The format string to use
|
|
* @...: Arguments for the format string
|
|
*
|
|
* The function returns the number of characters written
|
|
* into @buf. Use snprintf() or scnprintf() in order to avoid
|
|
* buffer overflows.
|
|
*/
|
|
int sprintf(char * buf, const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
int i;
|
|
|
|
va_start(args, fmt);
|
|
i=vsnprintf(buf, INT_MAX, fmt, args);
|
|
va_end(args);
|
|
return i;
|
|
}
|
|
|
|
/* From linux/lib/ctype.c, Copyright (C) 1991, 1992 Linus Torvalds */
|
|
const unsigned char _ctype[] = {
|
|
_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
|
|
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
|
|
_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
|
|
_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
|
|
_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
|
|
_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
|
|
_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
|
|
_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
|
|
_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
|
|
_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
|
|
_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
|
|
_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
|
|
_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
|
|
_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
|
|
_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
|
|
_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
|
|
_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
|
|
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
|
|
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
|
|
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
|
|
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
|
|
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
|
|
|
|
/**
|
|
* rand - Returns a pseudo random number
|
|
*/
|
|
|
|
static unsigned int randseed;
|
|
unsigned int rand(void)
|
|
{
|
|
randseed = 129 * randseed + 907633385;
|
|
return randseed;
|
|
}
|
|
|
|
void srand(unsigned int seed)
|
|
{
|
|
randseed = seed;
|
|
}
|
|
|
|
void abort(void)
|
|
{
|
|
printf("Aborted.");
|
|
while(1);
|
|
}
|