dt_string.c revision 210767
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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26#include <strings.h>
27#include <stdlib.h>
28#include <errno.h>
29#include <ctype.h>
30
31#include <dt_string.h>
32#include <dt_impl.h>
33
34/*
35 * Create a copy of string s, but only duplicate the first n bytes.
36 */
37char *
38strndup(const char *s, size_t n)
39{
40	char *s2 = malloc(n + 1);
41
42	if (s2 == NULL)
43		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
44
45	(void) strncpy(s2, s, n);
46	s2[n] = '\0';
47	return (s2);
48}
49
50/*
51 * Transform string s inline, converting each embedded C escape sequence string
52 * to the corresponding character.  For example, the substring "\n" is replaced
53 * by an inline '\n' character.  The length of the resulting string is returned.
54 */
55size_t
56stresc2chr(char *s)
57{
58	char *p, *q, c;
59	int esc = 0;
60	int x;
61
62	for (p = q = s; (c = *p) != '\0'; p++) {
63		if (esc) {
64			switch (c) {
65			case '0':
66			case '1':
67			case '2':
68			case '3':
69			case '4':
70			case '5':
71			case '6':
72			case '7':
73				c -= '0';
74				p++;
75
76				if (*p >= '0' && *p <= '7') {
77					c = c * 8 + *p++ - '0';
78
79					if (*p >= '0' && *p <= '7')
80						c = c * 8 + *p - '0';
81					else
82						p--;
83				} else
84					p--;
85
86				*q++ = c;
87				break;
88
89			case 'a':
90				*q++ = '\a';
91				break;
92			case 'b':
93				*q++ = '\b';
94				break;
95			case 'f':
96				*q++ = '\f';
97				break;
98			case 'n':
99				*q++ = '\n';
100				break;
101			case 'r':
102				*q++ = '\r';
103				break;
104			case 't':
105				*q++ = '\t';
106				break;
107			case 'v':
108				*q++ = '\v';
109				break;
110
111			case 'x':
112				for (x = 0; (c = *++p) != '\0'; ) {
113					if (c >= '0' && c <= '9')
114						x = x * 16 + c - '0';
115					else if (c >= 'a' && c <= 'f')
116						x = x * 16 + c - 'a' + 10;
117					else if (c >= 'A' && c <= 'F')
118						x = x * 16 + c - 'A' + 10;
119					else
120						break;
121				}
122				*q++ = (char)x;
123				p--;
124				break;
125
126			case '"':
127			case '\\':
128				*q++ = c;
129				break;
130			default:
131				*q++ = '\\';
132				*q++ = c;
133			}
134
135			esc = 0;
136
137		} else {
138			if ((esc = c == '\\') == 0)
139				*q++ = c;
140		}
141	}
142
143	*q = '\0';
144	return ((size_t)(q - s));
145}
146
147/*
148 * Create a copy of string s in which certain unprintable or special characters
149 * have been converted to the string representation of their C escape sequence.
150 * For example, the newline character is expanded to the string "\n".
151 */
152char *
153strchr2esc(const char *s, size_t n)
154{
155	const char *p;
156	char *q, *s2, c;
157	size_t addl = 0;
158
159	for (p = s; p < s + n; p++) {
160		switch (c = *p) {
161		case '\0':
162		case '\a':
163		case '\b':
164		case '\f':
165		case '\n':
166		case '\r':
167		case '\t':
168		case '\v':
169		case '"':
170		case '\\':
171			addl++;		/* 1 add'l char needed to follow \ */
172			break;
173		case ' ':
174			break;
175		default:
176			if (c < '!' || c > '~')
177				addl += 3; /* 3 add'l chars following \ */
178		}
179	}
180
181	if ((s2 = malloc(n + addl + 1)) == NULL)
182		return (NULL);
183
184	for (p = s, q = s2; p < s + n; p++) {
185		switch (c = *p) {
186		case '\0':
187			*q++ = '\\';
188			*q++ = '0';
189			break;
190		case '\a':
191			*q++ = '\\';
192			*q++ = 'a';
193			break;
194		case '\b':
195			*q++ = '\\';
196			*q++ = 'b';
197			break;
198		case '\f':
199			*q++ = '\\';
200			*q++ = 'f';
201			break;
202		case '\n':
203			*q++ = '\\';
204			*q++ = 'n';
205			break;
206		case '\r':
207			*q++ = '\\';
208			*q++ = 'r';
209			break;
210		case '\t':
211			*q++ = '\\';
212			*q++ = 't';
213			break;
214		case '\v':
215			*q++ = '\\';
216			*q++ = 'v';
217			break;
218		case '"':
219			*q++ = '\\';
220			*q++ = '"';
221			break;
222		case '\\':
223			*q++ = '\\';
224			*q++ = '\\';
225			break;
226		case ' ':
227			*q++ = c;
228			break;
229		default:
230			if (c < '!' || c > '~') {
231				*q++ = '\\';
232				*q++ = ((c >> 6) & 3) + '0';
233				*q++ = ((c >> 3) & 7) + '0';
234				*q++ = (c & 7) + '0';
235			} else
236				*q++ = c;
237		}
238
239		if (c == '\0')
240			break; /* don't continue past \0 even if p < s + n */
241	}
242
243	*q = '\0';
244	return (s2);
245}
246
247/*
248 * Return the basename (name after final /) of the given string.  We use
249 * strbasename rather than basename to avoid conflicting with libgen.h's
250 * non-const function prototype.
251 */
252const char *
253strbasename(const char *s)
254{
255	const char *p = strrchr(s, '/');
256
257	if (p == NULL)
258		return (s);
259
260	return (++p);
261}
262
263/*
264 * This function tests a string against the regular expression used for idents
265 * and integers in the D lexer, and should match the superset of RGX_IDENT and
266 * RGX_INT in dt_lex.l.  If an invalid character is found, the function returns
267 * a pointer to it.  Otherwise NULL is returned for a valid string.
268 */
269const char *
270strbadidnum(const char *s)
271{
272	char *p;
273	int c;
274
275	if (*s == '\0')
276		return (s);
277
278	errno = 0;
279	(void) strtoull(s, &p, 0);
280
281	if (errno == 0 && *p == '\0')
282		return (NULL); /* matches RGX_INT */
283
284	while ((c = *s++) != '\0') {
285		if (isalnum(c) == 0 && c != '_' && c != '`')
286			return (s - 1);
287	}
288
289	return (NULL); /* matches RGX_IDENT */
290}
291
292/*
293 * Determine whether the string contains a glob matching pattern or is just a
294 * simple string.  See gmatch(3GEN) and sh(1) for the glob syntax definition.
295 */
296int
297strisglob(const char *s)
298{
299	char c;
300
301	while ((c = *s++) != '\0') {
302		if (c == '[' || c == '?' || c == '*' || c == '\\')
303			return (1);
304	}
305
306	return (0);
307}
308
309/*
310 * Hyphenate a string in-place by converting any instances of "__" to "-",
311 * which we use for probe names to improve readability, and return the string.
312 */
313char *
314strhyphenate(char *s)
315{
316	char *p, *q;
317
318	for (p = s, q = p + strlen(p); p < q; p++) {
319		if (p[0] == '_' && p[1] == '_') {
320			p[0] = '-';
321			bcopy(p + 2, p + 1, (size_t)(q - p) - 1);
322		}
323	}
324
325	return (s);
326}
327