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