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