17aec1d6eScindi /*
27aec1d6eScindi  * CDDL HEADER START
37aec1d6eScindi  *
47aec1d6eScindi  * The contents of this file are subject to the terms of the
57aec1d6eScindi  * Common Development and Distribution License, Version 1.0 only
67aec1d6eScindi  * (the "License").  You may not use this file except in compliance
77aec1d6eScindi  * with the License.
87aec1d6eScindi  *
97aec1d6eScindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107aec1d6eScindi  * or http://www.opensolaris.org/os/licensing.
117aec1d6eScindi  * See the License for the specific language governing permissions
127aec1d6eScindi  * and limitations under the License.
137aec1d6eScindi  *
147aec1d6eScindi  * When distributing Covered Code, include this CDDL HEADER in each
157aec1d6eScindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167aec1d6eScindi  * If applicable, add the following below this CDDL HEADER, with the
177aec1d6eScindi  * fields enclosed by brackets "[]" replaced with your own identifying
187aec1d6eScindi  * information: Portions Copyright [yyyy] [name of copyright owner]
197aec1d6eScindi  *
207aec1d6eScindi  * CDDL HEADER END
217aec1d6eScindi  */
227aec1d6eScindi /*
237aec1d6eScindi  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247aec1d6eScindi  * Use is subject to license terms.
257aec1d6eScindi  */
26e2336878SRob Johnston /*
27e2336878SRob Johnston  * Copyright 2019 Joyent, Inc.
28*9c994d58SRobert Mustacchi  * Copyright 2023 Oxide computer Company
29e2336878SRob Johnston  */
307aec1d6eScindi 
317aec1d6eScindi #include <strings.h>
327aec1d6eScindi #include <ctype.h>
337aec1d6eScindi #include <fm/libtopo.h>
347aec1d6eScindi #include <fm/topo_mod.h>
357aec1d6eScindi #include <topo_alloc.h>
367aec1d6eScindi 
377aec1d6eScindi char *
topo_hdl_strdup(topo_hdl_t * thp,const char * s)387aec1d6eScindi topo_hdl_strdup(topo_hdl_t *thp, const char *s)
397aec1d6eScindi {
407aec1d6eScindi 	char *p;
417aec1d6eScindi 
427aec1d6eScindi 	if (s != NULL)
437aec1d6eScindi 		p = topo_hdl_alloc(thp, strlen(s) + 1);
447aec1d6eScindi 	else
457aec1d6eScindi 		p = NULL;
467aec1d6eScindi 
477aec1d6eScindi 	if (p != NULL)
487aec1d6eScindi 		(void) strcpy(p, s);
497aec1d6eScindi 
507aec1d6eScindi 	return (p);
517aec1d6eScindi }
527aec1d6eScindi 
537aec1d6eScindi void
topo_hdl_strfree(topo_hdl_t * thp,char * s)547aec1d6eScindi topo_hdl_strfree(topo_hdl_t *thp, char *s)
557aec1d6eScindi {
567aec1d6eScindi 	if (s != NULL)
577aec1d6eScindi 		topo_hdl_free(thp, s, strlen(s) + 1);
587aec1d6eScindi }
597aec1d6eScindi 
60e2336878SRob Johnston void
topo_hdl_strfreev(topo_hdl_t * thp,char ** strarr,uint_t nelem)61e2336878SRob Johnston topo_hdl_strfreev(topo_hdl_t *thp, char **strarr, uint_t nelem)
62e2336878SRob Johnston {
63e2336878SRob Johnston 	for (uint_t i = 0; i < nelem; i++)
64e2336878SRob Johnston 		topo_hdl_strfree(thp, strarr[i]);
65e2336878SRob Johnston 
66e2336878SRob Johnston 	topo_hdl_free(thp, strarr, (nelem * sizeof (char *)));
67e2336878SRob Johnston }
68e2336878SRob Johnston 
697aec1d6eScindi char *
topo_mod_strdup(topo_mod_t * mod,const char * s)707aec1d6eScindi topo_mod_strdup(topo_mod_t *mod, const char *s)
717aec1d6eScindi {
727aec1d6eScindi 	return (topo_hdl_strdup(mod->tm_hdl, s));
737aec1d6eScindi }
747aec1d6eScindi 
75*9c994d58SRobert Mustacchi int
topo_hdl_vasprintf(topo_hdl_t * thp,char ** str,const char * fmt,va_list ap)76*9c994d58SRobert Mustacchi topo_hdl_vasprintf(topo_hdl_t *thp, char **str, const char *fmt, va_list ap)
77*9c994d58SRobert Mustacchi {
78*9c994d58SRobert Mustacchi 	int len, ret;
79*9c994d58SRobert Mustacchi 
80*9c994d58SRobert Mustacchi 	*str = NULL;
81*9c994d58SRobert Mustacchi 	len = vsnprintf(NULL, 0, fmt, ap);
82*9c994d58SRobert Mustacchi 	if (len < 0) {
83*9c994d58SRobert Mustacchi 		return (len);
84*9c994d58SRobert Mustacchi 	}
85*9c994d58SRobert Mustacchi 
86*9c994d58SRobert Mustacchi 	if (len == INT_MAX) {
87*9c994d58SRobert Mustacchi 		return (-1);
88*9c994d58SRobert Mustacchi 	}
89*9c994d58SRobert Mustacchi 	len++;
90*9c994d58SRobert Mustacchi 
91*9c994d58SRobert Mustacchi 	*str = topo_hdl_alloc(thp, len);
92*9c994d58SRobert Mustacchi 	if (*str == NULL) {
93*9c994d58SRobert Mustacchi 		return (-1);
94*9c994d58SRobert Mustacchi 	}
95*9c994d58SRobert Mustacchi 
96*9c994d58SRobert Mustacchi 	/*
97*9c994d58SRobert Mustacchi 	 * If an attempt to format a given string is inconsistent, then that
98*9c994d58SRobert Mustacchi 	 * means something is extremely wrong and we're not going to try again
99*9c994d58SRobert Mustacchi 	 * and leave that ultimately to the caller to deal with as it suggests
100*9c994d58SRobert Mustacchi 	 * they were changing something about the arguments themselves. While
101*9c994d58SRobert Mustacchi 	 * asprintf(3C) does loop on this, we are not as forgiving.
102*9c994d58SRobert Mustacchi 	 */
103*9c994d58SRobert Mustacchi 	ret = vsnprintf(*str, len, fmt, ap);
104*9c994d58SRobert Mustacchi 	if (ret < 0 || ret + 1 != len) {
105*9c994d58SRobert Mustacchi 		topo_hdl_free(thp, *str, len + 1);
106*9c994d58SRobert Mustacchi 		*str = NULL;
107*9c994d58SRobert Mustacchi 		return (-1);
108*9c994d58SRobert Mustacchi 	}
109*9c994d58SRobert Mustacchi 
110*9c994d58SRobert Mustacchi 	return (ret);
111*9c994d58SRobert Mustacchi }
112*9c994d58SRobert Mustacchi 
113*9c994d58SRobert Mustacchi int
topo_hdl_asprintf(topo_hdl_t * thp,char ** str,const char * fmt,...)114*9c994d58SRobert Mustacchi topo_hdl_asprintf(topo_hdl_t *thp, char **str, const char *fmt, ...)
115*9c994d58SRobert Mustacchi {
116*9c994d58SRobert Mustacchi 	int ret;
117*9c994d58SRobert Mustacchi 	va_list ap;
118*9c994d58SRobert Mustacchi 
119*9c994d58SRobert Mustacchi 	va_start(ap, fmt);
120*9c994d58SRobert Mustacchi 	ret = topo_hdl_vasprintf(thp, str, fmt, ap);
121*9c994d58SRobert Mustacchi 	va_end(ap);
122*9c994d58SRobert Mustacchi 	return (ret);
123*9c994d58SRobert Mustacchi }
124*9c994d58SRobert Mustacchi 
125*9c994d58SRobert Mustacchi int
topo_mod_vasprintf(topo_mod_t * mod,char ** str,const char * fmt,va_list ap)126*9c994d58SRobert Mustacchi topo_mod_vasprintf(topo_mod_t *mod, char **str, const char *fmt, va_list ap)
127*9c994d58SRobert Mustacchi {
128*9c994d58SRobert Mustacchi 	return (topo_hdl_vasprintf(mod->tm_hdl, str, fmt, ap));
129*9c994d58SRobert Mustacchi }
130*9c994d58SRobert Mustacchi 
131*9c994d58SRobert Mustacchi int
topo_mod_asprintf(topo_mod_t * mod,char ** str,const char * fmt,...)132*9c994d58SRobert Mustacchi topo_mod_asprintf(topo_mod_t *mod, char **str, const char *fmt, ...)
133*9c994d58SRobert Mustacchi {
134*9c994d58SRobert Mustacchi 	int ret;
135*9c994d58SRobert Mustacchi 	va_list ap;
136*9c994d58SRobert Mustacchi 
137*9c994d58SRobert Mustacchi 	va_start(ap, fmt);
138*9c994d58SRobert Mustacchi 	ret = topo_hdl_vasprintf(mod->tm_hdl, str, fmt, ap);
139*9c994d58SRobert Mustacchi 	va_end(ap);
140*9c994d58SRobert Mustacchi 	return (ret);
141*9c994d58SRobert Mustacchi }
142*9c994d58SRobert Mustacchi 
1437aec1d6eScindi void
topo_mod_strfree(topo_mod_t * mod,char * s)1447aec1d6eScindi topo_mod_strfree(topo_mod_t *mod, char *s)
1457aec1d6eScindi {
1467aec1d6eScindi 	topo_hdl_strfree(mod->tm_hdl, s);
1477aec1d6eScindi }
1487aec1d6eScindi 
149e2336878SRob Johnston void
topo_mod_strfreev(topo_mod_t * mod,char ** strarr,uint_t nelem)150e2336878SRob Johnston topo_mod_strfreev(topo_mod_t *mod, char **strarr, uint_t nelem)
151e2336878SRob Johnston {
152e2336878SRob Johnston 	topo_hdl_strfreev(mod->tm_hdl, strarr, nelem);
153e2336878SRob Johnston }
154e2336878SRob Johnston 
1557aec1d6eScindi const char *
topo_strbasename(const char * s)1567aec1d6eScindi topo_strbasename(const char *s)
1577aec1d6eScindi {
1587aec1d6eScindi 	const char *p = strrchr(s, '/');
1597aec1d6eScindi 
1607aec1d6eScindi 	if (p == NULL)
1617aec1d6eScindi 		return (s);
1627aec1d6eScindi 
1637aec1d6eScindi 	return (++p);
1647aec1d6eScindi }
1657aec1d6eScindi 
1667aec1d6eScindi char *
topo_strdirname(char * s)1677aec1d6eScindi topo_strdirname(char *s)
1687aec1d6eScindi {
1697aec1d6eScindi 	static char slash[] = "/";
1707aec1d6eScindi 	static char dot[] = ".";
1717aec1d6eScindi 	char *p;
1727aec1d6eScindi 
1737aec1d6eScindi 	if (s == NULL || *s == '\0')
1747aec1d6eScindi 		return (dot);
1757aec1d6eScindi 
1767aec1d6eScindi 	for (p = s + strlen(s); p != s && *--p == '/'; )
1777aec1d6eScindi 		continue;
1787aec1d6eScindi 
1797aec1d6eScindi 	if (p == s && *p == '/')
1807aec1d6eScindi 		return (slash);
1817aec1d6eScindi 
1827aec1d6eScindi 	while (p != s) {
1837aec1d6eScindi 		if (*--p == '/') {
1847aec1d6eScindi 			while (*p == '/' && p != s)
1857aec1d6eScindi 				p--;
1867aec1d6eScindi 			*++p = '\0';
1877aec1d6eScindi 			return (s);
1887aec1d6eScindi 		}
1897aec1d6eScindi 	}
1907aec1d6eScindi 
1917aec1d6eScindi 	return (dot);
1927aec1d6eScindi }
1937aec1d6eScindi 
1947aec1d6eScindi ulong_t
topo_strhash(const char * key)1957aec1d6eScindi topo_strhash(const char *key)
1967aec1d6eScindi {
1977aec1d6eScindi 	ulong_t g, h = 0;
1987aec1d6eScindi 	const char *p;
1997aec1d6eScindi 
2007aec1d6eScindi 	for (p = key; *p != '\0'; p++) {
2017aec1d6eScindi 		h = (h << 4) + *p;
2027aec1d6eScindi 
2037aec1d6eScindi 		if ((g = (h & 0xf0000000)) != 0) {
2047aec1d6eScindi 			h ^= (g >> 24);
2057aec1d6eScindi 			h ^= g;
2067aec1d6eScindi 		}
2077aec1d6eScindi 	}
2087aec1d6eScindi 
2097aec1d6eScindi 	return (h);
2107aec1d6eScindi }
2117aec1d6eScindi 
2127aec1d6eScindi /*
2137aec1d6eScindi  * Transform string s inline, converting each embedded C escape sequence string
2147aec1d6eScindi  * to the corresponding character.  For example, the substring "\n" is replaced
2157aec1d6eScindi  * by an inline '\n' character.  The length of the resulting string is returned.
2167aec1d6eScindi  */
2177aec1d6eScindi size_t
topo_stresc2chr(char * s)2187aec1d6eScindi topo_stresc2chr(char *s)
2197aec1d6eScindi {
2207aec1d6eScindi 	char *p, *q, c;
2217aec1d6eScindi 	int esc = 0;
2227aec1d6eScindi 	int x;
2237aec1d6eScindi 
2247aec1d6eScindi 	for (p = q = s; (c = *p) != '\0'; p++) {
2257aec1d6eScindi 		if (esc) {
2267aec1d6eScindi 			switch (c) {
2277aec1d6eScindi 			case '0':
2287aec1d6eScindi 			case '1':
2297aec1d6eScindi 			case '2':
2307aec1d6eScindi 			case '3':
2317aec1d6eScindi 			case '4':
2327aec1d6eScindi 			case '5':
2337aec1d6eScindi 			case '6':
2347aec1d6eScindi 			case '7':
2357aec1d6eScindi 				c -= '0';
2367aec1d6eScindi 				p++;
2377aec1d6eScindi 
2387aec1d6eScindi 				if (*p >= '0' && *p <= '7') {
2397aec1d6eScindi 					c = c * 8 + *p++ - '0';
2407aec1d6eScindi 
2417aec1d6eScindi 					if (*p >= '0' && *p <= '7')
2427aec1d6eScindi 						c = c * 8 + *p - '0';
2437aec1d6eScindi 					else
2447aec1d6eScindi 						p--;
2457aec1d6eScindi 				} else
2467aec1d6eScindi 					p--;
2477aec1d6eScindi 
2487aec1d6eScindi 				*q++ = c;
2497aec1d6eScindi 				break;
2507aec1d6eScindi 
2517aec1d6eScindi 			case 'a':
2527aec1d6eScindi 				*q++ = '\a';
2537aec1d6eScindi 				break;
2547aec1d6eScindi 			case 'b':
2557aec1d6eScindi 				*q++ = '\b';
2567aec1d6eScindi 				break;
2577aec1d6eScindi 			case 'f':
2587aec1d6eScindi 				*q++ = '\f';
2597aec1d6eScindi 				break;
2607aec1d6eScindi 			case 'n':
2617aec1d6eScindi 				*q++ = '\n';
2627aec1d6eScindi 				break;
2637aec1d6eScindi 			case 'r':
2647aec1d6eScindi 				*q++ = '\r';
2657aec1d6eScindi 				break;
2667aec1d6eScindi 			case 't':
2677aec1d6eScindi 				*q++ = '\t';
2687aec1d6eScindi 				break;
2697aec1d6eScindi 			case 'v':
2707aec1d6eScindi 				*q++ = '\v';
2717aec1d6eScindi 				break;
2727aec1d6eScindi 
2737aec1d6eScindi 			case 'x':
2747aec1d6eScindi 				for (x = 0; (c = *++p) != '\0'; ) {
2757aec1d6eScindi 					if (c >= '0' && c <= '9')
2767aec1d6eScindi 						x = x * 16 + c - '0';
2777aec1d6eScindi 					else if (c >= 'a' && c <= 'f')
2787aec1d6eScindi 						x = x * 16 + c - 'a' + 10;
2797aec1d6eScindi 					else if (c >= 'A' && c <= 'F')
2807aec1d6eScindi 						x = x * 16 + c - 'A' + 10;
2817aec1d6eScindi 					else
2827aec1d6eScindi 						break;
2837aec1d6eScindi 				}
2847aec1d6eScindi 				*q++ = (char)x;
2857aec1d6eScindi 				p--;
2867aec1d6eScindi 				break;
2877aec1d6eScindi 
2887aec1d6eScindi 			case '"':
2897aec1d6eScindi 			case '\\':
2907aec1d6eScindi 				*q++ = c;
2917aec1d6eScindi 				break;
2927aec1d6eScindi 			default:
2937aec1d6eScindi 				*q++ = '\\';
2947aec1d6eScindi 				*q++ = c;
2957aec1d6eScindi 			}
2967aec1d6eScindi 
2977aec1d6eScindi 			esc = 0;
2987aec1d6eScindi 
2997aec1d6eScindi 		} else {
3007aec1d6eScindi 			if ((esc = c == '\\') == 0)
3017aec1d6eScindi 				*q++ = c;
3027aec1d6eScindi 		}
3037aec1d6eScindi 	}
3047aec1d6eScindi 
3057aec1d6eScindi 	*q = '\0';
3067aec1d6eScindi 	return ((size_t)(q - s));
3077aec1d6eScindi }
3087aec1d6eScindi 
3097aec1d6eScindi int
topo_strmatch(const char * s,const char * p)3107aec1d6eScindi topo_strmatch(const char *s, const char *p)
3117aec1d6eScindi {
3127aec1d6eScindi 	char c;
3137aec1d6eScindi 
3147aec1d6eScindi 	if (p == NULL)
3157aec1d6eScindi 		return (0);
3167aec1d6eScindi 
3177aec1d6eScindi 	if (s == NULL)
3187aec1d6eScindi 		s = ""; /* treat NULL string as the empty string */
3197aec1d6eScindi 
3207aec1d6eScindi 	do {
3217aec1d6eScindi 		if ((c = *p++) == '\0')
3227aec1d6eScindi 			return (*s == '\0');
3237aec1d6eScindi 
3247aec1d6eScindi 		if (c == '*') {
3257aec1d6eScindi 			while (*p == '*')
3267aec1d6eScindi 				p++; /* consecutive *'s can be collapsed */
3277aec1d6eScindi 
3287aec1d6eScindi 			if (*p == '\0')
3297aec1d6eScindi 				return (1);
3307aec1d6eScindi 
3317aec1d6eScindi 			while (*s != '\0') {
3327aec1d6eScindi 				if (topo_strmatch(s++, p) != 0)
3337aec1d6eScindi 					return (1);
3347aec1d6eScindi 			}
3357aec1d6eScindi 
3367aec1d6eScindi 			return (0);
3377aec1d6eScindi 		}
3387aec1d6eScindi 	} while (c == *s++);
3397aec1d6eScindi 
3407aec1d6eScindi 	return (0);
3417aec1d6eScindi }
342