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