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