xref: /onnv-gate/usr/src/common/util/string.c (revision 7478:f2ea9cb5143d)
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
52085Sdr146992  * Common Development and Distribution License (the "License").
62085Sdr146992  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
225930Smyers  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Implementations of the functions described in vsnprintf(3C) and string(3C),
280Sstevel@tonic-gate  * for use by the kernel, the standalone, and kmdb.  Unless otherwise specified,
290Sstevel@tonic-gate  * these functions match the section 3C manpages.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/varargs.h>
343446Smrj 
353446Smrj #if defined(_KERNEL)
360Sstevel@tonic-gate #include <sys/systm.h>
373446Smrj #include <sys/debug.h>
383446Smrj #elif !defined(_BOOT)
393446Smrj #include <string.h>
400Sstevel@tonic-gate #endif
413446Smrj 
423446Smrj #ifndef	NULL
433446Smrj #define	NULL	0l
443446Smrj #endif
453446Smrj 
463446Smrj #include "memcpy.h"
473446Smrj #include "string.h"
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
503446Smrj  * We don't need these for x86 boot or kmdb.
510Sstevel@tonic-gate  */
523446Smrj #if !defined(_KMDB) && (!defined(_BOOT) || defined(__sparc))
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #define	ADDCHAR(c)	if (bufp++ - buf < buflen) bufp[-1] = (c)
550Sstevel@tonic-gate 
560Sstevel@tonic-gate /*
570Sstevel@tonic-gate  * Given a buffer 'buf' of size 'buflen', render as much of the string
580Sstevel@tonic-gate  * described by <fmt, args> as possible.  The string will always be
590Sstevel@tonic-gate  * null-terminated, so the maximum string length is 'buflen - 1'.
600Sstevel@tonic-gate  * Returns the number of bytes that would be necessary to render the
610Sstevel@tonic-gate  * entire string, not including null terminator (just like vsnprintf(3S)).
620Sstevel@tonic-gate  * To determine buffer size in advance, use vsnprintf(NULL, 0, fmt, args) + 1.
630Sstevel@tonic-gate  *
640Sstevel@tonic-gate  * There is no support for floating point, and the C locale is assumed.
650Sstevel@tonic-gate  */
660Sstevel@tonic-gate size_t
vsnprintf(char * buf,size_t buflen,const char * fmt,va_list aargs)670Sstevel@tonic-gate vsnprintf(char *buf, size_t buflen, const char *fmt, va_list aargs)
680Sstevel@tonic-gate {
690Sstevel@tonic-gate 	uint64_t ul, tmp;
700Sstevel@tonic-gate 	char *bufp = buf;	/* current buffer pointer */
71941Smyers 	int pad, width, base, sign, c, num;
72941Smyers 	int prec, h_count, l_count, dot_count;
73941Smyers 	int pad_count, transfer_count, left_align;
740Sstevel@tonic-gate 	char *digits, *sp, *bs;
750Sstevel@tonic-gate 	char numbuf[65];	/* sufficient for a 64-bit binary value */
760Sstevel@tonic-gate 	va_list args;
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	/*
790Sstevel@tonic-gate 	 * Make a copy so that all our callers don't have to make a copy
800Sstevel@tonic-gate 	 */
810Sstevel@tonic-gate 	va_copy(args, aargs);
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	if ((ssize_t)buflen < 0)
840Sstevel@tonic-gate 		buflen = 0;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	while ((c = *fmt++) != '\0') {
870Sstevel@tonic-gate 		if (c != '%') {
880Sstevel@tonic-gate 			ADDCHAR(c);
890Sstevel@tonic-gate 			continue;
900Sstevel@tonic-gate 		}
910Sstevel@tonic-gate 
92941Smyers 		width = prec = 0;
93941Smyers 		left_align = base = sign = 0;
94941Smyers 		h_count = l_count = dot_count = 0;
95941Smyers 		pad = ' ';
96941Smyers 		digits = "0123456789abcdef";
97941Smyers next_fmt:
980Sstevel@tonic-gate 		if ((c = *fmt++) == '\0')
990Sstevel@tonic-gate 			break;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 		if (c >= 'A' && c <= 'Z') {
1020Sstevel@tonic-gate 			c += 'a' - 'A';
1030Sstevel@tonic-gate 			digits = "0123456789ABCDEF";
1040Sstevel@tonic-gate 		}
1050Sstevel@tonic-gate 
106941Smyers 		switch (c) {
107941Smyers 		case '-':
108941Smyers 			left_align++;
109941Smyers 			goto next_fmt;
110941Smyers 		case '0':
111941Smyers 			if (dot_count == 0)
112941Smyers 				pad = '0';
113941Smyers 			/*FALLTHROUGH*/
114941Smyers 		case '1':
115941Smyers 		case '2':
116941Smyers 		case '3':
117941Smyers 		case '4':
118941Smyers 		case '5':
119941Smyers 		case '6':
120941Smyers 		case '7':
121941Smyers 		case '8':
122941Smyers 		case '9':
123941Smyers 			num = 0;
124941Smyers 			for (;;) {
125941Smyers 				num = 10 * num + c - '0';
126941Smyers 				c = *fmt;
127941Smyers 				if (c < '0' || c > '9')
128941Smyers 					break;
129941Smyers 				else
130941Smyers 					fmt++;
131941Smyers 			}
132941Smyers 			if (dot_count > 0)
133941Smyers 				prec = num;
134941Smyers 			else
135941Smyers 				width = num;
1360Sstevel@tonic-gate 
137941Smyers 			goto next_fmt;
138941Smyers 		case '.':
139941Smyers 			dot_count++;
140941Smyers 			goto next_fmt;
141941Smyers 		case '*':
1422085Sdr146992 			if (dot_count > 0)
1432085Sdr146992 				prec = (int)va_arg(args, int);
1442085Sdr146992 			else
1452085Sdr146992 				width = (int)va_arg(args, int);
146941Smyers 			goto next_fmt;
147941Smyers 		case 'l':
148941Smyers 			l_count++;
149941Smyers 			goto next_fmt;
150941Smyers 		case 'h':
151941Smyers 			h_count++;
152941Smyers 			goto next_fmt;
1530Sstevel@tonic-gate 		case 'd':
1540Sstevel@tonic-gate 			sign = 1;
1550Sstevel@tonic-gate 			/*FALLTHROUGH*/
1560Sstevel@tonic-gate 		case 'u':
1570Sstevel@tonic-gate 			base = 10;
1580Sstevel@tonic-gate 			break;
1590Sstevel@tonic-gate 		case 'p':
160941Smyers 			l_count = 1;
1610Sstevel@tonic-gate 			/*FALLTHROUGH*/
1620Sstevel@tonic-gate 		case 'x':
1630Sstevel@tonic-gate 			base = 16;
1640Sstevel@tonic-gate 			break;
1650Sstevel@tonic-gate 		case 'o':
1660Sstevel@tonic-gate 			base = 8;
1670Sstevel@tonic-gate 			break;
1680Sstevel@tonic-gate 		case 'b':
169941Smyers 			l_count = 0;
1700Sstevel@tonic-gate 			base = 1;
1710Sstevel@tonic-gate 			break;
1720Sstevel@tonic-gate 		case 'c':
173947Smyers 			c = (char)va_arg(args, int);
174941Smyers 			ADDCHAR(c);
1750Sstevel@tonic-gate 			break;
1760Sstevel@tonic-gate 		case 's':
1770Sstevel@tonic-gate 			sp = va_arg(args, char *);
178941Smyers 			if (sp == NULL) {
1790Sstevel@tonic-gate 				sp = "<null string>";
180941Smyers 				/* avoid truncation */
181941Smyers 				prec = strlen(sp);
182941Smyers 			}
183941Smyers 			/*
184941Smyers 			 * Handle simple case specially to avoid
185941Smyers 			 * performance hit of strlen()
186941Smyers 			 */
187941Smyers 			if (prec == 0 && width == 0) {
188941Smyers 				while ((c = *sp++) != 0)
189941Smyers 					ADDCHAR(c);
190941Smyers 				break;
191941Smyers 			}
192941Smyers 			if (prec > 0) {
1935930Smyers 				transfer_count = strnlen(sp, prec);
194941Smyers 				/* widen field if too narrow */
195941Smyers 				if (prec > width)
196941Smyers 					width = prec;
1975930Smyers 			} else
1985930Smyers 				transfer_count = strlen(sp);
199941Smyers 			if (width > transfer_count)
200941Smyers 				pad_count = width - transfer_count;
201941Smyers 			else
202941Smyers 				pad_count = 0;
203941Smyers 			while ((!left_align) && (pad_count-- > 0))
204941Smyers 				ADDCHAR(' ');
205941Smyers 			/* ADDCHAR() evaluates arg at most once */
206941Smyers 			while (transfer_count-- > 0)
207941Smyers 				ADDCHAR(*sp++);
208941Smyers 			while ((left_align) && (pad_count-- > 0))
209941Smyers 				ADDCHAR(' ');
2100Sstevel@tonic-gate 			break;
2110Sstevel@tonic-gate 		case '%':
2120Sstevel@tonic-gate 			ADDCHAR('%');
2130Sstevel@tonic-gate 			break;
2140Sstevel@tonic-gate 		}
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 		if (base == 0)
2170Sstevel@tonic-gate 			continue;
2180Sstevel@tonic-gate 
219941Smyers 		if (h_count == 0 && l_count == 0)
220941Smyers 			if (sign)
221941Smyers 				ul = (int64_t)va_arg(args, int);
222941Smyers 			else
223941Smyers 				ul = (int64_t)va_arg(args, unsigned int);
224941Smyers 		else if (l_count > 1)
225941Smyers 			if (sign)
226941Smyers 				ul = (int64_t)va_arg(args, int64_t);
227941Smyers 			else
228941Smyers 				ul = (int64_t)va_arg(args, uint64_t);
229941Smyers 		else if (l_count > 0)
230941Smyers 			if (sign)
231941Smyers 				ul = (int64_t)va_arg(args, long);
232941Smyers 			else
233941Smyers 				ul = (int64_t)va_arg(args, unsigned long);
234941Smyers 		else if (h_count > 1)
235941Smyers 			if (sign)
236947Smyers 				ul = (int64_t)((char)va_arg(args, int));
237941Smyers 			else
238947Smyers 				ul = (int64_t)((unsigned char)va_arg(args,
239947Smyers 				    int));
240941Smyers 		else if (h_count > 0)
241941Smyers 			if (sign)
242947Smyers 				ul = (int64_t)((short)va_arg(args, int));
243941Smyers 			else
244947Smyers 				ul = (int64_t)((unsigned short)va_arg(args,
245947Smyers 				    int));
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 		if (sign && (int64_t)ul < 0)
2480Sstevel@tonic-gate 			ul = -ul;
2490Sstevel@tonic-gate 		else
2500Sstevel@tonic-gate 			sign = 0;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 		if (c == 'b') {
2530Sstevel@tonic-gate 			bs = va_arg(args, char *);
2540Sstevel@tonic-gate 			base = *bs++;
2550Sstevel@tonic-gate 		}
2560Sstevel@tonic-gate 
257941Smyers 		/* avoid repeated division if width is 0 */
258941Smyers 		if (width > 0) {
259941Smyers 			tmp = ul;
260941Smyers 			do {
261941Smyers 				width--;
262941Smyers 			} while ((tmp /= base) != 0);
263941Smyers 		}
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 		if (sign && pad == '0')
2660Sstevel@tonic-gate 			ADDCHAR('-');
2670Sstevel@tonic-gate 		while (width-- > sign)
2680Sstevel@tonic-gate 			ADDCHAR(pad);
2690Sstevel@tonic-gate 		if (sign && pad == ' ')
2700Sstevel@tonic-gate 			ADDCHAR('-');
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 		sp = numbuf;
2730Sstevel@tonic-gate 		tmp = ul;
2740Sstevel@tonic-gate 		do {
2750Sstevel@tonic-gate 			*sp++ = digits[tmp % base];
2760Sstevel@tonic-gate 		} while ((tmp /= base) != 0);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 		while (sp > numbuf) {
2790Sstevel@tonic-gate 			sp--;
2800Sstevel@tonic-gate 			ADDCHAR(*sp);
2810Sstevel@tonic-gate 		}
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 		if (c == 'b' && ul != 0) {
2840Sstevel@tonic-gate 			int any = 0;
2850Sstevel@tonic-gate 			c = *bs++;
2860Sstevel@tonic-gate 			while (c != 0) {
2870Sstevel@tonic-gate 				if (ul & (1 << (c - 1))) {
2880Sstevel@tonic-gate 					if (any++ == 0)
2890Sstevel@tonic-gate 						ADDCHAR('<');
2900Sstevel@tonic-gate 					while ((c = *bs++) >= 32)
2910Sstevel@tonic-gate 						ADDCHAR(c);
2920Sstevel@tonic-gate 					ADDCHAR(',');
2930Sstevel@tonic-gate 				} else {
2940Sstevel@tonic-gate 					while ((c = *bs++) >= 32)
2950Sstevel@tonic-gate 						continue;
2960Sstevel@tonic-gate 				}
2970Sstevel@tonic-gate 			}
2980Sstevel@tonic-gate 			if (any) {
2990Sstevel@tonic-gate 				bufp--;
3000Sstevel@tonic-gate 				ADDCHAR('>');
3010Sstevel@tonic-gate 			}
3020Sstevel@tonic-gate 		}
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 	if (bufp - buf < buflen)
3050Sstevel@tonic-gate 		bufp[0] = c;
3060Sstevel@tonic-gate 	else if (buflen != 0)
3070Sstevel@tonic-gate 		buf[buflen - 1] = c;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	va_end(args);
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	return (bufp - buf);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate /*PRINTFLIKE1*/
3150Sstevel@tonic-gate size_t
snprintf(char * buf,size_t buflen,const char * fmt,...)3160Sstevel@tonic-gate snprintf(char *buf, size_t buflen, const char *fmt, ...)
3170Sstevel@tonic-gate {
3180Sstevel@tonic-gate 	va_list args;
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	va_start(args, fmt);
3210Sstevel@tonic-gate 	buflen = vsnprintf(buf, buflen, fmt, args);
3220Sstevel@tonic-gate 	va_end(args);
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	return (buflen);
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate 
3273446Smrj #if defined(_BOOT) && defined(__sparc)
3280Sstevel@tonic-gate /*
3290Sstevel@tonic-gate  * The sprintf() and vsprintf() routines aren't shared with the kernel because
3300Sstevel@tonic-gate  * the DDI mandates that they return the buffer rather than its length.
3310Sstevel@tonic-gate  */
3320Sstevel@tonic-gate /*PRINTFLIKE2*/
3330Sstevel@tonic-gate int
sprintf(char * buf,const char * fmt,...)3340Sstevel@tonic-gate sprintf(char *buf, const char *fmt, ...)
3350Sstevel@tonic-gate {
3360Sstevel@tonic-gate 	va_list args;
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	va_start(args, fmt);
3390Sstevel@tonic-gate 	(void) vsnprintf(buf, INT_MAX, fmt, args);
3400Sstevel@tonic-gate 	va_end(args);
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	return (strlen(buf));
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate int
vsprintf(char * buf,const char * fmt,va_list args)3460Sstevel@tonic-gate vsprintf(char *buf, const char *fmt, va_list args)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 	(void) vsnprintf(buf, INT_MAX, fmt, args);
3490Sstevel@tonic-gate 	return (strlen(buf));
3500Sstevel@tonic-gate }
3513446Smrj #endif /* _BOOT && __sparc */
3520Sstevel@tonic-gate 
3533446Smrj #endif /* !_KMDB && (!_BOOT || __sparc) */
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate char *
strcat(char * s1,const char * s2)3560Sstevel@tonic-gate strcat(char *s1, const char *s2)
3570Sstevel@tonic-gate {
3580Sstevel@tonic-gate 	char *os1 = s1;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	while (*s1++ != '\0')
3610Sstevel@tonic-gate 		;
3620Sstevel@tonic-gate 	s1--;
3630Sstevel@tonic-gate 	while ((*s1++ = *s2++) != '\0')
3640Sstevel@tonic-gate 		;
3650Sstevel@tonic-gate 	return (os1);
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate char *
strchr(const char * sp,int c)3690Sstevel@tonic-gate strchr(const char *sp, int c)
3700Sstevel@tonic-gate {
3710Sstevel@tonic-gate 	do {
3720Sstevel@tonic-gate 		if (*sp == (char)c)
3730Sstevel@tonic-gate 			return ((char *)sp);
3740Sstevel@tonic-gate 	} while (*sp++);
3750Sstevel@tonic-gate 	return (NULL);
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate int
strcmp(const char * s1,const char * s2)3790Sstevel@tonic-gate strcmp(const char *s1, const char *s2)
3800Sstevel@tonic-gate {
3810Sstevel@tonic-gate 	while (*s1 == *s2++)
3820Sstevel@tonic-gate 		if (*s1++ == '\0')
3830Sstevel@tonic-gate 			return (0);
3840Sstevel@tonic-gate 	return (*(unsigned char *)s1 - *(unsigned char *)--s2);
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate int
strncmp(const char * s1,const char * s2,size_t n)3880Sstevel@tonic-gate strncmp(const char *s1, const char *s2, size_t n)
3890Sstevel@tonic-gate {
3900Sstevel@tonic-gate 	if (s1 == s2)
3910Sstevel@tonic-gate 		return (0);
3920Sstevel@tonic-gate 	n++;
3930Sstevel@tonic-gate 	while (--n != 0 && *s1 == *s2++)
3940Sstevel@tonic-gate 		if (*s1++ == '\0')
3950Sstevel@tonic-gate 			return (0);
3960Sstevel@tonic-gate 	return ((n == 0) ? 0 : *(unsigned char *)s1 - *(unsigned char *)--s2);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate static const char charmap[] = {
4000Sstevel@tonic-gate 	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
4010Sstevel@tonic-gate 	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
4020Sstevel@tonic-gate 	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
4030Sstevel@tonic-gate 	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
4040Sstevel@tonic-gate 	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
4050Sstevel@tonic-gate 	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
4060Sstevel@tonic-gate 	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
4070Sstevel@tonic-gate 	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
4080Sstevel@tonic-gate 	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
4090Sstevel@tonic-gate 	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
4100Sstevel@tonic-gate 	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
4110Sstevel@tonic-gate 	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
4120Sstevel@tonic-gate 	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
4130Sstevel@tonic-gate 	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
4140Sstevel@tonic-gate 	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
4150Sstevel@tonic-gate 	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
4160Sstevel@tonic-gate 	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
4170Sstevel@tonic-gate 	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
4180Sstevel@tonic-gate 	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
4190Sstevel@tonic-gate 	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
4200Sstevel@tonic-gate 	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
4210Sstevel@tonic-gate 	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
4220Sstevel@tonic-gate 	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
4230Sstevel@tonic-gate 	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
4240Sstevel@tonic-gate 	'\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
4250Sstevel@tonic-gate 	'\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
4260Sstevel@tonic-gate 	'\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
4270Sstevel@tonic-gate 	'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
4280Sstevel@tonic-gate 	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
4290Sstevel@tonic-gate 	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
4300Sstevel@tonic-gate 	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
4310Sstevel@tonic-gate 	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
4320Sstevel@tonic-gate };
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate int
strcasecmp(const char * s1,const char * s2)4350Sstevel@tonic-gate strcasecmp(const char *s1, const char *s2)
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate 	const unsigned char *cm = (const unsigned char *)charmap;
4380Sstevel@tonic-gate 	const unsigned char *us1 = (const unsigned char *)s1;
4390Sstevel@tonic-gate 	const unsigned char *us2 = (const unsigned char *)s2;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	while (cm[*us1] == cm[*us2++])
4420Sstevel@tonic-gate 		if (*us1++ == '\0')
4430Sstevel@tonic-gate 			return (0);
4440Sstevel@tonic-gate 	return (cm[*us1] - cm[*(us2 - 1)]);
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate int
strncasecmp(const char * s1,const char * s2,size_t n)4480Sstevel@tonic-gate strncasecmp(const char *s1, const char *s2, size_t n)
4490Sstevel@tonic-gate {
4500Sstevel@tonic-gate 	const unsigned char *cm = (const unsigned char *)charmap;
4510Sstevel@tonic-gate 	const unsigned char *us1 = (const unsigned char *)s1;
4520Sstevel@tonic-gate 	const unsigned char *us2 = (const unsigned char *)s2;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	while (n != 0 && cm[*us1] == cm[*us2++]) {
4550Sstevel@tonic-gate 		if (*us1++ == '\0')
4560Sstevel@tonic-gate 			return (0);
4570Sstevel@tonic-gate 		n--;
4580Sstevel@tonic-gate 	}
4590Sstevel@tonic-gate 	return (n == 0 ? 0 : cm[*us1] - cm[*(us2 - 1)]);
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate char *
strcpy(char * s1,const char * s2)4630Sstevel@tonic-gate strcpy(char *s1, const char *s2)
4640Sstevel@tonic-gate {
4650Sstevel@tonic-gate 	char *os1 = s1;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	while ((*s1++ = *s2++) != '\0')
4680Sstevel@tonic-gate 		;
4690Sstevel@tonic-gate 	return (os1);
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate char *
strncpy(char * s1,const char * s2,size_t n)4730Sstevel@tonic-gate strncpy(char *s1, const char *s2, size_t n)
4740Sstevel@tonic-gate {
4750Sstevel@tonic-gate 	char *os1 = s1;
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	n++;
4780Sstevel@tonic-gate 	while (--n != 0 && (*s1++ = *s2++) != '\0')
4790Sstevel@tonic-gate 		;
4800Sstevel@tonic-gate 	if (n != 0)
4810Sstevel@tonic-gate 		while (--n != 0)
4820Sstevel@tonic-gate 			*s1++ = '\0';
4830Sstevel@tonic-gate 	return (os1);
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate char *
strrchr(const char * sp,int c)4870Sstevel@tonic-gate strrchr(const char *sp, int c)
4880Sstevel@tonic-gate {
4890Sstevel@tonic-gate 	char *r = NULL;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	do {
4920Sstevel@tonic-gate 		if (*sp == (char)c)
4930Sstevel@tonic-gate 			r = (char *)sp;
4940Sstevel@tonic-gate 	} while (*sp++);
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	return (r);
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate char *
strstr(const char * as1,const char * as2)5000Sstevel@tonic-gate strstr(const char *as1, const char *as2)
5010Sstevel@tonic-gate {
5020Sstevel@tonic-gate 	const char *s1, *s2;
5030Sstevel@tonic-gate 	const char *tptr;
5040Sstevel@tonic-gate 	char c;
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	s1 = as1;
5070Sstevel@tonic-gate 	s2 = as2;
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	if (s2 == NULL || *s2 == '\0')
5100Sstevel@tonic-gate 		return ((char *)s1);
5110Sstevel@tonic-gate 	c = *s2;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	while (*s1)
5140Sstevel@tonic-gate 		if (*s1++ == c) {
5150Sstevel@tonic-gate 			tptr = s1;
5160Sstevel@tonic-gate 			while ((c = *++s2) == *s1++ && c)
5170Sstevel@tonic-gate 				;
5180Sstevel@tonic-gate 			if (c == 0)
5190Sstevel@tonic-gate 				return ((char *)tptr - 1);
5200Sstevel@tonic-gate 			s1 = tptr;
5210Sstevel@tonic-gate 			s2 = as2;
5220Sstevel@tonic-gate 			c = *s2;
5230Sstevel@tonic-gate 		}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	return (NULL);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate char *
strpbrk(const char * string,const char * brkset)5290Sstevel@tonic-gate strpbrk(const char *string, const char *brkset)
5300Sstevel@tonic-gate {
5310Sstevel@tonic-gate 	const char *p;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	do {
5340Sstevel@tonic-gate 		for (p = brkset; *p != '\0' && *p != *string; ++p)
5350Sstevel@tonic-gate 			;
5360Sstevel@tonic-gate 		if (*p != '\0')
5370Sstevel@tonic-gate 			return ((char *)string);
5380Sstevel@tonic-gate 	} while (*string++);
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	return (NULL);
5410Sstevel@tonic-gate }
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate char *
strncat(char * s1,const char * s2,size_t n)5440Sstevel@tonic-gate strncat(char *s1, const char *s2, size_t n)
5450Sstevel@tonic-gate {
5460Sstevel@tonic-gate 	char *os1 = s1;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	n++;
5490Sstevel@tonic-gate 	while (*s1++ != '\0')
5500Sstevel@tonic-gate 		;
5510Sstevel@tonic-gate 	--s1;
5520Sstevel@tonic-gate 	while ((*s1++ = *s2++) != '\0') {
5530Sstevel@tonic-gate 		if (--n == 0) {
5540Sstevel@tonic-gate 			s1[-1] = '\0';
5550Sstevel@tonic-gate 			break;
5560Sstevel@tonic-gate 		}
5570Sstevel@tonic-gate 	}
5580Sstevel@tonic-gate 	return (os1);
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate #if defined(_BOOT) || defined(_KMDB)
5620Sstevel@tonic-gate #define	bcopy(src, dst, n)	(void) memcpy((dst), (src), (n))
5630Sstevel@tonic-gate #endif
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate size_t
strlcat(char * dst,const char * src,size_t dstsize)5660Sstevel@tonic-gate strlcat(char *dst, const char *src, size_t dstsize)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate 	char *df = dst;
5690Sstevel@tonic-gate 	size_t left = dstsize;
5700Sstevel@tonic-gate 	size_t l1;
5710Sstevel@tonic-gate 	size_t l2 = strlen(src);
5720Sstevel@tonic-gate 	size_t copied;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	while (left-- != 0 && *df != '\0')
5750Sstevel@tonic-gate 		df++;
5763446Smrj 	/*LINTED: possible ptrdiff_t overflow*/
5773446Smrj 	l1 = (size_t)(df - dst);
5780Sstevel@tonic-gate 	if (dstsize == l1)
5790Sstevel@tonic-gate 		return (l1 + l2);
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	copied = l1 + l2 >= dstsize ? dstsize - l1 - 1 : l2;
5820Sstevel@tonic-gate 	bcopy(src, dst + l1, copied);
5830Sstevel@tonic-gate 	dst[l1+copied] = '\0';
5840Sstevel@tonic-gate 	return (l1 + l2);
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate size_t
strlcpy(char * dst,const char * src,size_t len)5880Sstevel@tonic-gate strlcpy(char *dst, const char *src, size_t len)
5890Sstevel@tonic-gate {
5900Sstevel@tonic-gate 	size_t slen = strlen(src);
5910Sstevel@tonic-gate 	size_t copied;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	if (len == 0)
5940Sstevel@tonic-gate 		return (slen);
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	if (slen >= len)
5970Sstevel@tonic-gate 		copied = len - 1;
5980Sstevel@tonic-gate 	else
5990Sstevel@tonic-gate 		copied = slen;
6000Sstevel@tonic-gate 	bcopy(src, dst, copied);
6010Sstevel@tonic-gate 	dst[copied] = '\0';
6020Sstevel@tonic-gate 	return (slen);
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate size_t
strspn(const char * string,const char * charset)6060Sstevel@tonic-gate strspn(const char *string, const char *charset)
6070Sstevel@tonic-gate {
6080Sstevel@tonic-gate 	const char *p, *q;
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	for (q = string; *q != '\0'; ++q) {
6110Sstevel@tonic-gate 		for (p = charset; *p != '\0' && *p != *q; ++p)
6120Sstevel@tonic-gate 			;
6130Sstevel@tonic-gate 		if (*p == '\0')
6140Sstevel@tonic-gate 			break;
6150Sstevel@tonic-gate 	}
6160Sstevel@tonic-gate 
6173446Smrj 	/*LINTED: possible ptrdiff_t overflow*/
6183446Smrj 	return ((size_t)(q - string));
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate 
6215331Samw size_t
strcspn(const char * string,const char * charset)6225331Samw strcspn(const char *string, const char *charset)
6235331Samw {
6245331Samw 	const char *p, *q;
6255331Samw 
6265331Samw 	for (q = string; *q != '\0'; ++q) {
6275331Samw 		for (p = charset; *p != '\0' && *p != *q; ++p)
6285331Samw 			;
6295331Samw 		if (*p != '\0')
6305331Samw 			break;
6315331Samw 	}
6325331Samw 
6335331Samw 	/*LINTED E_PTRDIFF_OVERFLOW*/
6345331Samw 	return ((size_t)(q - string));
6355331Samw }
6365331Samw 
6375331Samw /*
6385331Samw  * strsep
6395331Samw  *
6405331Samw  * The strsep() function locates, in the string referenced by *stringp, the
6415331Samw  * first occurrence of any character in the string delim (or the terminating
6425331Samw  * `\0' character) and replaces it with a `\0'.  The location of the next
6435331Samw  * character after the delimiter character (or NULL, if the end of the
6445331Samw  * string was reached) is stored in *stringp.  The original value of
6455331Samw  * *stringp is returned.
6465331Samw  *
6475331Samw  * If *stringp is initially NULL, strsep() returns NULL.
648*7478SVladimir.Kotal@Sun.COM  *
649*7478SVladimir.Kotal@Sun.COM  * NOTE: This instance is left for in-kernel use. Libraries and programs
650*7478SVladimir.Kotal@Sun.COM  *       should use strsep from libc.
6515331Samw  */
6525331Samw char *
strsep(char ** stringp,const char * delim)6535331Samw strsep(char **stringp, const char *delim)
6545331Samw {
6555331Samw 	char *s;
6565331Samw 	const char *spanp;
6575331Samw 	int c, sc;
6585331Samw 	char *tok;
6595331Samw 
6605331Samw 	if ((s = *stringp) == NULL)
6615331Samw 		return (NULL);
6625331Samw 
6635331Samw 	for (tok = s; ; ) {
6645331Samw 		c = *s++;
6655331Samw 		spanp = delim;
6665331Samw 		do {
6675331Samw 			if ((sc = *spanp++) == c) {
6685331Samw 				if (c == 0)
6695331Samw 					s = NULL;
6705331Samw 				else
6715331Samw 					s[-1] = 0;
6725331Samw 				*stringp = s;
6735331Samw 				return (tok);
6745331Samw 			}
6755331Samw 		} while (sc != 0);
6765331Samw 	}
6775331Samw 	/* NOTREACHED */
6785331Samw }
6795331Samw 
6800Sstevel@tonic-gate /*
6810Sstevel@tonic-gate  * Unless mentioned otherwise, all of the routines below should be added to
6820Sstevel@tonic-gate  * the Solaris DDI as necessary.  For now, only provide them to standalone.
6830Sstevel@tonic-gate  */
6840Sstevel@tonic-gate #if defined(_BOOT) || defined(_KMDB)
6850Sstevel@tonic-gate char *
strtok(char * string,const char * sepset)6860Sstevel@tonic-gate strtok(char *string, const char *sepset)
6870Sstevel@tonic-gate {
6880Sstevel@tonic-gate 	char		*p, *q, *r;
6890Sstevel@tonic-gate 	static char	*savept;
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	/*
6920Sstevel@tonic-gate 	 * Set `p' to our current location in the string.
6930Sstevel@tonic-gate 	 */
6940Sstevel@tonic-gate 	p = (string == NULL) ? savept : string;
6950Sstevel@tonic-gate 	if (p == NULL)
6960Sstevel@tonic-gate 		return (NULL);
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	/*
6990Sstevel@tonic-gate 	 * Skip leading separators; bail if no tokens remain.
7000Sstevel@tonic-gate 	 */
7010Sstevel@tonic-gate 	q = p + strspn(p, sepset);
7020Sstevel@tonic-gate 	if (*q == '\0')
7030Sstevel@tonic-gate 		return (NULL);
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	/*
7060Sstevel@tonic-gate 	 * Mark the end of the token and set `savept' for the next iteration.
7070Sstevel@tonic-gate 	 */
7080Sstevel@tonic-gate 	if ((r = strpbrk(q, sepset)) == NULL)
7090Sstevel@tonic-gate 		savept = NULL;
7100Sstevel@tonic-gate 	else {
7110Sstevel@tonic-gate 		*r = '\0';
7120Sstevel@tonic-gate 		savept = ++r;
7130Sstevel@tonic-gate 	}
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	return (q);
7160Sstevel@tonic-gate }
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate /*
7190Sstevel@tonic-gate  * The strlen() routine isn't shared with the kernel because it has its own
7200Sstevel@tonic-gate  * hand-tuned assembly version.
7210Sstevel@tonic-gate  */
7220Sstevel@tonic-gate size_t
strlen(const char * s)7230Sstevel@tonic-gate strlen(const char *s)
7240Sstevel@tonic-gate {
7250Sstevel@tonic-gate 	size_t n = 0;
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	while (*s++)
7280Sstevel@tonic-gate 		n++;
7290Sstevel@tonic-gate 	return (n);
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate #endif /* _BOOT || _KMDB */
7330Sstevel@tonic-gate 
7345930Smyers /*
7355930Smyers  * Returns the number of non-NULL bytes in string argument,
7365930Smyers  * but not more than maxlen.  Does not look past str + maxlen.
7375930Smyers  */
7385930Smyers size_t
strnlen(const char * s,size_t maxlen)7395930Smyers strnlen(const char *s, size_t maxlen)
7405930Smyers {
7415930Smyers 	size_t n = 0;
7425930Smyers 
7435930Smyers 	while (maxlen != 0 && *s != 0) {
7445930Smyers 		s++;
7455930Smyers 		maxlen--;
7465930Smyers 		n++;
7475930Smyers 	}
7485930Smyers 
7495930Smyers 	return (n);
7505930Smyers }
7515930Smyers 
7525930Smyers 
7530Sstevel@tonic-gate #ifdef _KERNEL
7540Sstevel@tonic-gate /*
7550Sstevel@tonic-gate  * Check for a valid C identifier:
7560Sstevel@tonic-gate  *	a letter or underscore, followed by
7570Sstevel@tonic-gate  *	zero or more letters, digits and underscores.
7580Sstevel@tonic-gate  */
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate #define	IS_DIGIT(c)	((c) >= '0' && (c) <= '9')
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate #define	IS_ALPHA(c)	\
7630Sstevel@tonic-gate 	(((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate int
strident_valid(const char * id)7660Sstevel@tonic-gate strident_valid(const char *id)
7670Sstevel@tonic-gate {
7680Sstevel@tonic-gate 	int c = *id++;
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	if (!IS_ALPHA(c) && c != '_')
7710Sstevel@tonic-gate 		return (0);
7720Sstevel@tonic-gate 	while ((c = *id++) != 0) {
7730Sstevel@tonic-gate 		if (!IS_ALPHA(c) && !IS_DIGIT(c) && c != '_')
7740Sstevel@tonic-gate 			return (0);
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate 	return (1);
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate /*
7800Sstevel@tonic-gate  * Convert a string into a valid C identifier by replacing invalid
7810Sstevel@tonic-gate  * characters with '_'.  Also makes sure the string is nul-terminated
7820Sstevel@tonic-gate  * and takes up at most n bytes.
7830Sstevel@tonic-gate  */
7840Sstevel@tonic-gate void
strident_canon(char * s,size_t n)7850Sstevel@tonic-gate strident_canon(char *s, size_t n)
7860Sstevel@tonic-gate {
7870Sstevel@tonic-gate 	char c;
7880Sstevel@tonic-gate 	char *end = s + n - 1;
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	ASSERT(n > 0);
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	if ((c = *s) == 0)
7930Sstevel@tonic-gate 		return;
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	if (!IS_ALPHA(c) && c != '_')
7960Sstevel@tonic-gate 		*s = '_';
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	while (s < end && ((c = *(++s)) != 0)) {
7990Sstevel@tonic-gate 		if (!IS_ALPHA(c) && !IS_DIGIT(c) && c != '_')
8000Sstevel@tonic-gate 			*s = '_';
8010Sstevel@tonic-gate 	}
8020Sstevel@tonic-gate 	*s = 0;
8030Sstevel@tonic-gate }
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate #endif	/* _KERNEL */
806