xref: /onnv-gate/usr/src/common/util/string.c (revision 941)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*941Smyers  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Implementations of the functions described in vsnprintf(3C) and string(3C),
310Sstevel@tonic-gate  * for use by the kernel, the standalone, and kmdb.  Unless otherwise specified,
320Sstevel@tonic-gate  * these functions match the section 3C manpages.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/varargs.h>
370Sstevel@tonic-gate #if defined(_BOOT) || defined(_KMDB)
380Sstevel@tonic-gate #include <string.h>
390Sstevel@tonic-gate #else
400Sstevel@tonic-gate #include <sys/systm.h>
410Sstevel@tonic-gate #endif
420Sstevel@tonic-gate #ifdef _KERNEL
430Sstevel@tonic-gate #include <sys/debug.h>
440Sstevel@tonic-gate #endif	/* _KERNEL */
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate  * kmdb has its own *printf routines, and thus doesn't need these versions too.
480Sstevel@tonic-gate  */
490Sstevel@tonic-gate #if !defined(_KMDB)
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #define	ADDCHAR(c)	if (bufp++ - buf < buflen) bufp[-1] = (c)
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate  * Given a buffer 'buf' of size 'buflen', render as much of the string
550Sstevel@tonic-gate  * described by <fmt, args> as possible.  The string will always be
560Sstevel@tonic-gate  * null-terminated, so the maximum string length is 'buflen - 1'.
570Sstevel@tonic-gate  * Returns the number of bytes that would be necessary to render the
580Sstevel@tonic-gate  * entire string, not including null terminator (just like vsnprintf(3S)).
590Sstevel@tonic-gate  * To determine buffer size in advance, use vsnprintf(NULL, 0, fmt, args) + 1.
600Sstevel@tonic-gate  *
610Sstevel@tonic-gate  * There is no support for floating point, and the C locale is assumed.
620Sstevel@tonic-gate  */
630Sstevel@tonic-gate size_t
640Sstevel@tonic-gate vsnprintf(char *buf, size_t buflen, const char *fmt, va_list aargs)
650Sstevel@tonic-gate {
660Sstevel@tonic-gate 	uint64_t ul, tmp;
670Sstevel@tonic-gate 	char *bufp = buf;	/* current buffer pointer */
68*941Smyers 	int pad, width, base, sign, c, num;
69*941Smyers 	int prec, h_count, l_count, dot_count;
70*941Smyers 	int pad_count, transfer_count, left_align;
710Sstevel@tonic-gate 	char *digits, *sp, *bs;
720Sstevel@tonic-gate 	char numbuf[65];	/* sufficient for a 64-bit binary value */
730Sstevel@tonic-gate 	va_list args;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	/*
760Sstevel@tonic-gate 	 * Make a copy so that all our callers don't have to make a copy
770Sstevel@tonic-gate 	 */
780Sstevel@tonic-gate 	va_copy(args, aargs);
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	if ((ssize_t)buflen < 0)
810Sstevel@tonic-gate 		buflen = 0;
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	while ((c = *fmt++) != '\0') {
840Sstevel@tonic-gate 		if (c != '%') {
850Sstevel@tonic-gate 			ADDCHAR(c);
860Sstevel@tonic-gate 			continue;
870Sstevel@tonic-gate 		}
880Sstevel@tonic-gate 
89*941Smyers 		width = prec = 0;
90*941Smyers 		left_align = base = sign = 0;
91*941Smyers 		h_count = l_count = dot_count = 0;
92*941Smyers 		pad = ' ';
93*941Smyers 		digits = "0123456789abcdef";
94*941Smyers next_fmt:
950Sstevel@tonic-gate 		if ((c = *fmt++) == '\0')
960Sstevel@tonic-gate 			break;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 		if (c >= 'A' && c <= 'Z') {
990Sstevel@tonic-gate 			c += 'a' - 'A';
1000Sstevel@tonic-gate 			digits = "0123456789ABCDEF";
1010Sstevel@tonic-gate 		}
1020Sstevel@tonic-gate 
103*941Smyers 		switch (c) {
104*941Smyers 		case '-':
105*941Smyers 			left_align++;
106*941Smyers 			goto next_fmt;
107*941Smyers 		case '0':
108*941Smyers 			if (dot_count == 0)
109*941Smyers 				pad = '0';
110*941Smyers 			/*FALLTHROUGH*/
111*941Smyers 		case '1':
112*941Smyers 		case '2':
113*941Smyers 		case '3':
114*941Smyers 		case '4':
115*941Smyers 		case '5':
116*941Smyers 		case '6':
117*941Smyers 		case '7':
118*941Smyers 		case '8':
119*941Smyers 		case '9':
120*941Smyers 			num = 0;
121*941Smyers 			for (;;) {
122*941Smyers 				num = 10 * num + c - '0';
123*941Smyers 				c = *fmt;
124*941Smyers 				if (c < '0' || c > '9')
125*941Smyers 					break;
126*941Smyers 				else
127*941Smyers 					fmt++;
128*941Smyers 			}
129*941Smyers 			if (dot_count > 0)
130*941Smyers 				prec = num;
131*941Smyers 			else
132*941Smyers 				width = num;
1330Sstevel@tonic-gate 
134*941Smyers 			goto next_fmt;
135*941Smyers 		case '.':
136*941Smyers 			dot_count++;
137*941Smyers 			goto next_fmt;
138*941Smyers 		case '*':
139*941Smyers 			width = (int)va_arg(args, int);
140*941Smyers 			goto next_fmt;
141*941Smyers 		case 'l':
142*941Smyers 			l_count++;
143*941Smyers 			goto next_fmt;
144*941Smyers 		case 'h':
145*941Smyers 			h_count++;
146*941Smyers 			goto next_fmt;
1470Sstevel@tonic-gate 		case 'd':
1480Sstevel@tonic-gate 			sign = 1;
1490Sstevel@tonic-gate 			/*FALLTHROUGH*/
1500Sstevel@tonic-gate 		case 'u':
1510Sstevel@tonic-gate 			base = 10;
1520Sstevel@tonic-gate 			break;
1530Sstevel@tonic-gate 		case 'p':
154*941Smyers 			l_count = 1;
1550Sstevel@tonic-gate 			/*FALLTHROUGH*/
1560Sstevel@tonic-gate 		case 'x':
1570Sstevel@tonic-gate 			base = 16;
1580Sstevel@tonic-gate 			break;
1590Sstevel@tonic-gate 		case 'o':
1600Sstevel@tonic-gate 			base = 8;
1610Sstevel@tonic-gate 			break;
1620Sstevel@tonic-gate 		case 'b':
163*941Smyers 			l_count = 0;
1640Sstevel@tonic-gate 			base = 1;
1650Sstevel@tonic-gate 			break;
1660Sstevel@tonic-gate 		case 'c':
167*941Smyers 			c = (char)va_arg(args, char);
168*941Smyers 			ADDCHAR(c);
1690Sstevel@tonic-gate 			break;
1700Sstevel@tonic-gate 		case 's':
1710Sstevel@tonic-gate 			sp = va_arg(args, char *);
172*941Smyers 			if (sp == NULL) {
1730Sstevel@tonic-gate 				sp = "<null string>";
174*941Smyers 				/* avoid truncation */
175*941Smyers 				prec = strlen(sp);
176*941Smyers 			}
177*941Smyers 			/*
178*941Smyers 			 * Handle simple case specially to avoid
179*941Smyers 			 * performance hit of strlen()
180*941Smyers 			 */
181*941Smyers 			if (prec == 0 && width == 0) {
182*941Smyers 				while ((c = *sp++) != 0)
183*941Smyers 					ADDCHAR(c);
184*941Smyers 				break;
185*941Smyers 			}
186*941Smyers 			transfer_count = strlen(sp);
187*941Smyers 			if (prec > 0) {
188*941Smyers 				/* trim string if too long */
189*941Smyers 				if (transfer_count > prec)
190*941Smyers 					transfer_count = prec;
191*941Smyers 				/* widen field if too narrow */
192*941Smyers 				if (prec > width)
193*941Smyers 					width = prec;
194*941Smyers 			}
195*941Smyers 			if (width > transfer_count)
196*941Smyers 				pad_count = width - transfer_count;
197*941Smyers 			else
198*941Smyers 				pad_count = 0;
199*941Smyers 			while ((!left_align) && (pad_count-- > 0))
200*941Smyers 				ADDCHAR(' ');
201*941Smyers 			/* ADDCHAR() evaluates arg at most once */
202*941Smyers 			while (transfer_count-- > 0)
203*941Smyers 				ADDCHAR(*sp++);
204*941Smyers 			while ((left_align) && (pad_count-- > 0))
205*941Smyers 				ADDCHAR(' ');
2060Sstevel@tonic-gate 			break;
2070Sstevel@tonic-gate 		case '%':
2080Sstevel@tonic-gate 			ADDCHAR('%');
2090Sstevel@tonic-gate 			break;
2100Sstevel@tonic-gate 		}
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 		if (base == 0)
2130Sstevel@tonic-gate 			continue;
2140Sstevel@tonic-gate 
215*941Smyers 		if (h_count == 0 && l_count == 0)
216*941Smyers 			if (sign)
217*941Smyers 				ul = (int64_t)va_arg(args, int);
218*941Smyers 			else
219*941Smyers 				ul = (int64_t)va_arg(args, unsigned int);
220*941Smyers 		else if (l_count > 1)
221*941Smyers 			if (sign)
222*941Smyers 				ul = (int64_t)va_arg(args, int64_t);
223*941Smyers 			else
224*941Smyers 				ul = (int64_t)va_arg(args, uint64_t);
225*941Smyers 		else if (l_count > 0)
226*941Smyers 			if (sign)
227*941Smyers 				ul = (int64_t)va_arg(args, long);
228*941Smyers 			else
229*941Smyers 				ul = (int64_t)va_arg(args, unsigned long);
230*941Smyers 		else if (h_count > 1)
231*941Smyers 			if (sign)
232*941Smyers 				ul = (int64_t)va_arg(args, char);
233*941Smyers 			else
234*941Smyers 				ul = (int64_t)va_arg(args, unsigned char);
235*941Smyers 		else if (h_count > 0)
236*941Smyers 			if (sign)
237*941Smyers 				ul = (int64_t)va_arg(args, short);
238*941Smyers 			else
239*941Smyers 				ul = (int64_t)va_arg(args, unsigned short);
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 		if (sign && (int64_t)ul < 0)
2420Sstevel@tonic-gate 			ul = -ul;
2430Sstevel@tonic-gate 		else
2440Sstevel@tonic-gate 			sign = 0;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 		if (c == 'b') {
2470Sstevel@tonic-gate 			bs = va_arg(args, char *);
2480Sstevel@tonic-gate 			base = *bs++;
2490Sstevel@tonic-gate 		}
2500Sstevel@tonic-gate 
251*941Smyers 		/* avoid repeated division if width is 0 */
252*941Smyers 		if (width > 0) {
253*941Smyers 			tmp = ul;
254*941Smyers 			do {
255*941Smyers 				width--;
256*941Smyers 			} while ((tmp /= base) != 0);
257*941Smyers 		}
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 		if (sign && pad == '0')
2600Sstevel@tonic-gate 			ADDCHAR('-');
2610Sstevel@tonic-gate 		while (width-- > sign)
2620Sstevel@tonic-gate 			ADDCHAR(pad);
2630Sstevel@tonic-gate 		if (sign && pad == ' ')
2640Sstevel@tonic-gate 			ADDCHAR('-');
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 		sp = numbuf;
2670Sstevel@tonic-gate 		tmp = ul;
2680Sstevel@tonic-gate 		do {
2690Sstevel@tonic-gate 			*sp++ = digits[tmp % base];
2700Sstevel@tonic-gate 		} while ((tmp /= base) != 0);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 		while (sp > numbuf) {
2730Sstevel@tonic-gate 			sp--;
2740Sstevel@tonic-gate 			ADDCHAR(*sp);
2750Sstevel@tonic-gate 		}
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 		if (c == 'b' && ul != 0) {
2780Sstevel@tonic-gate 			int any = 0;
2790Sstevel@tonic-gate 			c = *bs++;
2800Sstevel@tonic-gate 			while (c != 0) {
2810Sstevel@tonic-gate 				if (ul & (1 << (c - 1))) {
2820Sstevel@tonic-gate 					if (any++ == 0)
2830Sstevel@tonic-gate 						ADDCHAR('<');
2840Sstevel@tonic-gate 					while ((c = *bs++) >= 32)
2850Sstevel@tonic-gate 						ADDCHAR(c);
2860Sstevel@tonic-gate 					ADDCHAR(',');
2870Sstevel@tonic-gate 				} else {
2880Sstevel@tonic-gate 					while ((c = *bs++) >= 32)
2890Sstevel@tonic-gate 						continue;
2900Sstevel@tonic-gate 				}
2910Sstevel@tonic-gate 			}
2920Sstevel@tonic-gate 			if (any) {
2930Sstevel@tonic-gate 				bufp--;
2940Sstevel@tonic-gate 				ADDCHAR('>');
2950Sstevel@tonic-gate 			}
2960Sstevel@tonic-gate 		}
2970Sstevel@tonic-gate 	}
2980Sstevel@tonic-gate 	if (bufp - buf < buflen)
2990Sstevel@tonic-gate 		bufp[0] = c;
3000Sstevel@tonic-gate 	else if (buflen != 0)
3010Sstevel@tonic-gate 		buf[buflen - 1] = c;
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	va_end(args);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	return (bufp - buf);
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate /*PRINTFLIKE1*/
3090Sstevel@tonic-gate size_t
3100Sstevel@tonic-gate snprintf(char *buf, size_t buflen, const char *fmt, ...)
3110Sstevel@tonic-gate {
3120Sstevel@tonic-gate 	va_list args;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	va_start(args, fmt);
3150Sstevel@tonic-gate 	buflen = vsnprintf(buf, buflen, fmt, args);
3160Sstevel@tonic-gate 	va_end(args);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	return (buflen);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate #if defined(_BOOT)
3220Sstevel@tonic-gate /*
3230Sstevel@tonic-gate  * The sprintf() and vsprintf() routines aren't shared with the kernel because
3240Sstevel@tonic-gate  * the DDI mandates that they return the buffer rather than its length.
3250Sstevel@tonic-gate  */
3260Sstevel@tonic-gate /*PRINTFLIKE2*/
3270Sstevel@tonic-gate int
3280Sstevel@tonic-gate sprintf(char *buf, const char *fmt, ...)
3290Sstevel@tonic-gate {
3300Sstevel@tonic-gate 	va_list args;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	va_start(args, fmt);
3330Sstevel@tonic-gate 	(void) vsnprintf(buf, INT_MAX, fmt, args);
3340Sstevel@tonic-gate 	va_end(args);
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	return (strlen(buf));
3370Sstevel@tonic-gate }
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate int
3400Sstevel@tonic-gate vsprintf(char *buf, const char *fmt, va_list args)
3410Sstevel@tonic-gate {
3420Sstevel@tonic-gate 	(void) vsnprintf(buf, INT_MAX, fmt, args);
3430Sstevel@tonic-gate 	return (strlen(buf));
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate #endif
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate #endif /* !_KMDB */
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate char *
3500Sstevel@tonic-gate strcat(char *s1, const char *s2)
3510Sstevel@tonic-gate {
3520Sstevel@tonic-gate 	char *os1 = s1;
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	while (*s1++ != '\0')
3550Sstevel@tonic-gate 		;
3560Sstevel@tonic-gate 	s1--;
3570Sstevel@tonic-gate 	while ((*s1++ = *s2++) != '\0')
3580Sstevel@tonic-gate 		;
3590Sstevel@tonic-gate 	return (os1);
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate char *
3630Sstevel@tonic-gate strchr(const char *sp, int c)
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate 	do {
3660Sstevel@tonic-gate 		if (*sp == (char)c)
3670Sstevel@tonic-gate 			return ((char *)sp);
3680Sstevel@tonic-gate 	} while (*sp++);
3690Sstevel@tonic-gate 	return (NULL);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate int
3730Sstevel@tonic-gate strcmp(const char *s1, const char *s2)
3740Sstevel@tonic-gate {
3750Sstevel@tonic-gate 	while (*s1 == *s2++)
3760Sstevel@tonic-gate 		if (*s1++ == '\0')
3770Sstevel@tonic-gate 			return (0);
3780Sstevel@tonic-gate 	return (*(unsigned char *)s1 - *(unsigned char *)--s2);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate int
3820Sstevel@tonic-gate strncmp(const char *s1, const char *s2, size_t n)
3830Sstevel@tonic-gate {
3840Sstevel@tonic-gate 	if (s1 == s2)
3850Sstevel@tonic-gate 		return (0);
3860Sstevel@tonic-gate 	n++;
3870Sstevel@tonic-gate 	while (--n != 0 && *s1 == *s2++)
3880Sstevel@tonic-gate 		if (*s1++ == '\0')
3890Sstevel@tonic-gate 			return (0);
3900Sstevel@tonic-gate 	return ((n == 0) ? 0 : *(unsigned char *)s1 - *(unsigned char *)--s2);
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate static const char charmap[] = {
3940Sstevel@tonic-gate 	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
3950Sstevel@tonic-gate 	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
3960Sstevel@tonic-gate 	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
3970Sstevel@tonic-gate 	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
3980Sstevel@tonic-gate 	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
3990Sstevel@tonic-gate 	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
4000Sstevel@tonic-gate 	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
4010Sstevel@tonic-gate 	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
4020Sstevel@tonic-gate 	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
4030Sstevel@tonic-gate 	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
4040Sstevel@tonic-gate 	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
4050Sstevel@tonic-gate 	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
4060Sstevel@tonic-gate 	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
4070Sstevel@tonic-gate 	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
4080Sstevel@tonic-gate 	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
4090Sstevel@tonic-gate 	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
4100Sstevel@tonic-gate 	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
4110Sstevel@tonic-gate 	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
4120Sstevel@tonic-gate 	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
4130Sstevel@tonic-gate 	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
4140Sstevel@tonic-gate 	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
4150Sstevel@tonic-gate 	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
4160Sstevel@tonic-gate 	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
4170Sstevel@tonic-gate 	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
4180Sstevel@tonic-gate 	'\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
4190Sstevel@tonic-gate 	'\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
4200Sstevel@tonic-gate 	'\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
4210Sstevel@tonic-gate 	'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
4220Sstevel@tonic-gate 	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
4230Sstevel@tonic-gate 	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
4240Sstevel@tonic-gate 	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
4250Sstevel@tonic-gate 	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
4260Sstevel@tonic-gate };
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate int
4290Sstevel@tonic-gate strcasecmp(const char *s1, const char *s2)
4300Sstevel@tonic-gate {
4310Sstevel@tonic-gate 	const unsigned char *cm = (const unsigned char *)charmap;
4320Sstevel@tonic-gate 	const unsigned char *us1 = (const unsigned char *)s1;
4330Sstevel@tonic-gate 	const unsigned char *us2 = (const unsigned char *)s2;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	while (cm[*us1] == cm[*us2++])
4360Sstevel@tonic-gate 		if (*us1++ == '\0')
4370Sstevel@tonic-gate 			return (0);
4380Sstevel@tonic-gate 	return (cm[*us1] - cm[*(us2 - 1)]);
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate int
4420Sstevel@tonic-gate strncasecmp(const char *s1, const char *s2, size_t n)
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate 	const unsigned char *cm = (const unsigned char *)charmap;
4450Sstevel@tonic-gate 	const unsigned char *us1 = (const unsigned char *)s1;
4460Sstevel@tonic-gate 	const unsigned char *us2 = (const unsigned char *)s2;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	while (n != 0 && cm[*us1] == cm[*us2++]) {
4490Sstevel@tonic-gate 		if (*us1++ == '\0')
4500Sstevel@tonic-gate 			return (0);
4510Sstevel@tonic-gate 		n--;
4520Sstevel@tonic-gate 	}
4530Sstevel@tonic-gate 	return (n == 0 ? 0 : cm[*us1] - cm[*(us2 - 1)]);
4540Sstevel@tonic-gate }
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate char *
4570Sstevel@tonic-gate strcpy(char *s1, const char *s2)
4580Sstevel@tonic-gate {
4590Sstevel@tonic-gate 	char *os1 = s1;
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	while ((*s1++ = *s2++) != '\0')
4620Sstevel@tonic-gate 		;
4630Sstevel@tonic-gate 	return (os1);
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate char *
4670Sstevel@tonic-gate strncpy(char *s1, const char *s2, size_t n)
4680Sstevel@tonic-gate {
4690Sstevel@tonic-gate 	char *os1 = s1;
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	n++;
4720Sstevel@tonic-gate 	while (--n != 0 && (*s1++ = *s2++) != '\0')
4730Sstevel@tonic-gate 		;
4740Sstevel@tonic-gate 	if (n != 0)
4750Sstevel@tonic-gate 		while (--n != 0)
4760Sstevel@tonic-gate 			*s1++ = '\0';
4770Sstevel@tonic-gate 	return (os1);
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate char *
4810Sstevel@tonic-gate strrchr(const char *sp, int c)
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate 	char *r = NULL;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	do {
4860Sstevel@tonic-gate 		if (*sp == (char)c)
4870Sstevel@tonic-gate 			r = (char *)sp;
4880Sstevel@tonic-gate 	} while (*sp++);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	return (r);
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate char *
4940Sstevel@tonic-gate strstr(const char *as1, const char *as2)
4950Sstevel@tonic-gate {
4960Sstevel@tonic-gate 	const char *s1, *s2;
4970Sstevel@tonic-gate 	const char *tptr;
4980Sstevel@tonic-gate 	char c;
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	s1 = as1;
5010Sstevel@tonic-gate 	s2 = as2;
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	if (s2 == NULL || *s2 == '\0')
5040Sstevel@tonic-gate 		return ((char *)s1);
5050Sstevel@tonic-gate 	c = *s2;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	while (*s1)
5080Sstevel@tonic-gate 		if (*s1++ == c) {
5090Sstevel@tonic-gate 			tptr = s1;
5100Sstevel@tonic-gate 			while ((c = *++s2) == *s1++ && c)
5110Sstevel@tonic-gate 				;
5120Sstevel@tonic-gate 			if (c == 0)
5130Sstevel@tonic-gate 				return ((char *)tptr - 1);
5140Sstevel@tonic-gate 			s1 = tptr;
5150Sstevel@tonic-gate 			s2 = as2;
5160Sstevel@tonic-gate 			c = *s2;
5170Sstevel@tonic-gate 		}
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	return (NULL);
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate char *
5230Sstevel@tonic-gate strpbrk(const char *string, const char *brkset)
5240Sstevel@tonic-gate {
5250Sstevel@tonic-gate 	const char *p;
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	do {
5280Sstevel@tonic-gate 		for (p = brkset; *p != '\0' && *p != *string; ++p)
5290Sstevel@tonic-gate 			;
5300Sstevel@tonic-gate 		if (*p != '\0')
5310Sstevel@tonic-gate 			return ((char *)string);
5320Sstevel@tonic-gate 	} while (*string++);
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	return (NULL);
5350Sstevel@tonic-gate }
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate char *
5380Sstevel@tonic-gate strncat(char *s1, const char *s2, size_t n)
5390Sstevel@tonic-gate {
5400Sstevel@tonic-gate 	char *os1 = s1;
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	n++;
5430Sstevel@tonic-gate 	while (*s1++ != '\0')
5440Sstevel@tonic-gate 		;
5450Sstevel@tonic-gate 	--s1;
5460Sstevel@tonic-gate 	while ((*s1++ = *s2++) != '\0') {
5470Sstevel@tonic-gate 		if (--n == 0) {
5480Sstevel@tonic-gate 			s1[-1] = '\0';
5490Sstevel@tonic-gate 			break;
5500Sstevel@tonic-gate 		}
5510Sstevel@tonic-gate 	}
5520Sstevel@tonic-gate 	return (os1);
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate #if defined(_BOOT) || defined(_KMDB)
5560Sstevel@tonic-gate #define	bcopy(src, dst, n)	(void) memcpy((dst), (src), (n))
5570Sstevel@tonic-gate #endif
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate size_t
5600Sstevel@tonic-gate strlcat(char *dst, const char *src, size_t dstsize)
5610Sstevel@tonic-gate {
5620Sstevel@tonic-gate 	char *df = dst;
5630Sstevel@tonic-gate 	size_t left = dstsize;
5640Sstevel@tonic-gate 	size_t l1;
5650Sstevel@tonic-gate 	size_t l2 = strlen(src);
5660Sstevel@tonic-gate 	size_t copied;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	while (left-- != 0 && *df != '\0')
5690Sstevel@tonic-gate 		df++;
5700Sstevel@tonic-gate 	l1 = df - dst;
5710Sstevel@tonic-gate 	if (dstsize == l1)
5720Sstevel@tonic-gate 		return (l1 + l2);
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	copied = l1 + l2 >= dstsize ? dstsize - l1 - 1 : l2;
5750Sstevel@tonic-gate 	bcopy(src, dst + l1, copied);
5760Sstevel@tonic-gate 	dst[l1+copied] = '\0';
5770Sstevel@tonic-gate 	return (l1 + l2);
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate size_t
5810Sstevel@tonic-gate strlcpy(char *dst, const char *src, size_t len)
5820Sstevel@tonic-gate {
5830Sstevel@tonic-gate 	size_t slen = strlen(src);
5840Sstevel@tonic-gate 	size_t copied;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	if (len == 0)
5870Sstevel@tonic-gate 		return (slen);
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	if (slen >= len)
5900Sstevel@tonic-gate 		copied = len - 1;
5910Sstevel@tonic-gate 	else
5920Sstevel@tonic-gate 		copied = slen;
5930Sstevel@tonic-gate 	bcopy(src, dst, copied);
5940Sstevel@tonic-gate 	dst[copied] = '\0';
5950Sstevel@tonic-gate 	return (slen);
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate size_t
5990Sstevel@tonic-gate strspn(const char *string, const char *charset)
6000Sstevel@tonic-gate {
6010Sstevel@tonic-gate 	const char *p, *q;
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	for (q = string; *q != '\0'; ++q) {
6040Sstevel@tonic-gate 		for (p = charset; *p != '\0' && *p != *q; ++p)
6050Sstevel@tonic-gate 			;
6060Sstevel@tonic-gate 		if (*p == '\0')
6070Sstevel@tonic-gate 			break;
6080Sstevel@tonic-gate 	}
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	return (q - string);
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate /*
6140Sstevel@tonic-gate  * Unless mentioned otherwise, all of the routines below should be added to
6150Sstevel@tonic-gate  * the Solaris DDI as necessary.  For now, only provide them to standalone.
6160Sstevel@tonic-gate  */
6170Sstevel@tonic-gate #if defined(_BOOT) || defined(_KMDB)
6180Sstevel@tonic-gate char *
6190Sstevel@tonic-gate strtok(char *string, const char *sepset)
6200Sstevel@tonic-gate {
6210Sstevel@tonic-gate 	char		*p, *q, *r;
6220Sstevel@tonic-gate 	static char	*savept;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	/*
6250Sstevel@tonic-gate 	 * Set `p' to our current location in the string.
6260Sstevel@tonic-gate 	 */
6270Sstevel@tonic-gate 	p = (string == NULL) ? savept : string;
6280Sstevel@tonic-gate 	if (p == NULL)
6290Sstevel@tonic-gate 		return (NULL);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	/*
6320Sstevel@tonic-gate 	 * Skip leading separators; bail if no tokens remain.
6330Sstevel@tonic-gate 	 */
6340Sstevel@tonic-gate 	q = p + strspn(p, sepset);
6350Sstevel@tonic-gate 	if (*q == '\0')
6360Sstevel@tonic-gate 		return (NULL);
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	/*
6390Sstevel@tonic-gate 	 * Mark the end of the token and set `savept' for the next iteration.
6400Sstevel@tonic-gate 	 */
6410Sstevel@tonic-gate 	if ((r = strpbrk(q, sepset)) == NULL)
6420Sstevel@tonic-gate 		savept = NULL;
6430Sstevel@tonic-gate 	else {
6440Sstevel@tonic-gate 		*r = '\0';
6450Sstevel@tonic-gate 		savept = ++r;
6460Sstevel@tonic-gate 	}
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	return (q);
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate /*
6520Sstevel@tonic-gate  * The strlen() routine isn't shared with the kernel because it has its own
6530Sstevel@tonic-gate  * hand-tuned assembly version.
6540Sstevel@tonic-gate  */
6550Sstevel@tonic-gate size_t
6560Sstevel@tonic-gate strlen(const char *s)
6570Sstevel@tonic-gate {
6580Sstevel@tonic-gate 	size_t n = 0;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	while (*s++)
6610Sstevel@tonic-gate 		n++;
6620Sstevel@tonic-gate 	return (n);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate #endif /* _BOOT || _KMDB */
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate #ifdef _KERNEL
6680Sstevel@tonic-gate /*
6690Sstevel@tonic-gate  * Check for a valid C identifier:
6700Sstevel@tonic-gate  *	a letter or underscore, followed by
6710Sstevel@tonic-gate  *	zero or more letters, digits and underscores.
6720Sstevel@tonic-gate  */
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate #define	IS_DIGIT(c)	((c) >= '0' && (c) <= '9')
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate #define	IS_ALPHA(c)	\
6770Sstevel@tonic-gate 	(((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate int
6800Sstevel@tonic-gate strident_valid(const char *id)
6810Sstevel@tonic-gate {
6820Sstevel@tonic-gate 	int c = *id++;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	if (!IS_ALPHA(c) && c != '_')
6850Sstevel@tonic-gate 		return (0);
6860Sstevel@tonic-gate 	while ((c = *id++) != 0) {
6870Sstevel@tonic-gate 		if (!IS_ALPHA(c) && !IS_DIGIT(c) && c != '_')
6880Sstevel@tonic-gate 			return (0);
6890Sstevel@tonic-gate 	}
6900Sstevel@tonic-gate 	return (1);
6910Sstevel@tonic-gate }
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate /*
6940Sstevel@tonic-gate  * Convert a string into a valid C identifier by replacing invalid
6950Sstevel@tonic-gate  * characters with '_'.  Also makes sure the string is nul-terminated
6960Sstevel@tonic-gate  * and takes up at most n bytes.
6970Sstevel@tonic-gate  */
6980Sstevel@tonic-gate void
6990Sstevel@tonic-gate strident_canon(char *s, size_t n)
7000Sstevel@tonic-gate {
7010Sstevel@tonic-gate 	char c;
7020Sstevel@tonic-gate 	char *end = s + n - 1;
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	ASSERT(n > 0);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	if ((c = *s) == 0)
7070Sstevel@tonic-gate 		return;
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	if (!IS_ALPHA(c) && c != '_')
7100Sstevel@tonic-gate 		*s = '_';
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	while (s < end && ((c = *(++s)) != 0)) {
7130Sstevel@tonic-gate 		if (!IS_ALPHA(c) && !IS_DIGIT(c) && c != '_')
7140Sstevel@tonic-gate 			*s = '_';
7150Sstevel@tonic-gate 	}
7160Sstevel@tonic-gate 	*s = 0;
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate #endif	/* _KERNEL */
720