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 */
69size_t
70vsnprintf(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";
104next_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*/
345size_t
346snprintf(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*/
363int
364sprintf(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
375int
376vsprintf(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
385char *
386strcat(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
398char *
399strchr(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
408int
409strcmp(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
417int
418strncmp(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
429static 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
464int
465strcasecmp(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
477int
478strncasecmp(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
492char *
493strcpy(char *s1, const char *s2)
494{
495	char *os1 = s1;
496
497	while ((*s1++ = *s2++) != '\0')
498		;
499	return (os1);
500}
501
502char *
503strncpy(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
516char *
517strrchr(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
529char *
530strstr(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
558char *
559strpbrk(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
573char *
574strncat(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
595size_t
596strlcat(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
617size_t
618strlcpy(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
635size_t
636strspn(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
651size_t
652strcspn(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 */
682char *
683strsep(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)
715char *
716strtok(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 */
752size_t
753strlen(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 */
768size_t
769strnlen(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
795int
796strident_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 */
814void
815strident_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