1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 * 2008-08-14 Bernard the first version 9 * 2010-02-15 Gary Lee add strlcpy 10 * 2010-03-17 Bernard add strlcpy implementation to this file. 11 * fix strlcpy declaration 12 * 2010-03-24 Bernard add strchr and strtok implementation. 13 */ 14 15 #include <rtthread.h> 16 #include <stdint.h> 17 18 #if !defined (RT_USING_NEWLIB) && defined (RT_USING_MINILIBC) 19 #include "string.h" 20 21 /* there is no strcpy and strcmp implementation in RT-Thread */ 22 char *strcpy(char *dest, const char *src) 23 { 24 return (char *)rt_strncpy(dest, src, rt_strlen(src) + 1); 25 } 26 27 char *strncpy(char *dest, const char *src, size_t siz) 28 { 29 return (char *)rt_strncpy(dest, src, siz); 30 } 31 32 size_t strlcpy(char *dst, const char *src, size_t siz) 33 { 34 register char *d = dst; 35 register const char *s = src; 36 register size_t n = siz; 37 38 /* Copy as many bytes as will fit */ 39 if (n != 0 && --n != 0) 40 { 41 do 42 { 43 if ((*d++ = *s++) == 0) break; 44 } while (--n != 0); 45 } 46 47 /* Not enough room in dst, add NUL and traverse rest of src */ 48 if (n == 0) 49 { 50 if (siz != 0) *d = '\0'; /* NUL-terminate dst */ 51 while (*s++) ; 52 } 53 54 return(s - src - 1); /* count does not include NUL */ 55 } 56 57 int strcmp (const char *s1, const char *s2) 58 { 59 while (*s1 && *s1 == *s2) 60 s1++, s2++; 61 return (*s1 - *s2); 62 } 63 64 /** 65 * strncmp - Compare two length-limited strings 66 * @cs: One string 67 * @ct: Another string 68 * @count: The maximum number of bytes to compare 69 */ 70 int strncmp(const char *cs,const char *ct, size_t count) 71 { 72 register signed char __res = 0; 73 74 while (count) { 75 if ((__res = *cs - *ct++) != 0 || !*cs++) 76 break; 77 count--; 78 } 79 80 return __res; 81 } 82 83 char *strcat(char * dest, const char * src) 84 { 85 char *tmp = dest; 86 87 while (*dest) 88 dest++; 89 while ((*dest++ = *src++) != '\0') 90 ; 91 92 return tmp; 93 } 94 95 char *strncat(char *dest, const char *src, size_t count) 96 { 97 char *tmp = dest; 98 99 if (count) { 100 while (*dest) 101 dest++; 102 while ((*dest++ = *src++)) { 103 if (--count == 0) { 104 *dest = '\0'; 105 break; 106 } 107 } 108 } 109 110 return tmp; 111 } 112 113 char *strrchr(const char *t, int c) 114 { 115 register char ch; 116 register const char *l=0; 117 118 ch = c; 119 for (;;) 120 { 121 if (*t == ch) l=t; 122 if (!*t) return (char*)l; 123 ++t; 124 } 125 126 return (char*)l; 127 } 128 129 130 int strncasecmp ( const char* s1, const char* s2, size_t len ) 131 { 132 register unsigned int x2; 133 register unsigned int x1; 134 register const char* end = s1 + len; 135 136 while (1) 137 { 138 if ((s1 >= end) ) 139 return 0; 140 141 x2 = *s2 - 'A'; if ((x2 < 26u)) x2 += 32; 142 x1 = *s1 - 'A'; if ((x1 < 26u)) x1 += 32; 143 s1++; s2++; 144 145 if (x2 != x1) 146 break; 147 148 if (x1 == (unsigned int)-'A') 149 break; 150 } 151 152 return x1 - x2; 153 } 154 155 /* private function */ 156 #define isdigit(c) ((unsigned)((c) - '0') < 10) 157 158 rt_inline int divide(int *n, int base) 159 { 160 rt_int32_t res; 161 162 /* optimized for processor which does not support divide instructions. */ 163 if (base == 10) 164 { 165 res = ((int)*n) % 10U; 166 *n = ((int)*n) / 10U; 167 } 168 else 169 { 170 res = ((int)*n) % 16U; 171 *n = ((int)*n) / 16U; 172 } 173 174 return res; 175 } 176 177 rt_inline int skip_atoi(const char **s) 178 { 179 register int i=0; 180 while (isdigit(**s)) i = i*10 + *((*s)++) - '0'; 181 182 return i; 183 } 184 185 unsigned char _ctype[] = { 186 _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ 187 _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ 188 _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ 189 _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ 190 _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ 191 _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ 192 _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ 193 _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ 194 _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ 195 _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ 196 _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ 197 _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ 198 _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ 199 _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ 200 _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ 201 _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ 202 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ 203 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ 204 _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ 205 _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ 206 _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ 207 _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ 208 _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ 209 _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ 210 211 #define __ismask(x) (_ctype[(int)(unsigned char)(x)]) 212 213 #define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) 214 #define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) 215 #define iscntrl(c) ((__ismask(c)&(_C)) != 0) 216 #define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) 217 #define islower(c) ((__ismask(c)&(_L)) != 0) 218 #define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) 219 #define ispunct(c) ((__ismask(c)&(_P)) != 0) 220 #define isspace(c) ((__ismask(c)&(_S)) != 0) 221 #define isupper(c) ((__ismask(c)&(_U)) != 0) 222 #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) 223 224 #define isascii(c) (((unsigned char)(c))<=0x7f) 225 #define toascii(c) (((unsigned char)(c))&0x7f) 226 227 static inline unsigned char __tolower(unsigned char c) 228 { 229 if (isupper(c)) 230 c -= 'A'-'a'; 231 return c; 232 } 233 234 static inline unsigned char __toupper(unsigned char c) 235 { 236 if (islower(c)) 237 c -= 'a'-'A'; 238 return c; 239 } 240 241 int tolower(int c) 242 { 243 return __tolower(c); 244 } 245 246 int toupper(int c) 247 { 248 return __toupper(c); 249 } 250 251 /** 252 * simple_strtoul - convert a string to an unsigned long 253 * @cp: The start of the string 254 * @endp: A pointer to the end of the parsed string will be placed here 255 * @base: The number base to use 256 */ 257 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) 258 { 259 unsigned long result = 0,value; 260 261 if (!base) { 262 base = 10; 263 if (*cp == '0') { 264 base = 8; 265 cp++; 266 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { 267 cp++; 268 base = 16; 269 } 270 } 271 } else if (base == 16) { 272 if (cp[0] == '0' && toupper(cp[1]) == 'X') 273 cp += 2; 274 } 275 while (isxdigit(*cp) && 276 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { 277 result = result*base + value; 278 cp++; 279 } 280 if (endp) 281 *endp = (char *)cp; 282 return result; 283 } 284 285 /** 286 * simple_strtol - convert a string to a signed long 287 * @cp: The start of the string 288 * @endp: A pointer to the end of the parsed string will be placed here 289 * @base: The number base to use 290 */ 291 long simple_strtol(const char *cp,char **endp,unsigned int base) 292 { 293 if(*cp=='-') 294 return -simple_strtoul(cp+1,endp,base); 295 return simple_strtoul(cp,endp,base); 296 } 297 298 /** 299 * simple_strtoull - convert a string to an unsigned long long 300 * @cp: The start of the string 301 * @endp: A pointer to the end of the parsed string will be placed here 302 * @base: The number base to use 303 */ 304 unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) 305 { 306 unsigned long long result = 0, value; 307 308 if (*cp == '0') { 309 cp++; 310 if ((toupper(*cp) == 'X') && isxdigit (cp[1])) { 311 base = 16; 312 cp++; 313 } 314 if (!base) { 315 base = 8; 316 } 317 } 318 if (!base) { 319 base = 10; 320 } 321 while (isxdigit (*cp) && (value = isdigit (*cp) 322 ? *cp - '0' 323 : (islower (*cp) ? toupper (*cp) : *cp) - 'A' + 10) < base) { 324 result = result * base + value; 325 cp++; 326 } 327 if (endp) 328 *endp = (char *) cp; 329 return result; 330 } 331 332 /** 333 * simple_strtoll - convert a string to a signed long long 334 * @cp: The start of the string 335 * @endp: A pointer to the end of the parsed string will be placed here 336 * @base: The number base to use 337 */ 338 long long simple_strtoll(const char *cp,char **endp,unsigned int base) 339 { 340 if(*cp=='-') 341 return -simple_strtoull(cp+1,endp,base); 342 return simple_strtoull(cp,endp,base); 343 } 344 345 /** 346 * vsscanf - Unformat a buffer into a list of arguments 347 * @buf: input buffer 348 * @fmt: format of buffer 349 * @args: arguments 350 */ 351 int vsscanf(const char * buf, const char * fmt, va_list args) 352 { 353 const char *str = buf; 354 char *next; 355 int num = 0; 356 int qualifier; 357 int base; 358 int field_width = -1; 359 int is_sign = 0; 360 361 while(*fmt && *str) { 362 /* skip any white space in format */ 363 /* white space in format matchs any amount of 364 * white space, including none, in the input. 365 */ 366 if (isspace(*fmt)) { 367 while (isspace(*fmt)) 368 ++fmt; 369 while (isspace(*str)) 370 ++str; 371 } 372 373 /* anything that is not a conversion must match exactly */ 374 if (*fmt != '%' && *fmt) { 375 if (*fmt++ != *str++) 376 break; 377 continue; 378 } 379 380 if (!*fmt) 381 break; 382 ++fmt; 383 384 /* skip this conversion. 385 * advance both strings to next white space 386 */ 387 if (*fmt == '*') { 388 while (!isspace(*fmt) && *fmt) 389 fmt++; 390 while (!isspace(*str) && *str) 391 str++; 392 continue; 393 } 394 395 /* get field width */ 396 if (isdigit(*fmt)) 397 field_width = skip_atoi(&fmt); 398 399 /* get conversion qualifier */ 400 qualifier = -1; 401 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z') { 402 qualifier = *fmt; 403 fmt++; 404 } 405 base = 10; 406 is_sign = 0; 407 408 if (!*fmt || !*str) 409 break; 410 411 switch(*fmt++) { 412 case 'c': 413 { 414 char *s = (char *) va_arg(args,char*); 415 if (field_width == -1) 416 field_width = 1; 417 do { 418 *s++ = *str++; 419 } while(field_width-- > 0 && *str); 420 num++; 421 } 422 continue; 423 case 's': 424 { 425 char *s = (char *) va_arg(args, char *); 426 if(field_width == -1) 427 field_width = INT_MAX; 428 /* first, skip leading white space in buffer */ 429 while (isspace(*str)) 430 str++; 431 432 /* now copy until next white space */ 433 while (*str && !isspace(*str) && field_width--) { 434 *s++ = *str++; 435 } 436 *s = '\0'; 437 num++; 438 } 439 continue; 440 case 'n': 441 /* return number of characters read so far */ 442 { 443 int *i = (int *)va_arg(args,int*); 444 *i = str - buf; 445 } 446 continue; 447 case 'o': 448 base = 8; 449 break; 450 case 'x': 451 case 'X': 452 base = 16; 453 break; 454 case 'd': 455 case 'i': 456 is_sign = 1; 457 case 'u': 458 break; 459 case '%': 460 /* looking for '%' in str */ 461 if (*str++ != '%') 462 return num; 463 continue; 464 default: 465 /* invalid format; stop here */ 466 return num; 467 } 468 469 /* have some sort of integer conversion. 470 * first, skip white space in buffer. 471 */ 472 while (isspace(*str)) 473 str++; 474 475 if (!*str || !isdigit(*str)) 476 break; 477 478 switch(qualifier) { 479 case 'h': 480 if (is_sign) { 481 short *s = (short *) va_arg(args,short *); 482 *s = (short) simple_strtol(str,&next,base); 483 } else { 484 unsigned short *s = (unsigned short *) va_arg(args, unsigned short *); 485 *s = (unsigned short) simple_strtoul(str, &next, base); 486 } 487 break; 488 case 'l': 489 if (is_sign) { 490 long *l = (long *) va_arg(args,long *); 491 *l = simple_strtol(str,&next,base); 492 } else { 493 unsigned long *l = (unsigned long*) va_arg(args,unsigned long*); 494 *l = simple_strtoul(str,&next,base); 495 } 496 break; 497 case 'L': 498 if (is_sign) { 499 long long *l = (long long*) va_arg(args,long long *); 500 *l = simple_strtoll(str,&next,base); 501 } else { 502 unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*); 503 *l = simple_strtoull(str,&next,base); 504 } 505 break; 506 case 'Z': 507 { 508 unsigned long *s = (unsigned long*) va_arg(args,unsigned long*); 509 *s = (unsigned long) simple_strtoul(str,&next,base); 510 } 511 break; 512 default: 513 if (is_sign) { 514 int *i = (int *) va_arg(args, int*); 515 *i = (int) simple_strtol(str,&next,base); 516 } else { 517 unsigned int *i = (unsigned int*) va_arg(args, unsigned int*); 518 *i = (unsigned int) simple_strtoul(str,&next,base); 519 } 520 break; 521 } 522 num++; 523 524 if (!next) 525 break; 526 str = next; 527 } 528 return num; 529 } 530 531 /** 532 * sscanf - Unformat a buffer into a list of arguments 533 * @buf: input buffer 534 * @fmt: formatting of buffer 535 * @...: resulting arguments 536 */ 537 int sscanf(const char * buf, const char * fmt, ...) 538 { 539 va_list args; 540 int i; 541 542 va_start(args,fmt); 543 i = vsscanf(buf,fmt,args); 544 va_end(args); 545 546 return i; 547 } 548 549 size_t strspn(const char *s, const char *accept) 550 { 551 size_t l=0; 552 int a=1,i, al=strlen(accept); 553 554 while((a)&&(*s)) 555 { 556 for(a=i=0;(!a)&&(i<al);i++) 557 if (*s==accept[i]) a=1; 558 if (a) l++; 559 s++; 560 } 561 return l; 562 } 563 564 size_t strcspn(const char *s, const char *reject) 565 { 566 size_t l=0; 567 int a=1,i,al=strlen(reject); 568 569 while((a)&&(*s)) 570 { 571 for(i=0;(a)&&(i<al);i++) 572 if (*s==reject[i]) a=0; 573 if (a) l++; 574 s++; 575 } 576 return l; 577 } 578 579 char*strtok_r(char*s,const char*delim,char**ptrptr) 580 { 581 char*tmp=0; 582 583 if (s==0) s=*ptrptr; 584 s += strspn(s,delim); /* overread leading delimiter */ 585 if (*s) 586 { 587 tmp=s; 588 s+=strcspn(s,delim); 589 590 if (*s) *s++=0; /* not the end ? => terminate it */ 591 } 592 *ptrptr=s; 593 return tmp; 594 } 595 596 char *strtok(char *s, const char *delim) 597 { 598 static char *strtok_pos; 599 return strtok_r(s,delim,&strtok_pos); 600 } 601 602 char *strchr(const char *s1, int i) 603 { 604 const unsigned char *s = (const unsigned char *)s1; 605 unsigned char c = (unsigned int)i; 606 607 while (*s && *s != c) 608 { 609 s++; 610 } 611 612 if (*s != c) 613 { 614 s = NULL; 615 } 616 617 return (char *) s; 618 } 619 620 long strtol(const char *str, char **endptr, int base) 621 { 622 return simple_strtol(str, endptr, base); 623 } 624 625 long long strtoll(const char *str, char **endptr, int base) 626 { 627 return simple_strtoll(str, endptr, base); 628 } 629 630 #endif 631