1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * Implementations of the functions described in vsnprintf(3C) and string(3C),
31*0Sstevel@tonic-gate  * for use by the kernel, the standalone, and kmdb.  Unless otherwise specified,
32*0Sstevel@tonic-gate  * these functions match the section 3C manpages.
33*0Sstevel@tonic-gate  */
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include <sys/types.h>
36*0Sstevel@tonic-gate #include <sys/varargs.h>
37*0Sstevel@tonic-gate #if defined(_BOOT) || defined(_KMDB)
38*0Sstevel@tonic-gate #include <string.h>
39*0Sstevel@tonic-gate #else
40*0Sstevel@tonic-gate #include <sys/systm.h>
41*0Sstevel@tonic-gate #endif
42*0Sstevel@tonic-gate #ifdef _KERNEL
43*0Sstevel@tonic-gate #include <sys/debug.h>
44*0Sstevel@tonic-gate #endif	/* _KERNEL */
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate /*
47*0Sstevel@tonic-gate  * kmdb has its own *printf routines, and thus doesn't need these versions too.
48*0Sstevel@tonic-gate  */
49*0Sstevel@tonic-gate #if !defined(_KMDB)
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate #define	ADDCHAR(c)	if (bufp++ - buf < buflen) bufp[-1] = (c)
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate /*
54*0Sstevel@tonic-gate  * Given a buffer 'buf' of size 'buflen', render as much of the string
55*0Sstevel@tonic-gate  * described by <fmt, args> as possible.  The string will always be
56*0Sstevel@tonic-gate  * null-terminated, so the maximum string length is 'buflen - 1'.
57*0Sstevel@tonic-gate  * Returns the number of bytes that would be necessary to render the
58*0Sstevel@tonic-gate  * entire string, not including null terminator (just like vsnprintf(3S)).
59*0Sstevel@tonic-gate  * To determine buffer size in advance, use vsnprintf(NULL, 0, fmt, args) + 1.
60*0Sstevel@tonic-gate  *
61*0Sstevel@tonic-gate  * There is no support for floating point, and the C locale is assumed.
62*0Sstevel@tonic-gate  */
63*0Sstevel@tonic-gate size_t
64*0Sstevel@tonic-gate vsnprintf(char *buf, size_t buflen, const char *fmt, va_list aargs)
65*0Sstevel@tonic-gate {
66*0Sstevel@tonic-gate 	uint64_t ul, tmp;
67*0Sstevel@tonic-gate 	char *bufp = buf;	/* current buffer pointer */
68*0Sstevel@tonic-gate 	int pad, width, ells, base, sign, c;
69*0Sstevel@tonic-gate 	char *digits, *sp, *bs;
70*0Sstevel@tonic-gate 	char numbuf[65];	/* sufficient for a 64-bit binary value */
71*0Sstevel@tonic-gate 	va_list args;
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	/*
74*0Sstevel@tonic-gate 	 * Make a copy so that all our callers don't have to make a copy
75*0Sstevel@tonic-gate 	 */
76*0Sstevel@tonic-gate 	va_copy(args, aargs);
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 	if ((ssize_t)buflen < 0)
79*0Sstevel@tonic-gate 		buflen = 0;
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate 	while ((c = *fmt++) != '\0') {
82*0Sstevel@tonic-gate 		if (c != '%') {
83*0Sstevel@tonic-gate 			ADDCHAR(c);
84*0Sstevel@tonic-gate 			continue;
85*0Sstevel@tonic-gate 		}
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 		if ((c = *fmt++) == '\0')
88*0Sstevel@tonic-gate 			break;
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate 		for (pad = ' '; c == '0'; c = *fmt++)
91*0Sstevel@tonic-gate 			pad = '0';
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 		for (width = 0; c >= '0' && c <= '9'; c = *fmt++)
94*0Sstevel@tonic-gate 			width = width * 10 + c - '0';
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 		for (ells = 0; c == 'l'; c = *fmt++)
97*0Sstevel@tonic-gate 			ells++;
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 		digits = "0123456789abcdef";
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 		if (c >= 'A' && c <= 'Z') {
102*0Sstevel@tonic-gate 			c += 'a' - 'A';
103*0Sstevel@tonic-gate 			digits = "0123456789ABCDEF";
104*0Sstevel@tonic-gate 		}
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 		base = sign = 0;
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate 		switch (c) {
109*0Sstevel@tonic-gate 		case 'd':
110*0Sstevel@tonic-gate 			sign = 1;
111*0Sstevel@tonic-gate 			/*FALLTHROUGH*/
112*0Sstevel@tonic-gate 		case 'u':
113*0Sstevel@tonic-gate 			base = 10;
114*0Sstevel@tonic-gate 			break;
115*0Sstevel@tonic-gate 		case 'p':
116*0Sstevel@tonic-gate 			ells = 1;
117*0Sstevel@tonic-gate 			/*FALLTHROUGH*/
118*0Sstevel@tonic-gate 		case 'x':
119*0Sstevel@tonic-gate 			base = 16;
120*0Sstevel@tonic-gate 			break;
121*0Sstevel@tonic-gate 		case 'o':
122*0Sstevel@tonic-gate 			base = 8;
123*0Sstevel@tonic-gate 			break;
124*0Sstevel@tonic-gate 		case 'b':
125*0Sstevel@tonic-gate 			ells = 0;
126*0Sstevel@tonic-gate 			base = 1;
127*0Sstevel@tonic-gate 			break;
128*0Sstevel@tonic-gate 		case 'c':
129*0Sstevel@tonic-gate 			ul = (int64_t)va_arg(args, int);
130*0Sstevel@tonic-gate 			ADDCHAR((int)ul & 0xff);
131*0Sstevel@tonic-gate 			break;
132*0Sstevel@tonic-gate 		case 's':
133*0Sstevel@tonic-gate 			sp = va_arg(args, char *);
134*0Sstevel@tonic-gate 			if (sp == NULL)
135*0Sstevel@tonic-gate 				sp = "<null string>";
136*0Sstevel@tonic-gate 			while ((c = *sp++) != 0)
137*0Sstevel@tonic-gate 				ADDCHAR(c);
138*0Sstevel@tonic-gate 			break;
139*0Sstevel@tonic-gate 		case '%':
140*0Sstevel@tonic-gate 			ADDCHAR('%');
141*0Sstevel@tonic-gate 			break;
142*0Sstevel@tonic-gate 		}
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 		if (base == 0)
145*0Sstevel@tonic-gate 			continue;
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 		if (ells == 0)
148*0Sstevel@tonic-gate 			ul = (int64_t)va_arg(args, int);
149*0Sstevel@tonic-gate 		else if (ells == 1)
150*0Sstevel@tonic-gate 			ul = (int64_t)va_arg(args, long);
151*0Sstevel@tonic-gate 		else
152*0Sstevel@tonic-gate 			ul = (int64_t)va_arg(args, int64_t);
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 		if (sign && (int64_t)ul < 0)
155*0Sstevel@tonic-gate 			ul = -ul;
156*0Sstevel@tonic-gate 		else
157*0Sstevel@tonic-gate 			sign = 0;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 		if (ells < 8 / sizeof (long))
160*0Sstevel@tonic-gate 			ul &= 0xffffffffU;
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 		if (c == 'b') {
163*0Sstevel@tonic-gate 			bs = va_arg(args, char *);
164*0Sstevel@tonic-gate 			base = *bs++;
165*0Sstevel@tonic-gate 		}
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 		tmp = ul;
168*0Sstevel@tonic-gate 		do {
169*0Sstevel@tonic-gate 			width--;
170*0Sstevel@tonic-gate 		} while ((tmp /= base) != 0);
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 		if (sign && pad == '0')
173*0Sstevel@tonic-gate 			ADDCHAR('-');
174*0Sstevel@tonic-gate 		while (width-- > sign)
175*0Sstevel@tonic-gate 			ADDCHAR(pad);
176*0Sstevel@tonic-gate 		if (sign && pad == ' ')
177*0Sstevel@tonic-gate 			ADDCHAR('-');
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 		sp = numbuf;
180*0Sstevel@tonic-gate 		tmp = ul;
181*0Sstevel@tonic-gate 		do {
182*0Sstevel@tonic-gate 			*sp++ = digits[tmp % base];
183*0Sstevel@tonic-gate 		} while ((tmp /= base) != 0);
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 		while (sp > numbuf) {
186*0Sstevel@tonic-gate 			sp--;
187*0Sstevel@tonic-gate 			ADDCHAR(*sp);
188*0Sstevel@tonic-gate 		}
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 		if (c == 'b' && ul != 0) {
191*0Sstevel@tonic-gate 			int any = 0;
192*0Sstevel@tonic-gate 			c = *bs++;
193*0Sstevel@tonic-gate 			while (c != 0) {
194*0Sstevel@tonic-gate 				if (ul & (1 << (c - 1))) {
195*0Sstevel@tonic-gate 					if (any++ == 0)
196*0Sstevel@tonic-gate 						ADDCHAR('<');
197*0Sstevel@tonic-gate 					while ((c = *bs++) >= 32)
198*0Sstevel@tonic-gate 						ADDCHAR(c);
199*0Sstevel@tonic-gate 					ADDCHAR(',');
200*0Sstevel@tonic-gate 				} else {
201*0Sstevel@tonic-gate 					while ((c = *bs++) >= 32)
202*0Sstevel@tonic-gate 						continue;
203*0Sstevel@tonic-gate 				}
204*0Sstevel@tonic-gate 			}
205*0Sstevel@tonic-gate 			if (any) {
206*0Sstevel@tonic-gate 				bufp--;
207*0Sstevel@tonic-gate 				ADDCHAR('>');
208*0Sstevel@tonic-gate 			}
209*0Sstevel@tonic-gate 		}
210*0Sstevel@tonic-gate 	}
211*0Sstevel@tonic-gate 	if (bufp - buf < buflen)
212*0Sstevel@tonic-gate 		bufp[0] = c;
213*0Sstevel@tonic-gate 	else if (buflen != 0)
214*0Sstevel@tonic-gate 		buf[buflen - 1] = c;
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	va_end(args);
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	return (bufp - buf);
219*0Sstevel@tonic-gate }
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate /*PRINTFLIKE1*/
222*0Sstevel@tonic-gate size_t
223*0Sstevel@tonic-gate snprintf(char *buf, size_t buflen, const char *fmt, ...)
224*0Sstevel@tonic-gate {
225*0Sstevel@tonic-gate 	va_list args;
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	va_start(args, fmt);
228*0Sstevel@tonic-gate 	buflen = vsnprintf(buf, buflen, fmt, args);
229*0Sstevel@tonic-gate 	va_end(args);
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	return (buflen);
232*0Sstevel@tonic-gate }
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate #if defined(_BOOT)
235*0Sstevel@tonic-gate /*
236*0Sstevel@tonic-gate  * The sprintf() and vsprintf() routines aren't shared with the kernel because
237*0Sstevel@tonic-gate  * the DDI mandates that they return the buffer rather than its length.
238*0Sstevel@tonic-gate  */
239*0Sstevel@tonic-gate /*PRINTFLIKE2*/
240*0Sstevel@tonic-gate int
241*0Sstevel@tonic-gate sprintf(char *buf, const char *fmt, ...)
242*0Sstevel@tonic-gate {
243*0Sstevel@tonic-gate 	va_list args;
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	va_start(args, fmt);
246*0Sstevel@tonic-gate 	(void) vsnprintf(buf, INT_MAX, fmt, args);
247*0Sstevel@tonic-gate 	va_end(args);
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	return (strlen(buf));
250*0Sstevel@tonic-gate }
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate int
253*0Sstevel@tonic-gate vsprintf(char *buf, const char *fmt, va_list args)
254*0Sstevel@tonic-gate {
255*0Sstevel@tonic-gate 	(void) vsnprintf(buf, INT_MAX, fmt, args);
256*0Sstevel@tonic-gate 	return (strlen(buf));
257*0Sstevel@tonic-gate }
258*0Sstevel@tonic-gate #endif
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate #endif /* !_KMDB */
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate char *
263*0Sstevel@tonic-gate strcat(char *s1, const char *s2)
264*0Sstevel@tonic-gate {
265*0Sstevel@tonic-gate 	char *os1 = s1;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 	while (*s1++ != '\0')
268*0Sstevel@tonic-gate 		;
269*0Sstevel@tonic-gate 	s1--;
270*0Sstevel@tonic-gate 	while ((*s1++ = *s2++) != '\0')
271*0Sstevel@tonic-gate 		;
272*0Sstevel@tonic-gate 	return (os1);
273*0Sstevel@tonic-gate }
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate char *
276*0Sstevel@tonic-gate strchr(const char *sp, int c)
277*0Sstevel@tonic-gate {
278*0Sstevel@tonic-gate 	do {
279*0Sstevel@tonic-gate 		if (*sp == (char)c)
280*0Sstevel@tonic-gate 			return ((char *)sp);
281*0Sstevel@tonic-gate 	} while (*sp++);
282*0Sstevel@tonic-gate 	return (NULL);
283*0Sstevel@tonic-gate }
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate int
286*0Sstevel@tonic-gate strcmp(const char *s1, const char *s2)
287*0Sstevel@tonic-gate {
288*0Sstevel@tonic-gate 	while (*s1 == *s2++)
289*0Sstevel@tonic-gate 		if (*s1++ == '\0')
290*0Sstevel@tonic-gate 			return (0);
291*0Sstevel@tonic-gate 	return (*(unsigned char *)s1 - *(unsigned char *)--s2);
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate int
295*0Sstevel@tonic-gate strncmp(const char *s1, const char *s2, size_t n)
296*0Sstevel@tonic-gate {
297*0Sstevel@tonic-gate 	if (s1 == s2)
298*0Sstevel@tonic-gate 		return (0);
299*0Sstevel@tonic-gate 	n++;
300*0Sstevel@tonic-gate 	while (--n != 0 && *s1 == *s2++)
301*0Sstevel@tonic-gate 		if (*s1++ == '\0')
302*0Sstevel@tonic-gate 			return (0);
303*0Sstevel@tonic-gate 	return ((n == 0) ? 0 : *(unsigned char *)s1 - *(unsigned char *)--s2);
304*0Sstevel@tonic-gate }
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate static const char charmap[] = {
307*0Sstevel@tonic-gate 	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
308*0Sstevel@tonic-gate 	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
309*0Sstevel@tonic-gate 	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
310*0Sstevel@tonic-gate 	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
311*0Sstevel@tonic-gate 	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
312*0Sstevel@tonic-gate 	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
313*0Sstevel@tonic-gate 	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
314*0Sstevel@tonic-gate 	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
315*0Sstevel@tonic-gate 	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
316*0Sstevel@tonic-gate 	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
317*0Sstevel@tonic-gate 	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
318*0Sstevel@tonic-gate 	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
319*0Sstevel@tonic-gate 	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
320*0Sstevel@tonic-gate 	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
321*0Sstevel@tonic-gate 	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
322*0Sstevel@tonic-gate 	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
323*0Sstevel@tonic-gate 	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
324*0Sstevel@tonic-gate 	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
325*0Sstevel@tonic-gate 	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
326*0Sstevel@tonic-gate 	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
327*0Sstevel@tonic-gate 	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
328*0Sstevel@tonic-gate 	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
329*0Sstevel@tonic-gate 	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
330*0Sstevel@tonic-gate 	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
331*0Sstevel@tonic-gate 	'\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
332*0Sstevel@tonic-gate 	'\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
333*0Sstevel@tonic-gate 	'\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
334*0Sstevel@tonic-gate 	'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
335*0Sstevel@tonic-gate 	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
336*0Sstevel@tonic-gate 	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
337*0Sstevel@tonic-gate 	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
338*0Sstevel@tonic-gate 	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
339*0Sstevel@tonic-gate };
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate int
342*0Sstevel@tonic-gate strcasecmp(const char *s1, const char *s2)
343*0Sstevel@tonic-gate {
344*0Sstevel@tonic-gate 	const unsigned char *cm = (const unsigned char *)charmap;
345*0Sstevel@tonic-gate 	const unsigned char *us1 = (const unsigned char *)s1;
346*0Sstevel@tonic-gate 	const unsigned char *us2 = (const unsigned char *)s2;
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 	while (cm[*us1] == cm[*us2++])
349*0Sstevel@tonic-gate 		if (*us1++ == '\0')
350*0Sstevel@tonic-gate 			return (0);
351*0Sstevel@tonic-gate 	return (cm[*us1] - cm[*(us2 - 1)]);
352*0Sstevel@tonic-gate }
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate int
355*0Sstevel@tonic-gate strncasecmp(const char *s1, const char *s2, size_t n)
356*0Sstevel@tonic-gate {
357*0Sstevel@tonic-gate 	const unsigned char *cm = (const unsigned char *)charmap;
358*0Sstevel@tonic-gate 	const unsigned char *us1 = (const unsigned char *)s1;
359*0Sstevel@tonic-gate 	const unsigned char *us2 = (const unsigned char *)s2;
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	while (n != 0 && cm[*us1] == cm[*us2++]) {
362*0Sstevel@tonic-gate 		if (*us1++ == '\0')
363*0Sstevel@tonic-gate 			return (0);
364*0Sstevel@tonic-gate 		n--;
365*0Sstevel@tonic-gate 	}
366*0Sstevel@tonic-gate 	return (n == 0 ? 0 : cm[*us1] - cm[*(us2 - 1)]);
367*0Sstevel@tonic-gate }
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate char *
370*0Sstevel@tonic-gate strcpy(char *s1, const char *s2)
371*0Sstevel@tonic-gate {
372*0Sstevel@tonic-gate 	char *os1 = s1;
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 	while ((*s1++ = *s2++) != '\0')
375*0Sstevel@tonic-gate 		;
376*0Sstevel@tonic-gate 	return (os1);
377*0Sstevel@tonic-gate }
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate char *
380*0Sstevel@tonic-gate strncpy(char *s1, const char *s2, size_t n)
381*0Sstevel@tonic-gate {
382*0Sstevel@tonic-gate 	char *os1 = s1;
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	n++;
385*0Sstevel@tonic-gate 	while (--n != 0 && (*s1++ = *s2++) != '\0')
386*0Sstevel@tonic-gate 		;
387*0Sstevel@tonic-gate 	if (n != 0)
388*0Sstevel@tonic-gate 		while (--n != 0)
389*0Sstevel@tonic-gate 			*s1++ = '\0';
390*0Sstevel@tonic-gate 	return (os1);
391*0Sstevel@tonic-gate }
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate char *
394*0Sstevel@tonic-gate strrchr(const char *sp, int c)
395*0Sstevel@tonic-gate {
396*0Sstevel@tonic-gate 	char *r = NULL;
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 	do {
399*0Sstevel@tonic-gate 		if (*sp == (char)c)
400*0Sstevel@tonic-gate 			r = (char *)sp;
401*0Sstevel@tonic-gate 	} while (*sp++);
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	return (r);
404*0Sstevel@tonic-gate }
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate char *
407*0Sstevel@tonic-gate strstr(const char *as1, const char *as2)
408*0Sstevel@tonic-gate {
409*0Sstevel@tonic-gate 	const char *s1, *s2;
410*0Sstevel@tonic-gate 	const char *tptr;
411*0Sstevel@tonic-gate 	char c;
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 	s1 = as1;
414*0Sstevel@tonic-gate 	s2 = as2;
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 	if (s2 == NULL || *s2 == '\0')
417*0Sstevel@tonic-gate 		return ((char *)s1);
418*0Sstevel@tonic-gate 	c = *s2;
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	while (*s1)
421*0Sstevel@tonic-gate 		if (*s1++ == c) {
422*0Sstevel@tonic-gate 			tptr = s1;
423*0Sstevel@tonic-gate 			while ((c = *++s2) == *s1++ && c)
424*0Sstevel@tonic-gate 				;
425*0Sstevel@tonic-gate 			if (c == 0)
426*0Sstevel@tonic-gate 				return ((char *)tptr - 1);
427*0Sstevel@tonic-gate 			s1 = tptr;
428*0Sstevel@tonic-gate 			s2 = as2;
429*0Sstevel@tonic-gate 			c = *s2;
430*0Sstevel@tonic-gate 		}
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 	return (NULL);
433*0Sstevel@tonic-gate }
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate char *
436*0Sstevel@tonic-gate strpbrk(const char *string, const char *brkset)
437*0Sstevel@tonic-gate {
438*0Sstevel@tonic-gate 	const char *p;
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	do {
441*0Sstevel@tonic-gate 		for (p = brkset; *p != '\0' && *p != *string; ++p)
442*0Sstevel@tonic-gate 			;
443*0Sstevel@tonic-gate 		if (*p != '\0')
444*0Sstevel@tonic-gate 			return ((char *)string);
445*0Sstevel@tonic-gate 	} while (*string++);
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	return (NULL);
448*0Sstevel@tonic-gate }
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate char *
451*0Sstevel@tonic-gate strncat(char *s1, const char *s2, size_t n)
452*0Sstevel@tonic-gate {
453*0Sstevel@tonic-gate 	char *os1 = s1;
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	n++;
456*0Sstevel@tonic-gate 	while (*s1++ != '\0')
457*0Sstevel@tonic-gate 		;
458*0Sstevel@tonic-gate 	--s1;
459*0Sstevel@tonic-gate 	while ((*s1++ = *s2++) != '\0') {
460*0Sstevel@tonic-gate 		if (--n == 0) {
461*0Sstevel@tonic-gate 			s1[-1] = '\0';
462*0Sstevel@tonic-gate 			break;
463*0Sstevel@tonic-gate 		}
464*0Sstevel@tonic-gate 	}
465*0Sstevel@tonic-gate 	return (os1);
466*0Sstevel@tonic-gate }
467*0Sstevel@tonic-gate 
468*0Sstevel@tonic-gate #if defined(_BOOT) || defined(_KMDB)
469*0Sstevel@tonic-gate #define	bcopy(src, dst, n)	(void) memcpy((dst), (src), (n))
470*0Sstevel@tonic-gate #endif
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate size_t
473*0Sstevel@tonic-gate strlcat(char *dst, const char *src, size_t dstsize)
474*0Sstevel@tonic-gate {
475*0Sstevel@tonic-gate 	char *df = dst;
476*0Sstevel@tonic-gate 	size_t left = dstsize;
477*0Sstevel@tonic-gate 	size_t l1;
478*0Sstevel@tonic-gate 	size_t l2 = strlen(src);
479*0Sstevel@tonic-gate 	size_t copied;
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 	while (left-- != 0 && *df != '\0')
482*0Sstevel@tonic-gate 		df++;
483*0Sstevel@tonic-gate 	l1 = df - dst;
484*0Sstevel@tonic-gate 	if (dstsize == l1)
485*0Sstevel@tonic-gate 		return (l1 + l2);
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	copied = l1 + l2 >= dstsize ? dstsize - l1 - 1 : l2;
488*0Sstevel@tonic-gate 	bcopy(src, dst + l1, copied);
489*0Sstevel@tonic-gate 	dst[l1+copied] = '\0';
490*0Sstevel@tonic-gate 	return (l1 + l2);
491*0Sstevel@tonic-gate }
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate size_t
494*0Sstevel@tonic-gate strlcpy(char *dst, const char *src, size_t len)
495*0Sstevel@tonic-gate {
496*0Sstevel@tonic-gate 	size_t slen = strlen(src);
497*0Sstevel@tonic-gate 	size_t copied;
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	if (len == 0)
500*0Sstevel@tonic-gate 		return (slen);
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	if (slen >= len)
503*0Sstevel@tonic-gate 		copied = len - 1;
504*0Sstevel@tonic-gate 	else
505*0Sstevel@tonic-gate 		copied = slen;
506*0Sstevel@tonic-gate 	bcopy(src, dst, copied);
507*0Sstevel@tonic-gate 	dst[copied] = '\0';
508*0Sstevel@tonic-gate 	return (slen);
509*0Sstevel@tonic-gate }
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate size_t
512*0Sstevel@tonic-gate strspn(const char *string, const char *charset)
513*0Sstevel@tonic-gate {
514*0Sstevel@tonic-gate 	const char *p, *q;
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 	for (q = string; *q != '\0'; ++q) {
517*0Sstevel@tonic-gate 		for (p = charset; *p != '\0' && *p != *q; ++p)
518*0Sstevel@tonic-gate 			;
519*0Sstevel@tonic-gate 		if (*p == '\0')
520*0Sstevel@tonic-gate 			break;
521*0Sstevel@tonic-gate 	}
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 	return (q - string);
524*0Sstevel@tonic-gate }
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate /*
527*0Sstevel@tonic-gate  * Unless mentioned otherwise, all of the routines below should be added to
528*0Sstevel@tonic-gate  * the Solaris DDI as necessary.  For now, only provide them to standalone.
529*0Sstevel@tonic-gate  */
530*0Sstevel@tonic-gate #if defined(_BOOT) || defined(_KMDB)
531*0Sstevel@tonic-gate char *
532*0Sstevel@tonic-gate strtok(char *string, const char *sepset)
533*0Sstevel@tonic-gate {
534*0Sstevel@tonic-gate 	char		*p, *q, *r;
535*0Sstevel@tonic-gate 	static char	*savept;
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	/*
538*0Sstevel@tonic-gate 	 * Set `p' to our current location in the string.
539*0Sstevel@tonic-gate 	 */
540*0Sstevel@tonic-gate 	p = (string == NULL) ? savept : string;
541*0Sstevel@tonic-gate 	if (p == NULL)
542*0Sstevel@tonic-gate 		return (NULL);
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 	/*
545*0Sstevel@tonic-gate 	 * Skip leading separators; bail if no tokens remain.
546*0Sstevel@tonic-gate 	 */
547*0Sstevel@tonic-gate 	q = p + strspn(p, sepset);
548*0Sstevel@tonic-gate 	if (*q == '\0')
549*0Sstevel@tonic-gate 		return (NULL);
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 	/*
552*0Sstevel@tonic-gate 	 * Mark the end of the token and set `savept' for the next iteration.
553*0Sstevel@tonic-gate 	 */
554*0Sstevel@tonic-gate 	if ((r = strpbrk(q, sepset)) == NULL)
555*0Sstevel@tonic-gate 		savept = NULL;
556*0Sstevel@tonic-gate 	else {
557*0Sstevel@tonic-gate 		*r = '\0';
558*0Sstevel@tonic-gate 		savept = ++r;
559*0Sstevel@tonic-gate 	}
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 	return (q);
562*0Sstevel@tonic-gate }
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate /*
565*0Sstevel@tonic-gate  * The strlen() routine isn't shared with the kernel because it has its own
566*0Sstevel@tonic-gate  * hand-tuned assembly version.
567*0Sstevel@tonic-gate  */
568*0Sstevel@tonic-gate size_t
569*0Sstevel@tonic-gate strlen(const char *s)
570*0Sstevel@tonic-gate {
571*0Sstevel@tonic-gate 	size_t n = 0;
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	while (*s++)
574*0Sstevel@tonic-gate 		n++;
575*0Sstevel@tonic-gate 	return (n);
576*0Sstevel@tonic-gate }
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate #endif /* _BOOT || _KMDB */
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate #ifdef _KERNEL
581*0Sstevel@tonic-gate /*
582*0Sstevel@tonic-gate  * Check for a valid C identifier:
583*0Sstevel@tonic-gate  *	a letter or underscore, followed by
584*0Sstevel@tonic-gate  *	zero or more letters, digits and underscores.
585*0Sstevel@tonic-gate  */
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate #define	IS_DIGIT(c)	((c) >= '0' && (c) <= '9')
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate #define	IS_ALPHA(c)	\
590*0Sstevel@tonic-gate 	(((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate int
593*0Sstevel@tonic-gate strident_valid(const char *id)
594*0Sstevel@tonic-gate {
595*0Sstevel@tonic-gate 	int c = *id++;
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate 	if (!IS_ALPHA(c) && c != '_')
598*0Sstevel@tonic-gate 		return (0);
599*0Sstevel@tonic-gate 	while ((c = *id++) != 0) {
600*0Sstevel@tonic-gate 		if (!IS_ALPHA(c) && !IS_DIGIT(c) && c != '_')
601*0Sstevel@tonic-gate 			return (0);
602*0Sstevel@tonic-gate 	}
603*0Sstevel@tonic-gate 	return (1);
604*0Sstevel@tonic-gate }
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate /*
607*0Sstevel@tonic-gate  * Convert a string into a valid C identifier by replacing invalid
608*0Sstevel@tonic-gate  * characters with '_'.  Also makes sure the string is nul-terminated
609*0Sstevel@tonic-gate  * and takes up at most n bytes.
610*0Sstevel@tonic-gate  */
611*0Sstevel@tonic-gate void
612*0Sstevel@tonic-gate strident_canon(char *s, size_t n)
613*0Sstevel@tonic-gate {
614*0Sstevel@tonic-gate 	char c;
615*0Sstevel@tonic-gate 	char *end = s + n - 1;
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate 	ASSERT(n > 0);
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	if ((c = *s) == 0)
620*0Sstevel@tonic-gate 		return;
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 	if (!IS_ALPHA(c) && c != '_')
623*0Sstevel@tonic-gate 		*s = '_';
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	while (s < end && ((c = *(++s)) != 0)) {
626*0Sstevel@tonic-gate 		if (!IS_ALPHA(c) && !IS_DIGIT(c) && c != '_')
627*0Sstevel@tonic-gate 			*s = '_';
628*0Sstevel@tonic-gate 	}
629*0Sstevel@tonic-gate 	*s = 0;
630*0Sstevel@tonic-gate }
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate #endif	/* _KERNEL */
633