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