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