]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/ktap/userspace/util.c
Merge remote-tracking branch 'staging/staging-next'
[karo-tx-linux.git] / drivers / staging / ktap / userspace / util.c
1 /*
2  * util.c
3  *
4  * This file is part of ktap by Jovi Zhangwei.
5  *
6  * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>.
7  *
8  * Copyright (C) 1994-2013 Lua.org, PUC-Rio.
9  *  - The part of code in this file is copied from lua initially.
10  *  - lua's MIT license is compatible with GPL.
11  *
12  * ktap is free software; you can redistribute it and/or modify it
13  * under the terms and conditions of the GNU General Public License,
14  * version 2, as published by the Free Software Foundation.
15  *
16  * ktap is distributed in the hope it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19  * more details.
20  *
21  * You should have received a copy of the GNU General Public License along with
22  * this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <math.h>
31 #include "../include/ktap_types.h"
32 #include "ktapc.h"
33
34 /*
35  * converts an integer to a "floating point byte", represented as
36  * (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
37  * eeeee != 0 and (xxx) otherwise.
38  */
39 int ktapc_int2fb(unsigned int x)
40 {
41         int e = 0;  /* exponent */
42
43         if (x < 8)
44                 return x;
45         while (x >= 0x10) {
46                 x = (x+1) >> 1;
47                 e++;
48         }
49         return ((e+1) << 3) | ((int)x - 8);
50 }
51
52 /* converts back */
53 int ktapc_fb2int(int x)
54 {
55         int e = (x >> 3) & 0x1f;
56
57         if (e == 0)
58                 return x;
59         else
60                 return ((x & 7) + 8) << (e - 1);
61 }
62
63 int ktapc_ceillog2(unsigned int x)
64 {
65         static const u8 log_2[256] = {
66         0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
67         6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
68         7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
69         7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
70         8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
71         8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
72         8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
73         8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
74         };
75         int l = 0;
76
77         x--;
78         while (x >= 256) {
79                 l += 8;
80                 x >>= 8;
81         }
82         return l + log_2[x];
83 }
84
85 ktap_number ktapc_arith(int op, ktap_number v1, ktap_number v2)
86 {
87         switch (op) {
88         case KTAP_OPADD: return NUMADD(v1, v2);
89         case KTAP_OPSUB: return NUMSUB(v1, v2);
90         case KTAP_OPMUL: return NUMMUL(v1, v2);
91         case KTAP_OPDIV: return NUMDIV(v1, v2);
92         case KTAP_OPMOD: return NUMMOD(v1, v2);
93         //case KTAP_OPPOW: return NUMPOW(v1, v2);
94         case KTAP_OPUNM: return NUMUNM(v1);
95         default: ktap_assert(0); return 0;
96         }
97 }
98
99 int ktapc_hexavalue(int c)
100 {
101         if (isdigit(c))
102                 return c - '0';
103         else
104                 return tolower(c) - 'a' + 10;
105 }
106
107 static int isneg(const char **s)
108 {
109         if (**s == '-') {
110                 (*s)++;
111                 return 1;
112         } else if (**s == '+')
113                 (*s)++;
114
115         return 0;
116 }
117
118 static ktap_number readhexa(const char **s, ktap_number r, int *count)
119 {
120         for (; isxdigit((unsigned char)(**s)); (*s)++) {  /* read integer part */
121                 r = (r * 16.0) + (ktap_number)(ktapc_hexavalue((unsigned char)(**s)));
122                 (*count)++;
123         }
124
125         return r;
126 }
127
128 /*
129  * convert an hexadecimal numeric string to a number, following
130  * C99 specification for 'strtod'
131  */
132 static ktap_number strx2number(const char *s, char **endptr)
133 {
134         ktap_number r = 0.0;
135         int e = 0, i = 0;
136         int neg = 0;  /* 1 if number is negative */
137
138         *endptr = (char *)s;  /* nothing is valid yet */
139         while (isspace((unsigned char)(*s)))
140                 s++;  /* skip initial spaces */
141
142         neg = isneg(&s);  /* check signal */
143         if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')))  /* check '0x' */
144                 return 0.0;  /* invalid format (no '0x') */
145
146         s += 2;  /* skip '0x' */
147         r = readhexa(&s, r, &i);  /* read integer part */
148         if (*s == '.') {
149                 s++;  /* skip dot */
150                 r = readhexa(&s, r, &e);  /* read fractional part */
151         }
152
153         if (i == 0 && e == 0)
154                 return 0.0;  /* invalid format (no digit) */
155         e *= -4;  /* each fractional digit divides value by 2^-4 */
156         *endptr = (char *)s;  /* valid up to here */
157
158         if (*s == 'p' || *s == 'P') {  /* exponent part? */
159                 int exp1 = 0;
160                 int neg1;
161
162                 s++;  /* skip 'p' */
163                 neg1 = isneg(&s);  /* signal */
164                 if (!isdigit((unsigned char)(*s)))
165                         goto ret;  /* must have at least one digit */
166                 while (isdigit((unsigned char)(*s)))  /* read exponent */
167                         exp1 = exp1 * 10 + *(s++) - '0';
168                 if (neg1) exp1 = -exp1;
169                         e += exp1;
170         }
171
172         *endptr = (char *)s;  /* valid up to here */
173  ret:
174         if (neg)
175                 r = -r;
176
177         return ldexp(r, e);
178 }
179
180 int ktapc_str2d(const char *s, size_t len, ktap_number *result)
181 {
182         char *endptr;
183
184         if (strpbrk(s, "nN"))  /* reject 'inf' and 'nan' */
185                 return 0;
186         else if (strpbrk(s, "xX"))  /* hexa? */
187                 *result = strx2number(s, &endptr);
188         else
189                 *result = strtod(s, &endptr);
190
191         if (endptr == s)
192                 return 0;  /* nothing recognized */
193         while (isspace((unsigned char)(*endptr)))
194                 endptr++;
195         return (endptr == s + len);  /* OK if no trailing characters */
196 }
197
198 /* number of chars of a literal string without the ending \0 */
199 #define LL(x)   (sizeof(x)/sizeof(char) - 1)
200
201 #define RETS    "..."
202 #define PRE     "[string \""
203 #define POS     "\"]"
204
205 #define addstr(a,b,l)   ( memcpy(a,b,(l) * sizeof(char)), a += (l) )
206
207 void ktapc_chunkid(char *out, const char *source, size_t bufflen)
208 {
209         size_t l = strlen(source);
210
211         if (*source == '=') {  /* 'literal' source */
212                 if (l <= bufflen)  /* small enough? */
213                         memcpy(out, source + 1, l * sizeof(char));
214                 else {  /* truncate it */
215                         addstr(out, source + 1, bufflen - 1);
216                         *out = '\0';
217                 }
218         } else if (*source == '@') {  /* file name */
219                 if (l <= bufflen)  /* small enough? */
220                         memcpy(out, source + 1, l * sizeof(char));
221                 else {  /* add '...' before rest of name */
222                         addstr(out, RETS, LL(RETS));
223                         bufflen -= LL(RETS);
224                         memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char));
225                 }
226         } else {  /* string; format as [string "source"] */
227                 const char *nl = strchr(source, '\n');  /* find first new line (if any) */
228                 addstr(out, PRE, LL(PRE));  /* add prefix */
229                 bufflen -= LL(PRE RETS POS) + 1;  /* save space for prefix+suffix+'\0' */
230                 if (l < bufflen && nl == NULL) {  /* small one-line source? */
231                         addstr(out, source, l);  /* keep it */
232                 } else {
233                         if (nl != NULL)
234                                 l = nl - source;  /* stop at first newline */
235                         if (l > bufflen)
236                                 l = bufflen;
237                         addstr(out, source, l);
238                         addstr(out, RETS, LL(RETS));
239                 }
240                 memcpy(out, POS, (LL(POS) + 1) * sizeof(char));
241         }
242 }
243
244
245 /*
246  * strglobmatch is copyed from perf(linux/tools/perf/util/string.c)
247  */
248
249 /* Character class matching */
250 static bool __match_charclass(const char *pat, char c, const char **npat)
251 {
252         bool complement = false, ret = true;
253
254         if (*pat == '!') {
255                 complement = true;
256                 pat++;
257         }
258         if (*pat++ == c)        /* First character is special */
259                 goto end;
260
261         while (*pat && *pat != ']') {   /* Matching */
262                 if (*pat == '-' && *(pat + 1) != ']') { /* Range */
263                         if (*(pat - 1) <= c && c <= *(pat + 1))
264                                 goto end;
265                         if (*(pat - 1) > *(pat + 1))
266                                 goto error;
267                         pat += 2;
268                 } else if (*pat++ == c)
269                         goto end;
270         }
271         if (!*pat)
272                 goto error;
273         ret = false;
274
275 end:
276         while (*pat && *pat != ']')     /* Searching closing */
277                 pat++;
278         if (!*pat)
279                 goto error;
280         *npat = pat + 1;
281         return complement ? !ret : ret;
282
283 error:
284         return false;
285 }
286
287 /* Glob/lazy pattern matching */
288 static bool __match_glob(const char *str, const char *pat, bool ignore_space)
289 {
290         while (*str && *pat && *pat != '*') {
291                 if (ignore_space) {
292                         /* Ignore spaces for lazy matching */
293                         if (isspace(*str)) {
294                                 str++;
295                                 continue;
296                         }
297                         if (isspace(*pat)) {
298                                 pat++;
299                                 continue;
300                         }
301                 }
302                 if (*pat == '?') {      /* Matches any single character */
303                         str++;
304                         pat++;
305                         continue;
306                 } else if (*pat == '[') /* Character classes/Ranges */
307                         if (__match_charclass(pat + 1, *str, &pat)) {
308                                 str++;
309                                 continue;
310                         } else
311                                 return false;
312                 else if (*pat == '\\') /* Escaped char match as normal char */
313                         pat++;
314                 if (*str++ != *pat++)
315                         return false;
316         }
317         /* Check wild card */
318         if (*pat == '*') {
319                 while (*pat == '*')
320                         pat++;
321                 if (!*pat)      /* Tail wild card matches all */
322                         return true;
323                 while (*str)
324                         if (__match_glob(str++, pat, ignore_space))
325                                 return true;
326         }
327         return !*str && !*pat;
328 }
329
330 /**
331  * strglobmatch - glob expression pattern matching
332  * @str: the target string to match
333  * @pat: the pattern string to match
334  *
335  * This returns true if the @str matches @pat. @pat can includes wildcards
336  * ('*','?') and character classes ([CHARS], complementation and ranges are
337  * also supported). Also, this supports escape character ('\') to use special
338  * characters as normal character.
339  *
340  * Note: if @pat syntax is broken, this always returns false.
341  */
342 bool strglobmatch(const char *str, const char *pat)
343 {
344         return __match_glob(str, pat, false);
345 }
346