xref: /illumos-gate/usr/src/common/util/string.c (revision ff56787d6488797571f1eaba7dcf3ff9903154ba)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright 2014 Joyent, Inc.  All rights reserved.
25  */
26 
27 /*
28  * Copyright (c) 2016 by Delphix. All rights reserved.
29  * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
30  */
31 
32 /*
33  * Implementations of the functions described in vsnprintf(3C) and string(3C),
34  * for use by the kernel, the standalone, and kmdb.  Unless otherwise specified,
35  * these functions match the section 3C manpages.
36  */
37 
38 #include <sys/types.h>
39 #include <sys/null.h>
40 #include <sys/varargs.h>
41 #include <sys/stdbool.h>
42 
43 #if defined(_KERNEL)
44 #include <sys/systm.h>
45 #include <sys/debug.h>
46 #elif !defined(_BOOT)
47 #include <string.h>
48 #endif
49 
50 #include "memcpy.h"
51 #include "string.h"
52 
53 /*
54  * We don't need these for x86 boot or kmdb.
55  */
56 #if !defined(_KMDB) && (!defined(_BOOT) || defined(__sparc))
57 
58 #define	ADDCHAR(c)	if (bufp++ - buf < buflen) bufp[-1] = (c)
59 
60 /*
61  * Given a buffer 'buf' of size 'buflen', render as much of the string
62  * described by <fmt, args> as possible.  The string will always be
63  * null-terminated, so the maximum string length is 'buflen - 1'.
64  * Returns the number of bytes that would be necessary to render the
65  * entire string, not including null terminator (just like vsnprintf(3C)).
66  * To determine buffer size in advance, use vsnprintf(NULL, 0, fmt, args) + 1.
67  *
68  * There is no support for floating point, and the C locale is assumed.
69  */
70 size_t
71 vsnprintf(char *buf, size_t buflen, const char *fmt, va_list aargs)
72 {
73 	uintmax_t ul, tmp;
74 	char *bufp = buf;	/* current buffer pointer */
75 	char c, pad;
76 	int width, base, sign, num;
77 	int prec, h_count, l_count, dot_count;
78 	bool zflag, jflag;
79 	int pad_count, transfer_count, left_align;
80 	char *digits, *sp, *bs;
81 	char numbuf[65];	/* sufficient for a 64-bit binary value */
82 	int numwidth;
83 	va_list args;
84 
85 	ul = 0;
86 	bs = NULL;
87 	/*
88 	 * Make a copy so that all our callers don't have to make a copy
89 	 */
90 	va_copy(args, aargs);
91 
92 	if ((ssize_t)buflen < 0)
93 		buflen = 0;
94 
95 	while ((c = *fmt++) != '\0') {
96 		if (c != '%') {
97 			ADDCHAR(c);
98 			continue;
99 		}
100 
101 		zflag = jflag = false;
102 		width = prec = numwidth = 0;
103 		left_align = base = sign = 0;
104 		h_count = l_count = dot_count = 0;
105 		pad = ' ';
106 		digits = "0123456789abcdef";
107 next_fmt:
108 		if ((c = *fmt++) == '\0')
109 			break;
110 
111 		if (c >= 'A' && c <= 'Z') {
112 			c += 'a' - 'A';
113 			digits = "0123456789ABCDEF";
114 		}
115 
116 		switch (c) {
117 		case '-':
118 			left_align++;
119 			goto next_fmt;
120 		case '0':
121 			if (dot_count == 0)
122 				pad = '0';
123 			/*FALLTHROUGH*/
124 		case '1':
125 		case '2':
126 		case '3':
127 		case '4':
128 		case '5':
129 		case '6':
130 		case '7':
131 		case '8':
132 		case '9':
133 			num = 0;
134 			for (;;) {
135 				num = 10 * num + c - '0';
136 				c = *fmt;
137 				if (c < '0' || c > '9')
138 					break;
139 				else
140 					fmt++;
141 			}
142 			if (dot_count > 0)
143 				prec = num;
144 			else
145 				width = num;
146 
147 			goto next_fmt;
148 		case '.':
149 			dot_count++;
150 			goto next_fmt;
151 		case '*':
152 			if (dot_count > 0)
153 				prec = (int)va_arg(args, int);
154 			else
155 				width = (int)va_arg(args, int);
156 			goto next_fmt;
157 		case 'l':
158 			l_count++;
159 			goto next_fmt;
160 		case 'h':
161 			h_count++;
162 			goto next_fmt;
163 		case 'j':
164 			jflag = true;
165 			goto next_fmt;
166 		case 'd':
167 			sign = 1;
168 			/*FALLTHROUGH*/
169 		case 'u':
170 			base = 10;
171 			break;
172 		case 'p':
173 			l_count = 1;
174 			/*FALLTHROUGH*/
175 		case 'x':
176 			base = 16;
177 			break;
178 		case 'o':
179 			base = 8;
180 			break;
181 		case 'b':
182 			l_count = 0;
183 			base = 1;
184 			break;
185 		case 'c':
186 			c = (char)va_arg(args, int);
187 			ADDCHAR(c);
188 			break;
189 		case 's':
190 			sp = va_arg(args, char *);
191 			if (sp == NULL) {
192 				sp = "<null string>";
193 				/* avoid truncation */
194 				prec = strlen(sp);
195 			}
196 			/*
197 			 * Handle simple case specially to avoid
198 			 * performance hit of strlen()
199 			 */
200 			if (prec == 0 && width == 0) {
201 				while ((c = *sp++) != 0)
202 					ADDCHAR(c);
203 				break;
204 			}
205 			if (prec > 0) {
206 				transfer_count = strnlen(sp, prec);
207 				/* widen field if too narrow */
208 				if (prec > width)
209 					width = prec;
210 			} else
211 				transfer_count = strlen(sp);
212 			if (width > transfer_count)
213 				pad_count = width - transfer_count;
214 			else
215 				pad_count = 0;
216 			while ((!left_align) && (pad_count-- > 0))
217 				ADDCHAR(' ');
218 			/* ADDCHAR() evaluates arg at most once */
219 			while (transfer_count-- > 0)
220 				ADDCHAR(*sp++);
221 			while ((left_align) && (pad_count-- > 0))
222 				ADDCHAR(' ');
223 			break;
224 		case 'z':
225 			zflag = true;
226 			goto next_fmt;
227 		case '%':
228 			ADDCHAR('%');
229 			break;
230 		}
231 
232 		if (base == 0)
233 			continue;
234 
235 		if (jflag) {
236 			if (sign)
237 				ul = va_arg(args, intmax_t);
238 			else
239 				ul = va_arg(args, uintmax_t);
240 		} else if (zflag) {
241 			if (sign)
242 				ul = va_arg(args, ssize_t);
243 			else
244 				ul = va_arg(args, size_t);
245 		} else if (h_count == 0 && l_count == 0) {
246 			if (sign)
247 				ul = va_arg(args, int);
248 			else
249 				ul = va_arg(args, unsigned int);
250 		} else if (l_count > 1) {
251 			if (sign)
252 				ul = va_arg(args, int64_t);
253 			else
254 				ul = va_arg(args, uint64_t);
255 		} else if (l_count > 0) {
256 			if (sign)
257 				ul = va_arg(args, long);
258 			else
259 				ul = va_arg(args, unsigned long);
260 		} else if (h_count > 1) {
261 			if (sign)
262 				ul = (signed char)va_arg(args, int);
263 			else
264 				ul = (unsigned char)va_arg(args, int);
265 		} else if (h_count > 0) {
266 			if (sign)
267 				ul = (short)va_arg(args, int);
268 			else
269 				ul = (unsigned short)va_arg(args, int);
270 		}
271 
272 		if (sign && (intmax_t)ul < 0)
273 			ul = -ul;
274 		else
275 			sign = 0;
276 
277 		if (c == 'b') {
278 			bs = va_arg(args, char *);
279 			base = *bs++;
280 		}
281 
282 		/*
283 		 * Fill in the number string buffer and calculate the
284 		 * number string length.
285 		 */
286 		tmp = ul;
287 		sp = numbuf;
288 		do {
289 			*sp++ = digits[tmp % base];
290 			numwidth++;
291 		} while ((tmp /= base) != 0);
292 
293 		/*
294 		 * Reduce the total field width by precision or the number
295 		 * string length depending on which one is bigger, and sign.
296 		 */
297 		if (prec >= numwidth)
298 			width -= prec;
299 		else
300 			width -= numwidth;
301 		width -= sign;
302 
303 		/* Add the sign if width is '0'-padded */
304 		if (sign && pad == '0')
305 			ADDCHAR('-');
306 
307 		/* If not left-aligned, add the width padding */
308 		if (!left_align) {
309 			while (width-- > 0)
310 				ADDCHAR(pad);
311 		}
312 
313 		/* Add the sign if width is NOT '0'-padded */
314 		if (sign && pad != '0')
315 			ADDCHAR('-');
316 
317 		/* Add the precision '0'-padding */
318 		while (prec-- > numwidth)
319 			ADDCHAR('0');
320 
321 		/* Print out the number */
322 		while (sp > numbuf) {
323 			sp--;
324 			ADDCHAR(*sp);
325 		}
326 
327 		/* Add left-alignment padding */
328 		while (width-- > 0)
329 			ADDCHAR(' ');
330 
331 		if (c == 'b' && ul != 0) {
332 			int any = 0;
333 			c = *bs++;
334 			while (c != 0) {
335 				if (ul & (1 << (c - 1))) {
336 					if (any++ == 0)
337 						ADDCHAR('<');
338 					while ((c = *bs++) > 32)
339 						ADDCHAR(c);
340 					ADDCHAR(',');
341 				} else {
342 					while ((c = *bs++) > 32)
343 						continue;
344 				}
345 			}
346 			if (any) {
347 				bufp--;
348 				ADDCHAR('>');
349 			}
350 		}
351 	}
352 	if (bufp - buf < buflen)
353 		bufp[0] = c;
354 	else if (buflen != 0)
355 		buf[buflen - 1] = c;
356 
357 	va_end(args);
358 
359 	return (bufp - buf);
360 }
361 
362 /*PRINTFLIKE3*/
363 size_t
364 snprintf(char *buf, size_t buflen, const char *fmt, ...)
365 {
366 	va_list args;
367 
368 	va_start(args, fmt);
369 	buflen = vsnprintf(buf, buflen, fmt, args);
370 	va_end(args);
371 
372 	return (buflen);
373 }
374 
375 #if defined(_BOOT) && defined(__sparc)
376 /*
377  * The sprintf() and vsprintf() routines aren't shared with the kernel because
378  * the DDI mandates that they return the buffer rather than its length.
379  */
380 /*PRINTFLIKE2*/
381 int
382 sprintf(char *buf, const char *fmt, ...)
383 {
384 	va_list args;
385 
386 	va_start(args, fmt);
387 	(void) vsnprintf(buf, INT_MAX, fmt, args);
388 	va_end(args);
389 
390 	return (strlen(buf));
391 }
392 
393 int
394 vsprintf(char *buf, const char *fmt, va_list args)
395 {
396 	(void) vsnprintf(buf, INT_MAX, fmt, args);
397 	return (strlen(buf));
398 }
399 #endif /* _BOOT && __sparc */
400 
401 #endif /* !_KMDB && (!_BOOT || __sparc) */
402 
403 char *
404 strcat(char *s1, const char *s2)
405 {
406 	char *os1 = s1;
407 
408 	while (*s1++ != '\0')
409 		;
410 	s1--;
411 	while ((*s1++ = *s2++) != '\0')
412 		;
413 	return (os1);
414 }
415 
416 char *
417 strchr(const char *sp, int c)
418 {
419 	do {
420 		if (*sp == (char)c)
421 			return ((char *)sp);
422 	} while (*sp++);
423 	return (NULL);
424 }
425 
426 int
427 strcmp(const char *s1, const char *s2)
428 {
429 	while (*s1 == *s2++)
430 		if (*s1++ == '\0')
431 			return (0);
432 	return (*(unsigned char *)s1 - *(unsigned char *)--s2);
433 }
434 
435 int
436 strncmp(const char *s1, const char *s2, size_t n)
437 {
438 	if (s1 == s2)
439 		return (0);
440 	n++;
441 	while (--n != 0 && *s1 == *s2++)
442 		if (*s1++ == '\0')
443 			return (0);
444 	return ((n == 0) ? 0 : *(unsigned char *)s1 - *(unsigned char *)--s2);
445 }
446 
447 static const char charmap[] = {
448 	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
449 	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
450 	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
451 	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
452 	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
453 	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
454 	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
455 	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
456 	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
457 	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
458 	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
459 	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
460 	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
461 	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
462 	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
463 	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
464 	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
465 	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
466 	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
467 	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
468 	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
469 	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
470 	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
471 	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
472 	'\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
473 	'\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
474 	'\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
475 	'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
476 	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
477 	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
478 	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
479 	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
480 };
481 
482 int
483 strcasecmp(const char *s1, const char *s2)
484 {
485 	const unsigned char *cm = (const unsigned char *)charmap;
486 	const unsigned char *us1 = (const unsigned char *)s1;
487 	const unsigned char *us2 = (const unsigned char *)s2;
488 
489 	while (cm[*us1] == cm[*us2++])
490 		if (*us1++ == '\0')
491 			return (0);
492 	return (cm[*us1] - cm[*(us2 - 1)]);
493 }
494 
495 int
496 strncasecmp(const char *s1, const char *s2, size_t n)
497 {
498 	const unsigned char *cm = (const unsigned char *)charmap;
499 	const unsigned char *us1 = (const unsigned char *)s1;
500 	const unsigned char *us2 = (const unsigned char *)s2;
501 
502 	while (n != 0 && cm[*us1] == cm[*us2++]) {
503 		if (*us1++ == '\0')
504 			return (0);
505 		n--;
506 	}
507 	return (n == 0 ? 0 : cm[*us1] - cm[*(us2 - 1)]);
508 }
509 
510 char *
511 strcpy(char *s1, const char *s2)
512 {
513 	char *os1 = s1;
514 
515 	while ((*s1++ = *s2++) != '\0')
516 		;
517 	return (os1);
518 }
519 
520 char *
521 strncpy(char *s1, const char *s2, size_t n)
522 {
523 	char *os1 = s1;
524 
525 	n++;
526 	while (--n != 0 && (*s1++ = *s2++) != '\0')
527 		;
528 	if (n != 0)
529 		while (--n != 0)
530 			*s1++ = '\0';
531 	return (os1);
532 }
533 
534 char *
535 strrchr(const char *sp, int c)
536 {
537 	char *r = NULL;
538 
539 	do {
540 		if (*sp == (char)c)
541 			r = (char *)sp;
542 	} while (*sp++);
543 
544 	return (r);
545 }
546 
547 char *
548 strstr(const char *as1, const char *as2)
549 {
550 	const char *s1, *s2;
551 	const char *tptr;
552 	char c;
553 
554 	s1 = as1;
555 	s2 = as2;
556 
557 	if (s2 == NULL || *s2 == '\0')
558 		return ((char *)s1);
559 	c = *s2;
560 
561 	while (*s1)
562 		if (*s1++ == c) {
563 			tptr = s1;
564 			while ((c = *++s2) == *s1++ && c)
565 				;
566 			if (c == 0)
567 				return ((char *)tptr - 1);
568 			s1 = tptr;
569 			s2 = as2;
570 			c = *s2;
571 		}
572 
573 	return (NULL);
574 }
575 
576 char *
577 strpbrk(const char *string, const char *brkset)
578 {
579 	const char *p;
580 
581 	do {
582 		for (p = brkset; *p != '\0' && *p != *string; ++p)
583 			;
584 		if (*p != '\0')
585 			return ((char *)string);
586 	} while (*string++);
587 
588 	return (NULL);
589 }
590 
591 char *
592 strncat(char *s1, const char *s2, size_t n)
593 {
594 	char *os1 = s1;
595 
596 	n++;
597 	while (*s1++ != '\0')
598 		;
599 	--s1;
600 	while ((*s1++ = *s2++) != '\0') {
601 		if (--n == 0) {
602 			s1[-1] = '\0';
603 			break;
604 		}
605 	}
606 	return (os1);
607 }
608 
609 #if defined(_BOOT) || defined(_KMDB)
610 #define	bcopy(src, dst, n)	(void) memcpy((dst), (src), (n))
611 #endif
612 
613 size_t
614 strlcat(char *dst, const char *src, size_t dstsize)
615 {
616 	char *df = dst;
617 	size_t left = dstsize;
618 	size_t l1;
619 	size_t l2 = strlen(src);
620 	size_t copied;
621 
622 	while (left-- != 0 && *df != '\0')
623 		df++;
624 	/*LINTED: possible ptrdiff_t overflow*/
625 	l1 = (size_t)(df - dst);
626 	if (dstsize == l1)
627 		return (l1 + l2);
628 
629 	copied = l1 + l2 >= dstsize ? dstsize - l1 - 1 : l2;
630 	bcopy(src, dst + l1, copied);
631 	dst[l1+copied] = '\0';
632 	return (l1 + l2);
633 }
634 
635 size_t
636 strlcpy(char *dst, const char *src, size_t len)
637 {
638 	size_t slen = strlen(src);
639 	size_t copied;
640 
641 	if (len == 0)
642 		return (slen);
643 
644 	if (slen >= len)
645 		copied = len - 1;
646 	else
647 		copied = slen;
648 	bcopy(src, dst, copied);
649 	dst[copied] = '\0';
650 	return (slen);
651 }
652 
653 size_t
654 strspn(const char *string, const char *charset)
655 {
656 	const char *p, *q;
657 
658 	for (q = string; *q != '\0'; ++q) {
659 		for (p = charset; *p != '\0' && *p != *q; ++p)
660 			;
661 		if (*p == '\0')
662 			break;
663 	}
664 
665 	/*LINTED: possible ptrdiff_t overflow*/
666 	return ((size_t)(q - string));
667 }
668 
669 size_t
670 strcspn(const char *string, const char *charset)
671 {
672 	const char *p, *q;
673 
674 	for (q = string; *q != '\0'; ++q) {
675 		for (p = charset; *p != '\0' && *p != *q; ++p)
676 			;
677 		if (*p != '\0')
678 			break;
679 	}
680 
681 	/*LINTED E_PTRDIFF_OVERFLOW*/
682 	return ((size_t)(q - string));
683 }
684 
685 /*
686  * strsep
687  *
688  * The strsep() function locates, in the string referenced by *stringp, the
689  * first occurrence of any character in the string delim (or the terminating
690  * `\0' character) and replaces it with a `\0'.  The location of the next
691  * character after the delimiter character (or NULL, if the end of the
692  * string was reached) is stored in *stringp.  The original value of
693  * *stringp is returned.
694  *
695  * If *stringp is initially NULL, strsep() returns NULL.
696  *
697  * NOTE: This instance is left for in-kernel use. Libraries and programs
698  *       should use strsep from libc.
699  */
700 char *
701 strsep(char **stringp, const char *delim)
702 {
703 	char *s;
704 	const char *spanp;
705 	int c, sc;
706 	char *tok;
707 
708 	if ((s = *stringp) == NULL)
709 		return (NULL);
710 
711 	for (tok = s; ; ) {
712 		c = *s++;
713 		spanp = delim;
714 		do {
715 			if ((sc = *spanp++) == c) {
716 				if (c == 0)
717 					s = NULL;
718 				else
719 					s[-1] = 0;
720 				*stringp = s;
721 				return (tok);
722 			}
723 		} while (sc != 0);
724 	}
725 	/* NOTREACHED */
726 }
727 
728 /*
729  * strtok_r
730  *
731  * uses strpbrk and strspn to break string into tokens on
732  * sequentially subsequent calls.  returns NULL when no
733  * non-separator characters remain.
734  * `subsequent' calls are calls with first argument NULL.
735  */
736 char *
737 strtok_r(char *string, const char *sepset, char **lasts)
738 {
739 	char	*q, *r;
740 
741 	/* first or subsequent call */
742 	if (string == NULL)
743 		string = *lasts;
744 
745 	if (string == NULL)		/* return if no tokens remaining */
746 		return (NULL);
747 
748 	q = string + strspn(string, sepset);	/* skip leading separators */
749 
750 	if (*q == '\0')		/* return if no tokens remaining */
751 		return (NULL);
752 
753 	if ((r = strpbrk(q, sepset)) == NULL) {	/* move past token */
754 		*lasts = NULL;	/* indicate this is last token */
755 	} else {
756 		*r = '\0';
757 		*lasts = r + 1;
758 	}
759 	return (q);
760 }
761 
762 /*
763  * Unless mentioned otherwise, all of the routines below should be added to
764  * the Solaris DDI as necessary.  For now, only provide them to standalone.
765  */
766 #if defined(_BOOT) || defined(_KMDB)
767 char *
768 strtok(char *string, const char *sepset)
769 {
770 	char		*p, *q, *r;
771 	static char	*savept;
772 
773 	/*
774 	 * Set `p' to our current location in the string.
775 	 */
776 	p = (string == NULL) ? savept : string;
777 	if (p == NULL)
778 		return (NULL);
779 
780 	/*
781 	 * Skip leading separators; bail if no tokens remain.
782 	 */
783 	q = p + strspn(p, sepset);
784 	if (*q == '\0')
785 		return (NULL);
786 
787 	/*
788 	 * Mark the end of the token and set `savept' for the next iteration.
789 	 */
790 	if ((r = strpbrk(q, sepset)) == NULL)
791 		savept = NULL;
792 	else {
793 		*r = '\0';
794 		savept = ++r;
795 	}
796 
797 	return (q);
798 }
799 
800 /*
801  * The strlen() routine isn't shared with the kernel because it has its own
802  * hand-tuned assembly version.
803  */
804 size_t
805 strlen(const char *s)
806 {
807 	size_t n = 0;
808 
809 	while (*s++)
810 		n++;
811 	return (n);
812 }
813 
814 #endif /* _BOOT || _KMDB */
815 
816 /*
817  * Returns the number of non-NULL bytes in string argument,
818  * but not more than maxlen.  Does not look past str + maxlen.
819  */
820 size_t
821 strnlen(const char *s, size_t maxlen)
822 {
823 	size_t n = 0;
824 
825 	while (maxlen != 0 && *s != 0) {
826 		s++;
827 		maxlen--;
828 		n++;
829 	}
830 
831 	return (n);
832 }
833 
834 
835 #ifdef _KERNEL
836 /*
837  * Check for a valid C identifier:
838  *	a letter or underscore, followed by
839  *	zero or more letters, digits and underscores.
840  */
841 
842 #define	IS_DIGIT(c)	((c) >= '0' && (c) <= '9')
843 
844 #define	IS_ALPHA(c)	\
845 	(((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
846 
847 int
848 strident_valid(const char *id)
849 {
850 	int c = *id++;
851 
852 	if (!IS_ALPHA(c) && c != '_')
853 		return (0);
854 	while ((c = *id++) != 0) {
855 		if (!IS_ALPHA(c) && !IS_DIGIT(c) && c != '_')
856 			return (0);
857 	}
858 	return (1);
859 }
860 
861 /*
862  * Convert a string into a valid C identifier by replacing invalid
863  * characters with '_'.  Also makes sure the string is nul-terminated
864  * and takes up at most n bytes.
865  */
866 void
867 strident_canon(char *s, size_t n)
868 {
869 	char c;
870 	char *end = s + n - 1;
871 
872 	ASSERT(n > 0);
873 
874 	if ((c = *s) == 0)
875 		return;
876 
877 	if (!IS_ALPHA(c) && c != '_')
878 		*s = '_';
879 
880 	while (s < end && ((c = *(++s)) != 0)) {
881 		if (!IS_ALPHA(c) && !IS_DIGIT(c) && c != '_')
882 			*s = '_';
883 	}
884 	*s = 0;
885 }
886 
887 #endif	/* _KERNEL */
888