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	/*
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";
102next_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*/
343size_t
344snprintf(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*/
361int
362sprintf(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
373int
374vsprintf(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
383char *
384strcat(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
396char *
397strchr(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
406int
407strcmp(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
415int
416strncmp(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
427static 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
462int
463strcasecmp(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
475int
476strncasecmp(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
490char *
491strcpy(char *s1, const char *s2)
492{
493	char *os1 = s1;
494
495	while ((*s1++ = *s2++) != '\0')
496		;
497	return (os1);
498}
499
500char *
501strncpy(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
514char *
515strrchr(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
527char *
528strstr(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
556char *
557strpbrk(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
571char *
572strncat(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
593size_t
594strlcat(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
615size_t
616strlcpy(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
633size_t
634strspn(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
649size_t
650strcspn(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 */
680char *
681strsep(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)
713char *
714strtok(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 */
750size_t
751strlen(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 */
766size_t
767strnlen(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
793int
794strident_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 */
812void
813strident_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