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