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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright 2019 Joyent, Inc. 28 * Copyright 2023 Oxide computer Company 29 */ 30 31 #include <strings.h> 32 #include <ctype.h> 33 #include <fm/libtopo.h> 34 #include <fm/topo_mod.h> 35 #include <topo_alloc.h> 36 37 char * 38 topo_hdl_strdup(topo_hdl_t *thp, const char *s) 39 { 40 char *p; 41 42 if (s != NULL) 43 p = topo_hdl_alloc(thp, strlen(s) + 1); 44 else 45 p = NULL; 46 47 if (p != NULL) 48 (void) strcpy(p, s); 49 50 return (p); 51 } 52 53 void 54 topo_hdl_strfree(topo_hdl_t *thp, char *s) 55 { 56 if (s != NULL) 57 topo_hdl_free(thp, s, strlen(s) + 1); 58 } 59 60 void 61 topo_hdl_strfreev(topo_hdl_t *thp, char **strarr, uint_t nelem) 62 { 63 for (uint_t i = 0; i < nelem; i++) 64 topo_hdl_strfree(thp, strarr[i]); 65 66 topo_hdl_free(thp, strarr, (nelem * sizeof (char *))); 67 } 68 69 char * 70 topo_mod_strdup(topo_mod_t *mod, const char *s) 71 { 72 return (topo_hdl_strdup(mod->tm_hdl, s)); 73 } 74 75 int 76 topo_hdl_vasprintf(topo_hdl_t *thp, char **str, const char *fmt, va_list ap) 77 { 78 int len, ret; 79 80 *str = NULL; 81 len = vsnprintf(NULL, 0, fmt, ap); 82 if (len < 0) { 83 return (len); 84 } 85 86 if (len == INT_MAX) { 87 return (-1); 88 } 89 len++; 90 91 *str = topo_hdl_alloc(thp, len); 92 if (*str == NULL) { 93 return (-1); 94 } 95 96 /* 97 * If an attempt to format a given string is inconsistent, then that 98 * means something is extremely wrong and we're not going to try again 99 * and leave that ultimately to the caller to deal with as it suggests 100 * they were changing something about the arguments themselves. While 101 * asprintf(3C) does loop on this, we are not as forgiving. 102 */ 103 ret = vsnprintf(*str, len, fmt, ap); 104 if (ret < 0 || ret + 1 != len) { 105 topo_hdl_free(thp, *str, len + 1); 106 *str = NULL; 107 return (-1); 108 } 109 110 return (ret); 111 } 112 113 int 114 topo_hdl_asprintf(topo_hdl_t *thp, char **str, const char *fmt, ...) 115 { 116 int ret; 117 va_list ap; 118 119 va_start(ap, fmt); 120 ret = topo_hdl_vasprintf(thp, str, fmt, ap); 121 va_end(ap); 122 return (ret); 123 } 124 125 int 126 topo_mod_vasprintf(topo_mod_t *mod, char **str, const char *fmt, va_list ap) 127 { 128 return (topo_hdl_vasprintf(mod->tm_hdl, str, fmt, ap)); 129 } 130 131 int 132 topo_mod_asprintf(topo_mod_t *mod, char **str, const char *fmt, ...) 133 { 134 int ret; 135 va_list ap; 136 137 va_start(ap, fmt); 138 ret = topo_hdl_vasprintf(mod->tm_hdl, str, fmt, ap); 139 va_end(ap); 140 return (ret); 141 } 142 143 void 144 topo_mod_strfree(topo_mod_t *mod, char *s) 145 { 146 topo_hdl_strfree(mod->tm_hdl, s); 147 } 148 149 void 150 topo_mod_strfreev(topo_mod_t *mod, char **strarr, uint_t nelem) 151 { 152 topo_hdl_strfreev(mod->tm_hdl, strarr, nelem); 153 } 154 155 const char * 156 topo_strbasename(const char *s) 157 { 158 const char *p = strrchr(s, '/'); 159 160 if (p == NULL) 161 return (s); 162 163 return (++p); 164 } 165 166 char * 167 topo_strdirname(char *s) 168 { 169 static char slash[] = "/"; 170 static char dot[] = "."; 171 char *p; 172 173 if (s == NULL || *s == '\0') 174 return (dot); 175 176 for (p = s + strlen(s); p != s && *--p == '/'; ) 177 continue; 178 179 if (p == s && *p == '/') 180 return (slash); 181 182 while (p != s) { 183 if (*--p == '/') { 184 while (*p == '/' && p != s) 185 p--; 186 *++p = '\0'; 187 return (s); 188 } 189 } 190 191 return (dot); 192 } 193 194 ulong_t 195 topo_strhash(const char *key) 196 { 197 ulong_t g, h = 0; 198 const char *p; 199 200 for (p = key; *p != '\0'; p++) { 201 h = (h << 4) + *p; 202 203 if ((g = (h & 0xf0000000)) != 0) { 204 h ^= (g >> 24); 205 h ^= g; 206 } 207 } 208 209 return (h); 210 } 211 212 /* 213 * Transform string s inline, converting each embedded C escape sequence string 214 * to the corresponding character. For example, the substring "\n" is replaced 215 * by an inline '\n' character. The length of the resulting string is returned. 216 */ 217 size_t 218 topo_stresc2chr(char *s) 219 { 220 char *p, *q, c; 221 int esc = 0; 222 int x; 223 224 for (p = q = s; (c = *p) != '\0'; p++) { 225 if (esc) { 226 switch (c) { 227 case '0': 228 case '1': 229 case '2': 230 case '3': 231 case '4': 232 case '5': 233 case '6': 234 case '7': 235 c -= '0'; 236 p++; 237 238 if (*p >= '0' && *p <= '7') { 239 c = c * 8 + *p++ - '0'; 240 241 if (*p >= '0' && *p <= '7') 242 c = c * 8 + *p - '0'; 243 else 244 p--; 245 } else 246 p--; 247 248 *q++ = c; 249 break; 250 251 case 'a': 252 *q++ = '\a'; 253 break; 254 case 'b': 255 *q++ = '\b'; 256 break; 257 case 'f': 258 *q++ = '\f'; 259 break; 260 case 'n': 261 *q++ = '\n'; 262 break; 263 case 'r': 264 *q++ = '\r'; 265 break; 266 case 't': 267 *q++ = '\t'; 268 break; 269 case 'v': 270 *q++ = '\v'; 271 break; 272 273 case 'x': 274 for (x = 0; (c = *++p) != '\0'; ) { 275 if (c >= '0' && c <= '9') 276 x = x * 16 + c - '0'; 277 else if (c >= 'a' && c <= 'f') 278 x = x * 16 + c - 'a' + 10; 279 else if (c >= 'A' && c <= 'F') 280 x = x * 16 + c - 'A' + 10; 281 else 282 break; 283 } 284 *q++ = (char)x; 285 p--; 286 break; 287 288 case '"': 289 case '\\': 290 *q++ = c; 291 break; 292 default: 293 *q++ = '\\'; 294 *q++ = c; 295 } 296 297 esc = 0; 298 299 } else { 300 if ((esc = c == '\\') == 0) 301 *q++ = c; 302 } 303 } 304 305 *q = '\0'; 306 return ((size_t)(q - s)); 307 } 308 309 int 310 topo_strmatch(const char *s, const char *p) 311 { 312 char c; 313 314 if (p == NULL) 315 return (0); 316 317 if (s == NULL) 318 s = ""; /* treat NULL string as the empty string */ 319 320 do { 321 if ((c = *p++) == '\0') 322 return (*s == '\0'); 323 324 if (c == '*') { 325 while (*p == '*') 326 p++; /* consecutive *'s can be collapsed */ 327 328 if (*p == '\0') 329 return (1); 330 331 while (*s != '\0') { 332 if (topo_strmatch(s++, p) != 0) 333 return (1); 334 } 335 336 return (0); 337 } 338 } while (c == *s++); 339 340 return (0); 341 } 342