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 (c) 2013, Joyent, Inc. All rights reserved.
28 */
29
30 #include <strings.h>
31 #include <ctype.h>
32 #include <fm/libtopo.h>
33 #include <fm/topo_mod.h>
34 #include <topo_alloc.h>
35
36 char *
37 topo_hdl_strdup(topo_hdl_t *thp, const char *s)
38 {
39 char *p;
40
41 if (s != NULL)
42 p = topo_hdl_alloc(thp, strlen(s) + 1);
43 else
44 p = NULL;
45
46 if (p != NULL)
47 (void) strcpy(p, s);
48
49 return (p);
50 }
51
52 void
53 topo_hdl_strfree(topo_hdl_t *thp, char *s)
54 {
55 if (s != NULL)
56 topo_hdl_free(thp, s, strlen(s) + 1);
57 }
58
59 char *
60 topo_hdl_strsplit(topo_hdl_t *hdl, const char *input, const char *sep,
61 char **lastp)
62 {
63 size_t seplen = strlen(sep);
64 const char *scanstart;
65 char *token;
66 char *ret;
67
68 if (input != NULL) {
69 /*
70 * Start scanning at beginning of input:
71 */
72 scanstart = input;
73 } else if (*lastp == NULL) {
74 /*
75 * If we have already finished scanning, return NULL.
76 */
77 return (NULL);
78 } else {
79 /*
80 * Otherwise, start scanning where we left off:
81 */
82 scanstart = *lastp;
83 }
84
85 token = strstr(scanstart, sep);
86 if (token != NULL) {
87 /*
88 * We still have a separator, so advance the next-start
89 * pointer past it:
90 */
91 *lastp = token + seplen;
92 /*
93 * Copy out this element. The buffer must fit the string
94 * exactly, so that topo_hdl_strfree() can determine its
95 * size with strlen().
96 */
97 ret = topo_hdl_alloc(hdl, token - scanstart + 1);
98 (void) strncpy(ret, scanstart, token - scanstart);
99 ret[token - scanstart] = '\0';
100 } else {
101 /*
102 * We have no separator, so this is the last element:
103 */
104 *lastp = NULL;
105 ret = topo_hdl_strdup(hdl, scanstart);
106 }
107
108 return (ret);
109 }
110
111 char *
112 topo_mod_strdup(topo_mod_t *mod, const char *s)
113 {
114 return (topo_hdl_strdup(mod->tm_hdl, s));
115 }
116
117 void
118 topo_mod_strfree(topo_mod_t *mod, char *s)
119 {
120 topo_hdl_strfree(mod->tm_hdl, s);
121 }
122
123 char *
124 topo_mod_strsplit(topo_mod_t *mod, const char *input, const char *sep,
125 char **lastp)
126 {
127 return (topo_hdl_strsplit(mod->tm_hdl, input, sep, lastp));
128 }
129
130 const char *
131 topo_strbasename(const char *s)
132 {
133 const char *p = strrchr(s, '/');
134
135 if (p == NULL)
136 return (s);
137
138 return (++p);
139 }
140
141 char *
142 topo_strdirname(char *s)
143 {
144 static char slash[] = "/";
145 static char dot[] = ".";
146 char *p;
147
148 if (s == NULL || *s == '\0')
149 return (dot);
150
151 for (p = s + strlen(s); p != s && *--p == '/'; )
152 continue;
153
154 if (p == s && *p == '/')
155 return (slash);
156
157 while (p != s) {
158 if (*--p == '/') {
159 while (*p == '/' && p != s)
160 p--;
161 *++p = '\0';
162 return (s);
163 }
164 }
165
166 return (dot);
167 }
168
169 ulong_t
170 topo_strhash(const char *key)
171 {
172 ulong_t g, h = 0;
173 const char *p;
174
175 for (p = key; *p != '\0'; p++) {
176 h = (h << 4) + *p;
177
178 if ((g = (h & 0xf0000000)) != 0) {
179 h ^= (g >> 24);
180 h ^= g;
181 }
182 }
183
184 return (h);
185 }
186
187 /*
188 * Transform string s inline, converting each embedded C escape sequence string
189 * to the corresponding character. For example, the substring "\n" is replaced
190 * by an inline '\n' character. The length of the resulting string is returned.
191 */
192 size_t
193 topo_stresc2chr(char *s)
194 {
195 char *p, *q, c;
196 int esc = 0;
197 int x;
198
199 for (p = q = s; (c = *p) != '\0'; p++) {
200 if (esc) {
201 switch (c) {
202 case '0':
203 case '1':
204 case '2':
205 case '3':
206 case '4':
207 case '5':
208 case '6':
209 case '7':
210 c -= '0';
211 p++;
212
213 if (*p >= '0' && *p <= '7') {
214 c = c * 8 + *p++ - '0';
215
216 if (*p >= '0' && *p <= '7')
217 c = c * 8 + *p - '0';
218 else
219 p--;
220 } else
221 p--;
222
223 *q++ = c;
224 break;
225
226 case 'a':
227 *q++ = '\a';
228 break;
229 case 'b':
230 *q++ = '\b';
231 break;
232 case 'f':
233 *q++ = '\f';
234 break;
235 case 'n':
236 *q++ = '\n';
237 break;
238 case 'r':
239 *q++ = '\r';
240 break;
241 case 't':
242 *q++ = '\t';
243 break;
244 case 'v':
245 *q++ = '\v';
246 break;
247
248 case 'x':
249 for (x = 0; (c = *++p) != '\0'; ) {
250 if (c >= '0' && c <= '9')
251 x = x * 16 + c - '0';
252 else if (c >= 'a' && c <= 'f')
253 x = x * 16 + c - 'a' + 10;
254 else if (c >= 'A' && c <= 'F')
255 x = x * 16 + c - 'A' + 10;
256 else
257 break;
258 }
259 *q++ = (char)x;
260 p--;
261 break;
262
263 case '"':
264 case '\\':
265 *q++ = c;
266 break;
267 default:
268 *q++ = '\\';
269 *q++ = c;
270 }
271
272 esc = 0;
273
274 } else {
275 if ((esc = c == '\\') == 0)
276 *q++ = c;
277 }
278 }
279
280 *q = '\0';
281 return ((size_t)(q - s));
282 }
283
284 int
285 topo_strmatch(const char *s, const char *p)
286 {
287 char c;
288
289 if (p == NULL)
290 return (0);
291
292 if (s == NULL)
293 s = ""; /* treat NULL string as the empty string */
294
295 do {
296 if ((c = *p++) == '\0')
297 return (*s == '\0');
298
299 if (c == '*') {
300 while (*p == '*')
301 p++; /* consecutive *'s can be collapsed */
302
303 if (*p == '\0')
304 return (1);
305
306 while (*s != '\0') {
307 if (topo_strmatch(s++, p) != 0)
308 return (1);
309 }
310
311 return (0);
312 }
313 } while (c == *s++);
314
315 return (0);
316 }