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 2005 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 #include <strings.h> 30*0Sstevel@tonic-gate #include <stdlib.h> 31*0Sstevel@tonic-gate #include <errno.h> 32*0Sstevel@tonic-gate #include <ctype.h> 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include <dt_string.h> 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate /* 37*0Sstevel@tonic-gate * Create a copy of string s, but only duplicate the first n bytes. 38*0Sstevel@tonic-gate */ 39*0Sstevel@tonic-gate char * 40*0Sstevel@tonic-gate strndup(const char *s, size_t n) 41*0Sstevel@tonic-gate { 42*0Sstevel@tonic-gate char *s2 = malloc(n + 1); 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate (void) strncpy(s2, s, n); 45*0Sstevel@tonic-gate s2[n] = '\0'; 46*0Sstevel@tonic-gate return (s2); 47*0Sstevel@tonic-gate } 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate /* 50*0Sstevel@tonic-gate * Transform string s inline, converting each embedded C escape sequence string 51*0Sstevel@tonic-gate * to the corresponding character. For example, the substring "\n" is replaced 52*0Sstevel@tonic-gate * by an inline '\n' character. The length of the resulting string is returned. 53*0Sstevel@tonic-gate */ 54*0Sstevel@tonic-gate size_t 55*0Sstevel@tonic-gate stresc2chr(char *s) 56*0Sstevel@tonic-gate { 57*0Sstevel@tonic-gate char *p, *q, c; 58*0Sstevel@tonic-gate int esc = 0; 59*0Sstevel@tonic-gate int x; 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate for (p = q = s; (c = *p) != '\0'; p++) { 62*0Sstevel@tonic-gate if (esc) { 63*0Sstevel@tonic-gate switch (c) { 64*0Sstevel@tonic-gate case '0': 65*0Sstevel@tonic-gate case '1': 66*0Sstevel@tonic-gate case '2': 67*0Sstevel@tonic-gate case '3': 68*0Sstevel@tonic-gate case '4': 69*0Sstevel@tonic-gate case '5': 70*0Sstevel@tonic-gate case '6': 71*0Sstevel@tonic-gate case '7': 72*0Sstevel@tonic-gate c -= '0'; 73*0Sstevel@tonic-gate p++; 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate if (*p >= '0' && *p <= '7') { 76*0Sstevel@tonic-gate c = c * 8 + *p++ - '0'; 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate if (*p >= '0' && *p <= '7') 79*0Sstevel@tonic-gate c = c * 8 + *p - '0'; 80*0Sstevel@tonic-gate else 81*0Sstevel@tonic-gate p--; 82*0Sstevel@tonic-gate } else 83*0Sstevel@tonic-gate p--; 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate *q++ = c; 86*0Sstevel@tonic-gate break; 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate case 'a': 89*0Sstevel@tonic-gate *q++ = '\a'; 90*0Sstevel@tonic-gate break; 91*0Sstevel@tonic-gate case 'b': 92*0Sstevel@tonic-gate *q++ = '\b'; 93*0Sstevel@tonic-gate break; 94*0Sstevel@tonic-gate case 'f': 95*0Sstevel@tonic-gate *q++ = '\f'; 96*0Sstevel@tonic-gate break; 97*0Sstevel@tonic-gate case 'n': 98*0Sstevel@tonic-gate *q++ = '\n'; 99*0Sstevel@tonic-gate break; 100*0Sstevel@tonic-gate case 'r': 101*0Sstevel@tonic-gate *q++ = '\r'; 102*0Sstevel@tonic-gate break; 103*0Sstevel@tonic-gate case 't': 104*0Sstevel@tonic-gate *q++ = '\t'; 105*0Sstevel@tonic-gate break; 106*0Sstevel@tonic-gate case 'v': 107*0Sstevel@tonic-gate *q++ = '\v'; 108*0Sstevel@tonic-gate break; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate case 'x': 111*0Sstevel@tonic-gate for (x = 0; (c = *++p) != '\0'; ) { 112*0Sstevel@tonic-gate if (c >= '0' && c <= '9') 113*0Sstevel@tonic-gate x = x * 16 + c - '0'; 114*0Sstevel@tonic-gate else if (c >= 'a' && c <= 'f') 115*0Sstevel@tonic-gate x = x * 16 + c - 'a' + 10; 116*0Sstevel@tonic-gate else if (c >= 'A' && c <= 'F') 117*0Sstevel@tonic-gate x = x * 16 + c - 'A' + 10; 118*0Sstevel@tonic-gate else 119*0Sstevel@tonic-gate break; 120*0Sstevel@tonic-gate } 121*0Sstevel@tonic-gate *q++ = (char)x; 122*0Sstevel@tonic-gate p--; 123*0Sstevel@tonic-gate break; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate case '"': 126*0Sstevel@tonic-gate case '\\': 127*0Sstevel@tonic-gate *q++ = c; 128*0Sstevel@tonic-gate break; 129*0Sstevel@tonic-gate default: 130*0Sstevel@tonic-gate *q++ = '\\'; 131*0Sstevel@tonic-gate *q++ = c; 132*0Sstevel@tonic-gate } 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate esc = 0; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate } else { 137*0Sstevel@tonic-gate if ((esc = c == '\\') == 0) 138*0Sstevel@tonic-gate *q++ = c; 139*0Sstevel@tonic-gate } 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate *q = '\0'; 143*0Sstevel@tonic-gate return ((size_t)(q - s)); 144*0Sstevel@tonic-gate } 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate /* 147*0Sstevel@tonic-gate * Create a copy of string s in which certain unprintable or special characters 148*0Sstevel@tonic-gate * have been converted to the string representation of their C escape sequence. 149*0Sstevel@tonic-gate * For example, the newline character is expanded to the string "\n". 150*0Sstevel@tonic-gate */ 151*0Sstevel@tonic-gate char * 152*0Sstevel@tonic-gate strchr2esc(const char *s, size_t n) 153*0Sstevel@tonic-gate { 154*0Sstevel@tonic-gate const char *p; 155*0Sstevel@tonic-gate char *q, *s2, c; 156*0Sstevel@tonic-gate size_t addl = 0; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate for (p = s; p < s + n; p++) { 159*0Sstevel@tonic-gate switch (c = *p) { 160*0Sstevel@tonic-gate case '\0': 161*0Sstevel@tonic-gate case '\a': 162*0Sstevel@tonic-gate case '\b': 163*0Sstevel@tonic-gate case '\f': 164*0Sstevel@tonic-gate case '\n': 165*0Sstevel@tonic-gate case '\r': 166*0Sstevel@tonic-gate case '\t': 167*0Sstevel@tonic-gate case '\v': 168*0Sstevel@tonic-gate case '"': 169*0Sstevel@tonic-gate case '\\': 170*0Sstevel@tonic-gate addl++; /* 1 add'l char needed to follow \ */ 171*0Sstevel@tonic-gate break; 172*0Sstevel@tonic-gate case ' ': 173*0Sstevel@tonic-gate break; 174*0Sstevel@tonic-gate default: 175*0Sstevel@tonic-gate if (c < '!' || c > '~') 176*0Sstevel@tonic-gate addl += 3; /* 3 add'l chars following \ */ 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate if ((s2 = malloc(n + addl + 1)) == NULL) 181*0Sstevel@tonic-gate return (NULL); 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate for (p = s, q = s2; p < s + n; p++) { 184*0Sstevel@tonic-gate switch (c = *p) { 185*0Sstevel@tonic-gate case '\0': 186*0Sstevel@tonic-gate *q++ = '\\'; 187*0Sstevel@tonic-gate *q++ = '0'; 188*0Sstevel@tonic-gate break; 189*0Sstevel@tonic-gate case '\a': 190*0Sstevel@tonic-gate *q++ = '\\'; 191*0Sstevel@tonic-gate *q++ = 'a'; 192*0Sstevel@tonic-gate break; 193*0Sstevel@tonic-gate case '\b': 194*0Sstevel@tonic-gate *q++ = '\\'; 195*0Sstevel@tonic-gate *q++ = 'b'; 196*0Sstevel@tonic-gate break; 197*0Sstevel@tonic-gate case '\f': 198*0Sstevel@tonic-gate *q++ = '\\'; 199*0Sstevel@tonic-gate *q++ = 'f'; 200*0Sstevel@tonic-gate break; 201*0Sstevel@tonic-gate case '\n': 202*0Sstevel@tonic-gate *q++ = '\\'; 203*0Sstevel@tonic-gate *q++ = 'n'; 204*0Sstevel@tonic-gate break; 205*0Sstevel@tonic-gate case '\r': 206*0Sstevel@tonic-gate *q++ = '\\'; 207*0Sstevel@tonic-gate *q++ = 'r'; 208*0Sstevel@tonic-gate break; 209*0Sstevel@tonic-gate case '\t': 210*0Sstevel@tonic-gate *q++ = '\\'; 211*0Sstevel@tonic-gate *q++ = 't'; 212*0Sstevel@tonic-gate break; 213*0Sstevel@tonic-gate case '\v': 214*0Sstevel@tonic-gate *q++ = '\\'; 215*0Sstevel@tonic-gate *q++ = 'v'; 216*0Sstevel@tonic-gate break; 217*0Sstevel@tonic-gate case '"': 218*0Sstevel@tonic-gate *q++ = '\\'; 219*0Sstevel@tonic-gate *q++ = '"'; 220*0Sstevel@tonic-gate break; 221*0Sstevel@tonic-gate case '\\': 222*0Sstevel@tonic-gate *q++ = '\\'; 223*0Sstevel@tonic-gate *q++ = '\\'; 224*0Sstevel@tonic-gate break; 225*0Sstevel@tonic-gate case ' ': 226*0Sstevel@tonic-gate *q++ = c; 227*0Sstevel@tonic-gate break; 228*0Sstevel@tonic-gate default: 229*0Sstevel@tonic-gate if (c < '!' || c > '~') { 230*0Sstevel@tonic-gate *q++ = '\\'; 231*0Sstevel@tonic-gate *q++ = ((c >> 6) & 3) + '0'; 232*0Sstevel@tonic-gate *q++ = ((c >> 3) & 7) + '0'; 233*0Sstevel@tonic-gate *q++ = (c & 7) + '0'; 234*0Sstevel@tonic-gate } else 235*0Sstevel@tonic-gate *q++ = c; 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate if (c == '\0') 239*0Sstevel@tonic-gate break; /* don't continue past \0 even if p < s + n */ 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate *q = '\0'; 243*0Sstevel@tonic-gate return (s2); 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate /* 247*0Sstevel@tonic-gate * Return the basename (name after final /) of the given string. We use 248*0Sstevel@tonic-gate * strbasename rather than basename to avoid conflicting with libgen.h's 249*0Sstevel@tonic-gate * non-const function prototype. 250*0Sstevel@tonic-gate */ 251*0Sstevel@tonic-gate const char * 252*0Sstevel@tonic-gate strbasename(const char *s) 253*0Sstevel@tonic-gate { 254*0Sstevel@tonic-gate const char *p = strrchr(s, '/'); 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate if (p == NULL) 257*0Sstevel@tonic-gate return (s); 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate return (++p); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate /* 263*0Sstevel@tonic-gate * This function tests a string against the regular expression used for idents 264*0Sstevel@tonic-gate * and integers in the D lexer, and should match the superset of RGX_IDENT and 265*0Sstevel@tonic-gate * RGX_INT in dt_lex.l. If an invalid character is found, the function returns 266*0Sstevel@tonic-gate * a pointer to it. Otherwise NULL is returned for a valid string. 267*0Sstevel@tonic-gate */ 268*0Sstevel@tonic-gate const char * 269*0Sstevel@tonic-gate strbadidnum(const char *s) 270*0Sstevel@tonic-gate { 271*0Sstevel@tonic-gate char *p; 272*0Sstevel@tonic-gate int c; 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate if (*s == '\0') 275*0Sstevel@tonic-gate return (s); 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate errno = 0; 278*0Sstevel@tonic-gate (void) strtoull(s, &p, 0); 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate if (errno == 0 && *p == '\0') 281*0Sstevel@tonic-gate return (NULL); /* matches RGX_INT */ 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate while ((c = *s++) != '\0') { 284*0Sstevel@tonic-gate if (isalnum(c) == 0 && c != '_' && c != '`') 285*0Sstevel@tonic-gate return (s - 1); 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate return (NULL); /* matches RGX_IDENT */ 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate /* 292*0Sstevel@tonic-gate * Determine whether the string contains a glob matching pattern or is just a 293*0Sstevel@tonic-gate * simple string. See gmatch(3GEN) and sh(1) for the glob syntax definition. 294*0Sstevel@tonic-gate */ 295*0Sstevel@tonic-gate int 296*0Sstevel@tonic-gate strisglob(const char *s) 297*0Sstevel@tonic-gate { 298*0Sstevel@tonic-gate char c; 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate while ((c = *s++) != '\0') { 301*0Sstevel@tonic-gate if (c == '[' || c == '?' || c == '*' || c == '\\') 302*0Sstevel@tonic-gate return (1); 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate return (0); 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate /* 309*0Sstevel@tonic-gate * Hyphenate a string in-place by converting any instances of "__" to "-", 310*0Sstevel@tonic-gate * which we use for probe names to improve readability, and return the string. 311*0Sstevel@tonic-gate */ 312*0Sstevel@tonic-gate char * 313*0Sstevel@tonic-gate strhyphenate(char *s) 314*0Sstevel@tonic-gate { 315*0Sstevel@tonic-gate char *p, *q; 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate for (p = s, q = p + strlen(p); p < q; p++) { 318*0Sstevel@tonic-gate if (p[0] == '_' && p[1] == '_') { 319*0Sstevel@tonic-gate p[0] = '-'; 320*0Sstevel@tonic-gate bcopy(p + 2, p + 1, (size_t)(q - p) - 1); 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate return (s); 325*0Sstevel@tonic-gate } 326