perf tools: Fix _GNU_SOURCE macro related strndup() build error
[linux-2.6.git] / tools / perf / util / string.c
1 #include "string.h"
2 #include "util.h"
3
4 static int hex(char ch)
5 {
6         if ((ch >= '0') && (ch <= '9'))
7                 return ch - '0';
8         if ((ch >= 'a') && (ch <= 'f'))
9                 return ch - 'a' + 10;
10         if ((ch >= 'A') && (ch <= 'F'))
11                 return ch - 'A' + 10;
12         return -1;
13 }
14
15 /*
16  * While we find nice hex chars, build a long_val.
17  * Return number of chars processed.
18  */
19 int hex2u64(const char *ptr, u64 *long_val)
20 {
21         const char *p = ptr;
22         *long_val = 0;
23
24         while (*p) {
25                 const int hex_val = hex(*p);
26
27                 if (hex_val < 0)
28                         break;
29
30                 *long_val = (*long_val << 4) | hex_val;
31                 p++;
32         }
33
34         return p - ptr;
35 }
36
37 char *strxfrchar(char *s, char from, char to)
38 {
39         char *p = s;
40
41         while ((p = strchr(p, from)) != NULL)
42                 *p++ = to;
43
44         return s;
45 }
46
47 #define K 1024LL
48 /*
49  * perf_atoll()
50  * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
51  * and return its numeric value
52  */
53 s64 perf_atoll(const char *str)
54 {
55         unsigned int i;
56         s64 length = -1, unit = 1;
57
58         if (!isdigit(str[0]))
59                 goto out_err;
60
61         for (i = 1; i < strlen(str); i++) {
62                 switch (str[i]) {
63                 case 'B':
64                 case 'b':
65                         break;
66                 case 'K':
67                         if (str[i + 1] != 'B')
68                                 goto out_err;
69                         else
70                                 goto kilo;
71                 case 'k':
72                         if (str[i + 1] != 'b')
73                                 goto out_err;
74 kilo:
75                         unit = K;
76                         break;
77                 case 'M':
78                         if (str[i + 1] != 'B')
79                                 goto out_err;
80                         else
81                                 goto mega;
82                 case 'm':
83                         if (str[i + 1] != 'b')
84                                 goto out_err;
85 mega:
86                         unit = K * K;
87                         break;
88                 case 'G':
89                         if (str[i + 1] != 'B')
90                                 goto out_err;
91                         else
92                                 goto giga;
93                 case 'g':
94                         if (str[i + 1] != 'b')
95                                 goto out_err;
96 giga:
97                         unit = K * K * K;
98                         break;
99                 case 'T':
100                         if (str[i + 1] != 'B')
101                                 goto out_err;
102                         else
103                                 goto tera;
104                 case 't':
105                         if (str[i + 1] != 'b')
106                                 goto out_err;
107 tera:
108                         unit = K * K * K * K;
109                         break;
110                 case '\0':      /* only specified figures */
111                         unit = 1;
112                         break;
113                 default:
114                         if (!isdigit(str[i]))
115                                 goto out_err;
116                         break;
117                 }
118         }
119
120         length = atoll(str) * unit;
121         goto out;
122
123 out_err:
124         length = -1;
125 out:
126         return length;
127 }
128
129 /*
130  * Helper function for splitting a string into an argv-like array.
131  * originaly copied from lib/argv_split.c
132  */
133 static const char *skip_sep(const char *cp)
134 {
135         while (*cp && isspace(*cp))
136                 cp++;
137
138         return cp;
139 }
140
141 static const char *skip_arg(const char *cp)
142 {
143         while (*cp && !isspace(*cp))
144                 cp++;
145
146         return cp;
147 }
148
149 static int count_argc(const char *str)
150 {
151         int count = 0;
152
153         while (*str) {
154                 str = skip_sep(str);
155                 if (*str) {
156                         count++;
157                         str = skip_arg(str);
158                 }
159         }
160
161         return count;
162 }
163
164 /**
165  * argv_free - free an argv
166  * @argv - the argument vector to be freed
167  *
168  * Frees an argv and the strings it points to.
169  */
170 void argv_free(char **argv)
171 {
172         char **p;
173         for (p = argv; *p; p++)
174                 free(*p);
175
176         free(argv);
177 }
178
179 /**
180  * argv_split - split a string at whitespace, returning an argv
181  * @str: the string to be split
182  * @argcp: returned argument count
183  *
184  * Returns an array of pointers to strings which are split out from
185  * @str.  This is performed by strictly splitting on white-space; no
186  * quote processing is performed.  Multiple whitespace characters are
187  * considered to be a single argument separator.  The returned array
188  * is always NULL-terminated.  Returns NULL on memory allocation
189  * failure.
190  */
191 char **argv_split(const char *str, int *argcp)
192 {
193         int argc = count_argc(str);
194         char **argv = zalloc(sizeof(*argv) * (argc+1));
195         char **argvp;
196
197         if (argv == NULL)
198                 goto out;
199
200         if (argcp)
201                 *argcp = argc;
202
203         argvp = argv;
204
205         while (*str) {
206                 str = skip_sep(str);
207
208                 if (*str) {
209                         const char *p = str;
210                         char *t;
211
212                         str = skip_arg(str);
213
214                         t = strndup(p, str-p);
215                         if (t == NULL)
216                                 goto fail;
217                         *argvp++ = t;
218                 }
219         }
220         *argvp = NULL;
221
222 out:
223         return argv;
224
225 fail:
226         argv_free(argv);
227         return NULL;
228 }