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 2018 Nexenta Systems, Inc. 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(3S)). 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 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 if (sign && (int64_t)ul < 0) 255 ul = -ul; 256 else 257 sign = 0; 258 259 if (c == 'b') { 260 bs = va_arg(args, char *); 261 base = *bs++; 262 } 263 264 /* 265 * Fill in the number string buffer and calculate the 266 * number string length. 267 */ 268 tmp = ul; 269 sp = numbuf; 270 do { 271 *sp++ = digits[tmp % base]; 272 numwidth++; 273 } while ((tmp /= base) != 0); 274 275 /* 276 * Reduce the total field width by precision or the number 277 * string length depending on which one is bigger, and sign. 278 */ 279 if (prec >= numwidth) 280 width -= prec; 281 else 282 width -= numwidth; 283 width -= sign; 284 285 /* Add the sign if width is '0'-padded */ 286 if (sign && pad == '0') 287 ADDCHAR('-'); 288 289 /* If not left-aligned, add the width padding */ 290 if (!left_align) { 291 while (width-- > 0) 292 ADDCHAR(pad); 293 } 294 295 /* Add the sign if width is NOT '0'-padded */ 296 if (sign && pad != '0') 297 ADDCHAR('-'); 298 299 /* Add the precision '0'-padding */ 300 while (prec-- > numwidth) 301 ADDCHAR('0'); 302 303 /* Print out the number */ 304 while (sp > numbuf) { 305 sp--; 306 ADDCHAR(*sp); 307 } 308 309 /* Add left-alignment padding */ 310 while (width-- > 0) 311 ADDCHAR(' '); 312 313 if (c == 'b' && ul != 0) { 314 int any = 0; 315 c = *bs++; 316 while (c != 0) { 317 if (ul & (1 << (c - 1))) { 318 if (any++ == 0) 319 ADDCHAR('<'); 320 while ((c = *bs++) >= 32) 321 ADDCHAR(c); 322 ADDCHAR(','); 323 } else { 324 while ((c = *bs++) >= 32) 325 continue; 326 } 327 } 328 if (any) { 329 bufp--; 330 ADDCHAR('>'); 331 } 332 } 333 } 334 if (bufp - buf < buflen) 335 bufp[0] = c; 336 else if (buflen != 0) 337 buf[buflen - 1] = c; 338 339 va_end(args); 340 341 return (bufp - buf); 342 } 343 344 /*PRINTFLIKE3*/ 345 size_t 346 snprintf(char *buf, size_t buflen, const char *fmt, ...) 347 { 348 va_list args; 349 350 va_start(args, fmt); 351 buflen = vsnprintf(buf, buflen, fmt, args); 352 va_end(args); 353 354 return (buflen); 355 } 356 357 #if defined(_BOOT) && defined(__sparc) 358 /* 359 * The sprintf() and vsprintf() routines aren't shared with the kernel because 360 * the DDI mandates that they return the buffer rather than its length. 361 */ 362 /*PRINTFLIKE2*/ 363 int 364 sprintf(char *buf, const char *fmt, ...) 365 { 366 va_list args; 367 368 va_start(args, fmt); 369 (void) vsnprintf(buf, INT_MAX, fmt, args); 370 va_end(args); 371 372 return (strlen(buf)); 373 } 374 375 int 376 vsprintf(char *buf, const char *fmt, va_list args) 377 { 378 (void) vsnprintf(buf, INT_MAX, fmt, args); 379 return (strlen(buf)); 380 } 381 #endif /* _BOOT && __sparc */ 382 383 #endif /* !_KMDB && (!_BOOT || __sparc) */ 384 385 char * 386 strcat(char *s1, const char *s2) 387 { 388 char *os1 = s1; 389 390 while (*s1++ != '\0') 391 ; 392 s1--; 393 while ((*s1++ = *s2++) != '\0') 394 ; 395 return (os1); 396 } 397 398 char * 399 strchr(const char *sp, int c) 400 { 401 do { 402 if (*sp == (char)c) 403 return ((char *)sp); 404 } while (*sp++); 405 return (NULL); 406 } 407 408 int 409 strcmp(const char *s1, const char *s2) 410 { 411 while (*s1 == *s2++) 412 if (*s1++ == '\0') 413 return (0); 414 return (*(unsigned char *)s1 - *(unsigned char *)--s2); 415 } 416 417 int 418 strncmp(const char *s1, const char *s2, size_t n) 419 { 420 if (s1 == s2) 421 return (0); 422 n++; 423 while (--n != 0 && *s1 == *s2++) 424 if (*s1++ == '\0') 425 return (0); 426 return ((n == 0) ? 0 : *(unsigned char *)s1 - *(unsigned char *)--s2); 427 } 428 429 static const char charmap[] = { 430 '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', 431 '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', 432 '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', 433 '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', 434 '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', 435 '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', 436 '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', 437 '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', 438 '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', 439 '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', 440 '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', 441 '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', 442 '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', 443 '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', 444 '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', 445 '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', 446 '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', 447 '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', 448 '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', 449 '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', 450 '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', 451 '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', 452 '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', 453 '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', 454 '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', 455 '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', 456 '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', 457 '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', 458 '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', 459 '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', 460 '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', 461 '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', 462 }; 463 464 int 465 strcasecmp(const char *s1, const char *s2) 466 { 467 const unsigned char *cm = (const unsigned char *)charmap; 468 const unsigned char *us1 = (const unsigned char *)s1; 469 const unsigned char *us2 = (const unsigned char *)s2; 470 471 while (cm[*us1] == cm[*us2++]) 472 if (*us1++ == '\0') 473 return (0); 474 return (cm[*us1] - cm[*(us2 - 1)]); 475 } 476 477 int 478 strncasecmp(const char *s1, const char *s2, size_t n) 479 { 480 const unsigned char *cm = (const unsigned char *)charmap; 481 const unsigned char *us1 = (const unsigned char *)s1; 482 const unsigned char *us2 = (const unsigned char *)s2; 483 484 while (n != 0 && cm[*us1] == cm[*us2++]) { 485 if (*us1++ == '\0') 486 return (0); 487 n--; 488 } 489 return (n == 0 ? 0 : cm[*us1] - cm[*(us2 - 1)]); 490 } 491 492 char * 493 strcpy(char *s1, const char *s2) 494 { 495 char *os1 = s1; 496 497 while ((*s1++ = *s2++) != '\0') 498 ; 499 return (os1); 500 } 501 502 char * 503 strncpy(char *s1, const char *s2, size_t n) 504 { 505 char *os1 = s1; 506 507 n++; 508 while (--n != 0 && (*s1++ = *s2++) != '\0') 509 ; 510 if (n != 0) 511 while (--n != 0) 512 *s1++ = '\0'; 513 return (os1); 514 } 515 516 char * 517 strrchr(const char *sp, int c) 518 { 519 char *r = NULL; 520 521 do { 522 if (*sp == (char)c) 523 r = (char *)sp; 524 } while (*sp++); 525 526 return (r); 527 } 528 529 char * 530 strstr(const char *as1, const char *as2) 531 { 532 const char *s1, *s2; 533 const char *tptr; 534 char c; 535 536 s1 = as1; 537 s2 = as2; 538 539 if (s2 == NULL || *s2 == '\0') 540 return ((char *)s1); 541 c = *s2; 542 543 while (*s1) 544 if (*s1++ == c) { 545 tptr = s1; 546 while ((c = *++s2) == *s1++ && c) 547 ; 548 if (c == 0) 549 return ((char *)tptr - 1); 550 s1 = tptr; 551 s2 = as2; 552 c = *s2; 553 } 554 555 return (NULL); 556 } 557 558 char * 559 strpbrk(const char *string, const char *brkset) 560 { 561 const char *p; 562 563 do { 564 for (p = brkset; *p != '\0' && *p != *string; ++p) 565 ; 566 if (*p != '\0') 567 return ((char *)string); 568 } while (*string++); 569 570 return (NULL); 571 } 572 573 char * 574 strncat(char *s1, const char *s2, size_t n) 575 { 576 char *os1 = s1; 577 578 n++; 579 while (*s1++ != '\0') 580 ; 581 --s1; 582 while ((*s1++ = *s2++) != '\0') { 583 if (--n == 0) { 584 s1[-1] = '\0'; 585 break; 586 } 587 } 588 return (os1); 589 } 590 591 #if defined(_BOOT) || defined(_KMDB) 592 #define bcopy(src, dst, n) (void) memcpy((dst), (src), (n)) 593 #endif 594 595 size_t 596 strlcat(char *dst, const char *src, size_t dstsize) 597 { 598 char *df = dst; 599 size_t left = dstsize; 600 size_t l1; 601 size_t l2 = strlen(src); 602 size_t copied; 603 604 while (left-- != 0 && *df != '\0') 605 df++; 606 /*LINTED: possible ptrdiff_t overflow*/ 607 l1 = (size_t)(df - dst); 608 if (dstsize == l1) 609 return (l1 + l2); 610 611 copied = l1 + l2 >= dstsize ? dstsize - l1 - 1 : l2; 612 bcopy(src, dst + l1, copied); 613 dst[l1+copied] = '\0'; 614 return (l1 + l2); 615 } 616 617 size_t 618 strlcpy(char *dst, const char *src, size_t len) 619 { 620 size_t slen = strlen(src); 621 size_t copied; 622 623 if (len == 0) 624 return (slen); 625 626 if (slen >= len) 627 copied = len - 1; 628 else 629 copied = slen; 630 bcopy(src, dst, copied); 631 dst[copied] = '\0'; 632 return (slen); 633 } 634 635 size_t 636 strspn(const char *string, const char *charset) 637 { 638 const char *p, *q; 639 640 for (q = string; *q != '\0'; ++q) { 641 for (p = charset; *p != '\0' && *p != *q; ++p) 642 ; 643 if (*p == '\0') 644 break; 645 } 646 647 /*LINTED: possible ptrdiff_t overflow*/ 648 return ((size_t)(q - string)); 649 } 650 651 size_t 652 strcspn(const char *string, const char *charset) 653 { 654 const char *p, *q; 655 656 for (q = string; *q != '\0'; ++q) { 657 for (p = charset; *p != '\0' && *p != *q; ++p) 658 ; 659 if (*p != '\0') 660 break; 661 } 662 663 /*LINTED E_PTRDIFF_OVERFLOW*/ 664 return ((size_t)(q - string)); 665 } 666 667 /* 668 * strsep 669 * 670 * The strsep() function locates, in the string referenced by *stringp, the 671 * first occurrence of any character in the string delim (or the terminating 672 * `\0' character) and replaces it with a `\0'. The location of the next 673 * character after the delimiter character (or NULL, if the end of the 674 * string was reached) is stored in *stringp. The original value of 675 * *stringp is returned. 676 * 677 * If *stringp is initially NULL, strsep() returns NULL. 678 * 679 * NOTE: This instance is left for in-kernel use. Libraries and programs 680 * should use strsep from libc. 681 */ 682 char * 683 strsep(char **stringp, const char *delim) 684 { 685 char *s; 686 const char *spanp; 687 int c, sc; 688 char *tok; 689 690 if ((s = *stringp) == NULL) 691 return (NULL); 692 693 for (tok = s; ; ) { 694 c = *s++; 695 spanp = delim; 696 do { 697 if ((sc = *spanp++) == c) { 698 if (c == 0) 699 s = NULL; 700 else 701 s[-1] = 0; 702 *stringp = s; 703 return (tok); 704 } 705 } while (sc != 0); 706 } 707 /* NOTREACHED */ 708 } 709 710 /* 711 * Unless mentioned otherwise, all of the routines below should be added to 712 * the Solaris DDI as necessary. For now, only provide them to standalone. 713 */ 714 #if defined(_BOOT) || defined(_KMDB) 715 char * 716 strtok(char *string, const char *sepset) 717 { 718 char *p, *q, *r; 719 static char *savept; 720 721 /* 722 * Set `p' to our current location in the string. 723 */ 724 p = (string == NULL) ? savept : string; 725 if (p == NULL) 726 return (NULL); 727 728 /* 729 * Skip leading separators; bail if no tokens remain. 730 */ 731 q = p + strspn(p, sepset); 732 if (*q == '\0') 733 return (NULL); 734 735 /* 736 * Mark the end of the token and set `savept' for the next iteration. 737 */ 738 if ((r = strpbrk(q, sepset)) == NULL) 739 savept = NULL; 740 else { 741 *r = '\0'; 742 savept = ++r; 743 } 744 745 return (q); 746 } 747 748 /* 749 * The strlen() routine isn't shared with the kernel because it has its own 750 * hand-tuned assembly version. 751 */ 752 size_t 753 strlen(const char *s) 754 { 755 size_t n = 0; 756 757 while (*s++) 758 n++; 759 return (n); 760 } 761 762 #endif /* _BOOT || _KMDB */ 763 764 /* 765 * Returns the number of non-NULL bytes in string argument, 766 * but not more than maxlen. Does not look past str + maxlen. 767 */ 768 size_t 769 strnlen(const char *s, size_t maxlen) 770 { 771 size_t n = 0; 772 773 while (maxlen != 0 && *s != 0) { 774 s++; 775 maxlen--; 776 n++; 777 } 778 779 return (n); 780 } 781 782 783 #ifdef _KERNEL 784 /* 785 * Check for a valid C identifier: 786 * a letter or underscore, followed by 787 * zero or more letters, digits and underscores. 788 */ 789 790 #define IS_DIGIT(c) ((c) >= '0' && (c) <= '9') 791 792 #define IS_ALPHA(c) \ 793 (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) 794 795 int 796 strident_valid(const char *id) 797 { 798 int c = *id++; 799 800 if (!IS_ALPHA(c) && c != '_') 801 return (0); 802 while ((c = *id++) != 0) { 803 if (!IS_ALPHA(c) && !IS_DIGIT(c) && c != '_') 804 return (0); 805 } 806 return (1); 807 } 808 809 /* 810 * Convert a string into a valid C identifier by replacing invalid 811 * characters with '_'. Also makes sure the string is nul-terminated 812 * and takes up at most n bytes. 813 */ 814 void 815 strident_canon(char *s, size_t n) 816 { 817 char c; 818 char *end = s + n - 1; 819 820 ASSERT(n > 0); 821 822 if ((c = *s) == 0) 823 return; 824 825 if (!IS_ALPHA(c) && c != '_') 826 *s = '_'; 827 828 while (s < end && ((c = *(++s)) != 0)) { 829 if (!IS_ALPHA(c) && !IS_DIGIT(c) && c != '_') 830 *s = '_'; 831 } 832 *s = 0; 833 } 834 835 #endif /* _KERNEL */ 836