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