xref: /illumos-gate/usr/src/cmd/fm/fmd/common/fmd_string.c (revision 7a6d80f1660abd4755c68cbd094d4a914681d26e)
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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <strings.h>
28 #include <ctype.h>
29 
30 #include <fmd_string.h>
31 
32 char *
33 fmd_strdup(const char *s, int flags)
34 {
35 	char *p;
36 
37 	if (s != NULL)
38 		p = fmd_alloc(strlen(s) + 1, flags);
39 	else
40 		p = NULL;
41 
42 	if (p != NULL)
43 		(void) strcpy(p, s);
44 
45 	return (p);
46 }
47 
48 void
49 fmd_strfree(char *s)
50 {
51 	if (s != NULL)
52 		fmd_free(s, strlen(s) + 1);
53 }
54 
55 const char *
56 fmd_strbasename(const char *s)
57 {
58 	const char *p = strrchr(s, '/');
59 
60 	if (p == NULL)
61 		return (s);
62 
63 	return (++p);
64 }
65 
66 char *
67 fmd_strdirname(char *s)
68 {
69 	static char slash[] = "/";
70 	static char dot[] = ".";
71 	char *p;
72 
73 	if (s == NULL || *s == '\0')
74 		return (dot);
75 
76 	for (p = s + strlen(s); p != s && *--p == '/'; )
77 		continue;
78 
79 	if (p == s && *p == '/')
80 		return (slash);
81 
82 	while (p != s) {
83 		if (*--p == '/') {
84 			while (*p == '/' && p != s)
85 				p--;
86 			*++p = '\0';
87 			return (s);
88 		}
89 	}
90 
91 	return (dot);
92 }
93 
94 ulong_t
95 fmd_strhash(const char *key)
96 {
97 	ulong_t g, h = 0;
98 	const char *p;
99 
100 	for (p = key; *p != '\0'; p++) {
101 		h = (h << 4) + *p;
102 
103 		if ((g = (h & 0xf0000000)) != 0) {
104 			h ^= (g >> 24);
105 			h ^= g;
106 		}
107 	}
108 
109 	return (h);
110 }
111 
112 /*
113  * Transform string s inline, converting each embedded C escape sequence string
114  * to the corresponding character.  For example, the substring "\n" is replaced
115  * by an inline '\n' character.  The length of the resulting string is returned.
116  */
117 size_t
118 fmd_stresc2chr(char *s)
119 {
120 	char *p, *q, c;
121 	int esc = 0;
122 	int x;
123 
124 	for (p = q = s; (c = *p) != '\0'; p++) {
125 		if (esc) {
126 			switch (c) {
127 			case '0':
128 			case '1':
129 			case '2':
130 			case '3':
131 			case '4':
132 			case '5':
133 			case '6':
134 			case '7':
135 				c -= '0';
136 				p++;
137 
138 				if (*p >= '0' && *p <= '7') {
139 					c = c * 8 + *p++ - '0';
140 
141 					if (*p >= '0' && *p <= '7')
142 						c = c * 8 + *p - '0';
143 					else
144 						p--;
145 				} else
146 					p--;
147 
148 				*q++ = c;
149 				break;
150 
151 			case 'a':
152 				*q++ = '\a';
153 				break;
154 			case 'b':
155 				*q++ = '\b';
156 				break;
157 			case 'f':
158 				*q++ = '\f';
159 				break;
160 			case 'n':
161 				*q++ = '\n';
162 				break;
163 			case 'r':
164 				*q++ = '\r';
165 				break;
166 			case 't':
167 				*q++ = '\t';
168 				break;
169 			case 'v':
170 				*q++ = '\v';
171 				break;
172 
173 			case 'x':
174 				for (x = 0; (c = *++p) != '\0'; ) {
175 					if (c >= '0' && c <= '9')
176 						x = x * 16 + c - '0';
177 					else if (c >= 'a' && c <= 'f')
178 						x = x * 16 + c - 'a' + 10;
179 					else if (c >= 'A' && c <= 'F')
180 						x = x * 16 + c - 'A' + 10;
181 					else
182 						break;
183 				}
184 				*q++ = (char)x;
185 				p--;
186 				break;
187 
188 			case '"':
189 			case '\\':
190 				*q++ = c;
191 				break;
192 			default:
193 				*q++ = '\\';
194 				*q++ = c;
195 			}
196 
197 			esc = 0;
198 
199 		} else {
200 			if ((esc = c == '\\') == 0)
201 				*q++ = c;
202 		}
203 	}
204 
205 	*q = '\0';
206 	return ((size_t)(q - s));
207 }
208 
209 /*
210  * We require that identifiers for buffers, statistics, and properties conform
211  * to the regular expression [a-zA-Z0-9\-_.].  If check_prefixes is set, we
212  * also flag strings that begin with a set of prefixes reserved for use by fmd.
213  */
214 const char *
215 fmd_strbadid(const char *s, int check_prefixes)
216 {
217 	const char *s0 = s;
218 	int c = *s++;
219 
220 	while ((c = *s++) != '\0') {
221 		if (!isupper(c) && !islower(c) &&
222 		    !isdigit(c) && c != '-' && c != '_' && c != '.')
223 			return (s - 1);
224 	}
225 
226 	if (check_prefixes && (s0[0] == '_' || s0[0] == '.' ||
227 	    strncmp(s0, "fmd_", 4) == 0 || strncmp(s0, "FMD_", 4) == 0 ||
228 	    strncmp(s0, "fmd.", 4) == 0 || strncmp(s0, "FMD.", 4) == 0))
229 		return (s0);
230 
231 	return (NULL);
232 }
233 
234 int
235 fmd_strmatch(const char *s, const char *p)
236 {
237 	char c;
238 
239 	if (p == NULL)
240 		return (0);
241 
242 	if (s == NULL)
243 		s = ""; /* treat NULL string as the empty string */
244 
245 	do {
246 		if ((c = *p++) == '\0')
247 			return (*s == '\0');
248 
249 		if (c == '*') {
250 			while (*p == '*')
251 				p++; /* consecutive *'s can be collapsed */
252 
253 			if (*p == '\0')
254 				return (1);
255 
256 			while (*s != '\0') {
257 				if (fmd_strmatch(s++, p) != 0)
258 					return (1);
259 			}
260 
261 			return (0);
262 		}
263 	} while (c == *s++);
264 
265 	return (0);
266 }
267