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