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