]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - cddl/contrib/opensolaris/lib/libdtrace/common/dt_string.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.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 (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  */
37 char *
38 strndup(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  */
55 size_t
56 stresc2chr(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  */
152 char *
153 strchr2esc(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  */
252 const char *
253 strbasename(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  */
269 const char *
270 strbadidnum(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  */
296 int
297 strisglob(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  */
313 char *
314 strhyphenate(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 }