/* * File : string.c * This file is part of RT-Thread RTOS * COPYRIGHT (C) 2008, RT-Thread Development Team * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rt-thread.org/license/LICENSE * * Change Logs: * Date Author Notes * 2008-08-14 Bernard the first version * 2010-02-15 Gary Lee add strlcpy * 2010-03-17 Bernard add strlcpy implementation to this file. * fix strlcpy declaration * 2010-03-24 Bernard add strchr and strtok implementation. */ #include #include #if !defined (RT_USING_NEWLIB) && defined (RT_USING_MINILIBC) #include "string.h" /* there is no strcpy and strcmp implementation in RT-Thread */ char *strcpy(char *dest, const char *src) { return (char *)rt_strncpy(dest, src, rt_strlen(src) + 1); } char *strncpy(char *dest, const char *src, size_t siz) { return (char *)rt_strncpy(dest, src, siz); } size_t strlcpy(char *dst, const char *src, size_t siz) { register char *d = dst; register const char *s = src; register size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } int strcmp (const char *s1, const char *s2) { while (*s1 && *s1 == *s2) s1++, s2++; return (*s1 - *s2); } /** * strncmp - Compare two length-limited strings * @cs: One string * @ct: Another string * @count: The maximum number of bytes to compare */ int strncmp(const char *cs,const char *ct, size_t count) { register signed char __res = 0; while (count) { if ((__res = *cs - *ct++) != 0 || !*cs++) break; count--; } return __res; } char *strcat(char * dest, const char * src) { char *tmp = dest; while (*dest) dest++; while ((*dest++ = *src++) != '\0') ; return tmp; } char *strncat(char *dest, const char *src, size_t count) { char *tmp = dest; if (count) { while (*dest) dest++; while ((*dest++ = *src++)) { if (--count == 0) { *dest = '\0'; break; } } } return tmp; } char *strrchr(const char *t, int c) { register char ch; register const char *l=0; ch = c; for (;;) { if (*t == ch) l=t; if (!*t) return (char*)l; ++t; } return (char*)l; } int strncasecmp ( const char* s1, const char* s2, size_t len ) { register unsigned int x2; register unsigned int x1; register const char* end = s1 + len; while (1) { if ((s1 >= end) ) return 0; x2 = *s2 - 'A'; if ((x2 < 26u)) x2 += 32; x1 = *s1 - 'A'; if ((x1 < 26u)) x1 += 32; s1++; s2++; if (x2 != x1) break; if (x1 == (unsigned int)-'A') break; } return x1 - x2; } /* private function */ #define isdigit(c) ((unsigned)((c) - '0') < 10) rt_inline int divide(int *n, int base) { rt_int32_t res; /* optimized for processor which does not support divide instructions. */ if (base == 10) { res = ((int)*n) % 10U; *n = ((int)*n) / 10U; } else { res = ((int)*n) % 16U; *n = ((int)*n) / 16U; } return res; } rt_inline int skip_atoi(const char **s) { register int i=0; while (isdigit(**s)) i = i*10 + *((*s)++) - '0'; return i; } 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 */ #define __ismask(x) (_ctype[(int)(unsigned char)(x)]) #define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) #define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) #define iscntrl(c) ((__ismask(c)&(_C)) != 0) #define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) #define islower(c) ((__ismask(c)&(_L)) != 0) #define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) #define ispunct(c) ((__ismask(c)&(_P)) != 0) #define isspace(c) ((__ismask(c)&(_S)) != 0) #define isupper(c) ((__ismask(c)&(_U)) != 0) #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) #define isascii(c) (((unsigned char)(c))<=0x7f) #define toascii(c) (((unsigned char)(c))&0x7f) static inline unsigned char __tolower(unsigned char c) { if (isupper(c)) c -= 'A'-'a'; return c; } static inline unsigned char __toupper(unsigned char c) { if (islower(c)) c -= 'a'-'A'; return c; } int tolower(int c) { return __tolower(c); } int toupper(int c) { return __toupper(c); } /** * simple_strtoul - convert a string to an unsigned long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) { unsigned long result = 0,value; if (!base) { base = 10; if (*cp == '0') { base = 8; cp++; if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { cp++; base = 16; } } } else if (base == 16) { if (cp[0] == '0' && toupper(cp[1]) == 'X') cp += 2; } while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { result = result*base + value; cp++; } if (endp) *endp = (char *)cp; return result; } /** * simple_strtol - convert a string to a signed long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ long simple_strtol(const char *cp,char **endp,unsigned int base) { if(*cp=='-') return -simple_strtoul(cp+1,endp,base); return simple_strtoul(cp,endp,base); } /** * simple_strtoull - convert a string to an unsigned long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) { unsigned long long result = 0, value; if (*cp == '0') { cp++; if ((toupper(*cp) == 'X') && isxdigit (cp[1])) { base = 16; cp++; } if (!base) { base = 8; } } if (!base) { base = 10; } while (isxdigit (*cp) && (value = isdigit (*cp) ? *cp - '0' : (islower (*cp) ? toupper (*cp) : *cp) - 'A' + 10) < base) { result = result * base + value; cp++; } if (endp) *endp = (char *) cp; return result; } /** * simple_strtoll - convert a string to a signed long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ long long simple_strtoll(const char *cp,char **endp,unsigned int base) { if(*cp=='-') return -simple_strtoull(cp+1,endp,base); return simple_strtoull(cp,endp,base); } /** * vsscanf - Unformat a buffer into a list of arguments * @buf: input buffer * @fmt: format of buffer * @args: arguments */ int vsscanf(const char * buf, const char * fmt, va_list args) { const char *str = buf; char *next; int num = 0; int qualifier; int base; int field_width = -1; int is_sign = 0; while(*fmt && *str) { /* skip any white space in format */ /* white space in format matchs any amount of * white space, including none, in the input. */ if (isspace(*fmt)) { while (isspace(*fmt)) ++fmt; while (isspace(*str)) ++str; } /* anything that is not a conversion must match exactly */ if (*fmt != '%' && *fmt) { if (*fmt++ != *str++) break; continue; } if (!*fmt) break; ++fmt; /* skip this conversion. * advance both strings to next white space */ if (*fmt == '*') { while (!isspace(*fmt) && *fmt) fmt++; while (!isspace(*str) && *str) str++; continue; } /* get field width */ if (isdigit(*fmt)) field_width = skip_atoi(&fmt); /* get conversion qualifier */ qualifier = -1; if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z') { qualifier = *fmt; fmt++; } base = 10; is_sign = 0; if (!*fmt || !*str) break; switch(*fmt++) { case 'c': { char *s = (char *) va_arg(args,char*); if (field_width == -1) field_width = 1; do { *s++ = *str++; } while(field_width-- > 0 && *str); num++; } continue; case 's': { char *s = (char *) va_arg(args, char *); if(field_width == -1) field_width = INT_MAX; /* first, skip leading white space in buffer */ while (isspace(*str)) str++; /* now copy until next white space */ while (*str && !isspace(*str) && field_width--) { *s++ = *str++; } *s = '\0'; num++; } continue; case 'n': /* return number of characters read so far */ { int *i = (int *)va_arg(args,int*); *i = str - buf; } continue; case 'o': base = 8; break; case 'x': case 'X': base = 16; break; case 'd': case 'i': is_sign = 1; case 'u': break; case '%': /* looking for '%' in str */ if (*str++ != '%') return num; continue; default: /* invalid format; stop here */ return num; } /* have some sort of integer conversion. * first, skip white space in buffer. */ while (isspace(*str)) str++; if (!*str || !isdigit(*str)) break; switch(qualifier) { case 'h': if (is_sign) { short *s = (short *) va_arg(args,short *); *s = (short) simple_strtol(str,&next,base); } else { unsigned short *s = (unsigned short *) va_arg(args, unsigned short *); *s = (unsigned short) simple_strtoul(str, &next, base); } break; case 'l': if (is_sign) { long *l = (long *) va_arg(args,long *); *l = simple_strtol(str,&next,base); } else { unsigned long *l = (unsigned long*) va_arg(args,unsigned long*); *l = simple_strtoul(str,&next,base); } break; case 'L': if (is_sign) { long long *l = (long long*) va_arg(args,long long *); *l = simple_strtoll(str,&next,base); } else { unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*); *l = simple_strtoull(str,&next,base); } break; case 'Z': { unsigned long *s = (unsigned long*) va_arg(args,unsigned long*); *s = (unsigned long) simple_strtoul(str,&next,base); } break; default: if (is_sign) { int *i = (int *) va_arg(args, int*); *i = (int) simple_strtol(str,&next,base); } else { unsigned int *i = (unsigned int*) va_arg(args, unsigned int*); *i = (unsigned int) simple_strtoul(str,&next,base); } break; } num++; if (!next) break; str = next; } return num; } /** * sscanf - Unformat a buffer into a list of arguments * @buf: input buffer * @fmt: formatting of buffer * @...: resulting arguments */ int sscanf(const char * buf, const char * fmt, ...) { va_list args; int i; va_start(args,fmt); i = vsscanf(buf,fmt,args); va_end(args); return i; } size_t strspn(const char *s, const char *accept) { size_t l=0; int a=1,i, al=strlen(accept); while((a)&&(*s)) { for(a=i=0;(!a)&&(i terminate it */ } *ptrptr=s; return tmp; } char *strtok(char *s, const char *delim) { static char *strtok_pos; return strtok_r(s,delim,&strtok_pos); } char *strchr(const char *s1, int i) { const unsigned char *s = (const unsigned char *)s1; unsigned char c = (unsigned int)i; while (*s && *s != c) { s++; } if (*s != c) { s = NULL; } return (char *) s; } long strtol(const char *str, char **endptr, int base) { return simple_strtol(str, endptr, base); } long long strtoll(const char *str, char **endptr, int base) { return simple_strtoll(str, endptr, base); } #endif