xref: /nrf52832-nimble/rt-thread/components/libc/compilers/minilibc/string.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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