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 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 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 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 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 * 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 * 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 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 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 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 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 * 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 * 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 * 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 * 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 * 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 * 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 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 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 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 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 * 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 * 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 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 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 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 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