Merge tag 'sunxi-fixes-for-4.3' of https://git.kernel.org/pub/scm/linux/kernel/git...
[linux-drm-fsl-dcu.git] / lib / string_helpers.c
1 /*
2  * Helpers for formatting and printing strings
3  *
4  * Copyright 31 August 2008 James Bottomley
5  * Copyright (C) 2013, Intel Corporation
6  */
7 #include <linux/bug.h>
8 #include <linux/kernel.h>
9 #include <linux/math64.h>
10 #include <linux/export.h>
11 #include <linux/ctype.h>
12 #include <linux/errno.h>
13 #include <linux/string.h>
14 #include <linux/string_helpers.h>
15
16 /**
17  * string_get_size - get the size in the specified units
18  * @size:       The size to be converted in blocks
19  * @blk_size:   Size of the block (use 1 for size in bytes)
20  * @units:      units to use (powers of 1000 or 1024)
21  * @buf:        buffer to format to
22  * @len:        length of buffer
23  *
24  * This function returns a string formatted to 3 significant figures
25  * giving the size in the required units.  @buf should have room for
26  * at least 9 bytes and will always be zero terminated.
27  *
28  */
29 void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
30                      char *buf, int len)
31 {
32         static const char *const units_10[] = {
33                 "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
34         };
35         static const char *const units_2[] = {
36                 "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"
37         };
38         static const char *const *const units_str[] = {
39                 [STRING_UNITS_10] = units_10,
40                 [STRING_UNITS_2] = units_2,
41         };
42         static const unsigned int divisor[] = {
43                 [STRING_UNITS_10] = 1000,
44                 [STRING_UNITS_2] = 1024,
45         };
46         int i, j;
47         u32 remainder = 0, sf_cap, exp;
48         char tmp[8];
49         const char *unit;
50
51         tmp[0] = '\0';
52         i = 0;
53         if (!size)
54                 goto out;
55
56         while (blk_size >= divisor[units]) {
57                 remainder = do_div(blk_size, divisor[units]);
58                 i++;
59         }
60
61         exp = divisor[units] / (u32)blk_size;
62         /*
63          * size must be strictly greater than exp here to ensure that remainder
64          * is greater than divisor[units] coming out of the if below.
65          */
66         if (size > exp) {
67                 remainder = do_div(size, divisor[units]);
68                 remainder *= blk_size;
69                 i++;
70         } else {
71                 remainder *= size;
72         }
73
74         size *= blk_size;
75         size += remainder / divisor[units];
76         remainder %= divisor[units];
77
78         while (size >= divisor[units]) {
79                 remainder = do_div(size, divisor[units]);
80                 i++;
81         }
82
83         sf_cap = size;
84         for (j = 0; sf_cap*10 < 1000; j++)
85                 sf_cap *= 10;
86
87         if (j) {
88                 remainder *= 1000;
89                 remainder /= divisor[units];
90                 snprintf(tmp, sizeof(tmp), ".%03u", remainder);
91                 tmp[j+1] = '\0';
92         }
93
94  out:
95         if (i >= ARRAY_SIZE(units_2))
96                 unit = "UNK";
97         else
98                 unit = units_str[units][i];
99
100         snprintf(buf, len, "%u%s %s", (u32)size,
101                  tmp, unit);
102 }
103 EXPORT_SYMBOL(string_get_size);
104
105 static bool unescape_space(char **src, char **dst)
106 {
107         char *p = *dst, *q = *src;
108
109         switch (*q) {
110         case 'n':
111                 *p = '\n';
112                 break;
113         case 'r':
114                 *p = '\r';
115                 break;
116         case 't':
117                 *p = '\t';
118                 break;
119         case 'v':
120                 *p = '\v';
121                 break;
122         case 'f':
123                 *p = '\f';
124                 break;
125         default:
126                 return false;
127         }
128         *dst += 1;
129         *src += 1;
130         return true;
131 }
132
133 static bool unescape_octal(char **src, char **dst)
134 {
135         char *p = *dst, *q = *src;
136         u8 num;
137
138         if (isodigit(*q) == 0)
139                 return false;
140
141         num = (*q++) & 7;
142         while (num < 32 && isodigit(*q) && (q - *src < 3)) {
143                 num <<= 3;
144                 num += (*q++) & 7;
145         }
146         *p = num;
147         *dst += 1;
148         *src = q;
149         return true;
150 }
151
152 static bool unescape_hex(char **src, char **dst)
153 {
154         char *p = *dst, *q = *src;
155         int digit;
156         u8 num;
157
158         if (*q++ != 'x')
159                 return false;
160
161         num = digit = hex_to_bin(*q++);
162         if (digit < 0)
163                 return false;
164
165         digit = hex_to_bin(*q);
166         if (digit >= 0) {
167                 q++;
168                 num = (num << 4) | digit;
169         }
170         *p = num;
171         *dst += 1;
172         *src = q;
173         return true;
174 }
175
176 static bool unescape_special(char **src, char **dst)
177 {
178         char *p = *dst, *q = *src;
179
180         switch (*q) {
181         case '\"':
182                 *p = '\"';
183                 break;
184         case '\\':
185                 *p = '\\';
186                 break;
187         case 'a':
188                 *p = '\a';
189                 break;
190         case 'e':
191                 *p = '\e';
192                 break;
193         default:
194                 return false;
195         }
196         *dst += 1;
197         *src += 1;
198         return true;
199 }
200
201 /**
202  * string_unescape - unquote characters in the given string
203  * @src:        source buffer (escaped)
204  * @dst:        destination buffer (unescaped)
205  * @size:       size of the destination buffer (0 to unlimit)
206  * @flags:      combination of the flags (bitwise OR):
207  *      %UNESCAPE_SPACE:
208  *              '\f' - form feed
209  *              '\n' - new line
210  *              '\r' - carriage return
211  *              '\t' - horizontal tab
212  *              '\v' - vertical tab
213  *      %UNESCAPE_OCTAL:
214  *              '\NNN' - byte with octal value NNN (1 to 3 digits)
215  *      %UNESCAPE_HEX:
216  *              '\xHH' - byte with hexadecimal value HH (1 to 2 digits)
217  *      %UNESCAPE_SPECIAL:
218  *              '\"' - double quote
219  *              '\\' - backslash
220  *              '\a' - alert (BEL)
221  *              '\e' - escape
222  *      %UNESCAPE_ANY:
223  *              all previous together
224  *
225  * Description:
226  * The function unquotes characters in the given string.
227  *
228  * Because the size of the output will be the same as or less than the size of
229  * the input, the transformation may be performed in place.
230  *
231  * Caller must provide valid source and destination pointers. Be aware that
232  * destination buffer will always be NULL-terminated. Source string must be
233  * NULL-terminated as well.
234  *
235  * Return:
236  * The amount of the characters processed to the destination buffer excluding
237  * trailing '\0' is returned.
238  */
239 int string_unescape(char *src, char *dst, size_t size, unsigned int flags)
240 {
241         char *out = dst;
242
243         while (*src && --size) {
244                 if (src[0] == '\\' && src[1] != '\0' && size > 1) {
245                         src++;
246                         size--;
247
248                         if (flags & UNESCAPE_SPACE &&
249                                         unescape_space(&src, &out))
250                                 continue;
251
252                         if (flags & UNESCAPE_OCTAL &&
253                                         unescape_octal(&src, &out))
254                                 continue;
255
256                         if (flags & UNESCAPE_HEX &&
257                                         unescape_hex(&src, &out))
258                                 continue;
259
260                         if (flags & UNESCAPE_SPECIAL &&
261                                         unescape_special(&src, &out))
262                                 continue;
263
264                         *out++ = '\\';
265                 }
266                 *out++ = *src++;
267         }
268         *out = '\0';
269
270         return out - dst;
271 }
272 EXPORT_SYMBOL(string_unescape);
273
274 static bool escape_passthrough(unsigned char c, char **dst, char *end)
275 {
276         char *out = *dst;
277
278         if (out < end)
279                 *out = c;
280         *dst = out + 1;
281         return true;
282 }
283
284 static bool escape_space(unsigned char c, char **dst, char *end)
285 {
286         char *out = *dst;
287         unsigned char to;
288
289         switch (c) {
290         case '\n':
291                 to = 'n';
292                 break;
293         case '\r':
294                 to = 'r';
295                 break;
296         case '\t':
297                 to = 't';
298                 break;
299         case '\v':
300                 to = 'v';
301                 break;
302         case '\f':
303                 to = 'f';
304                 break;
305         default:
306                 return false;
307         }
308
309         if (out < end)
310                 *out = '\\';
311         ++out;
312         if (out < end)
313                 *out = to;
314         ++out;
315
316         *dst = out;
317         return true;
318 }
319
320 static bool escape_special(unsigned char c, char **dst, char *end)
321 {
322         char *out = *dst;
323         unsigned char to;
324
325         switch (c) {
326         case '\\':
327                 to = '\\';
328                 break;
329         case '\a':
330                 to = 'a';
331                 break;
332         case '\e':
333                 to = 'e';
334                 break;
335         default:
336                 return false;
337         }
338
339         if (out < end)
340                 *out = '\\';
341         ++out;
342         if (out < end)
343                 *out = to;
344         ++out;
345
346         *dst = out;
347         return true;
348 }
349
350 static bool escape_null(unsigned char c, char **dst, char *end)
351 {
352         char *out = *dst;
353
354         if (c)
355                 return false;
356
357         if (out < end)
358                 *out = '\\';
359         ++out;
360         if (out < end)
361                 *out = '0';
362         ++out;
363
364         *dst = out;
365         return true;
366 }
367
368 static bool escape_octal(unsigned char c, char **dst, char *end)
369 {
370         char *out = *dst;
371
372         if (out < end)
373                 *out = '\\';
374         ++out;
375         if (out < end)
376                 *out = ((c >> 6) & 0x07) + '0';
377         ++out;
378         if (out < end)
379                 *out = ((c >> 3) & 0x07) + '0';
380         ++out;
381         if (out < end)
382                 *out = ((c >> 0) & 0x07) + '0';
383         ++out;
384
385         *dst = out;
386         return true;
387 }
388
389 static bool escape_hex(unsigned char c, char **dst, char *end)
390 {
391         char *out = *dst;
392
393         if (out < end)
394                 *out = '\\';
395         ++out;
396         if (out < end)
397                 *out = 'x';
398         ++out;
399         if (out < end)
400                 *out = hex_asc_hi(c);
401         ++out;
402         if (out < end)
403                 *out = hex_asc_lo(c);
404         ++out;
405
406         *dst = out;
407         return true;
408 }
409
410 /**
411  * string_escape_mem - quote characters in the given memory buffer
412  * @src:        source buffer (unescaped)
413  * @isz:        source buffer size
414  * @dst:        destination buffer (escaped)
415  * @osz:        destination buffer size
416  * @flags:      combination of the flags (bitwise OR):
417  *      %ESCAPE_SPACE: (special white space, not space itself)
418  *              '\f' - form feed
419  *              '\n' - new line
420  *              '\r' - carriage return
421  *              '\t' - horizontal tab
422  *              '\v' - vertical tab
423  *      %ESCAPE_SPECIAL:
424  *              '\\' - backslash
425  *              '\a' - alert (BEL)
426  *              '\e' - escape
427  *      %ESCAPE_NULL:
428  *              '\0' - null
429  *      %ESCAPE_OCTAL:
430  *              '\NNN' - byte with octal value NNN (3 digits)
431  *      %ESCAPE_ANY:
432  *              all previous together
433  *      %ESCAPE_NP:
434  *              escape only non-printable characters (checked by isprint)
435  *      %ESCAPE_ANY_NP:
436  *              all previous together
437  *      %ESCAPE_HEX:
438  *              '\xHH' - byte with hexadecimal value HH (2 digits)
439  * @only:       NULL-terminated string containing characters used to limit
440  *              the selected escape class. If characters are included in @only
441  *              that would not normally be escaped by the classes selected
442  *              in @flags, they will be copied to @dst unescaped.
443  *
444  * Description:
445  * The process of escaping byte buffer includes several parts. They are applied
446  * in the following sequence.
447  *      1. The character is matched to the printable class, if asked, and in
448  *         case of match it passes through to the output.
449  *      2. The character is not matched to the one from @only string and thus
450  *         must go as-is to the output.
451  *      3. The character is checked if it falls into the class given by @flags.
452  *         %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any
453  *         character. Note that they actually can't go together, otherwise
454  *         %ESCAPE_HEX will be ignored.
455  *
456  * Caller must provide valid source and destination pointers. Be aware that
457  * destination buffer will not be NULL-terminated, thus caller have to append
458  * it if needs.
459  *
460  * Return:
461  * The total size of the escaped output that would be generated for
462  * the given input and flags. To check whether the output was
463  * truncated, compare the return value to osz. There is room left in
464  * dst for a '\0' terminator if and only if ret < osz.
465  */
466 int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
467                       unsigned int flags, const char *only)
468 {
469         char *p = dst;
470         char *end = p + osz;
471         bool is_dict = only && *only;
472
473         while (isz--) {
474                 unsigned char c = *src++;
475
476                 /*
477                  * Apply rules in the following sequence:
478                  *      - the character is printable, when @flags has
479                  *        %ESCAPE_NP bit set
480                  *      - the @only string is supplied and does not contain a
481                  *        character under question
482                  *      - the character doesn't fall into a class of symbols
483                  *        defined by given @flags
484                  * In these cases we just pass through a character to the
485                  * output buffer.
486                  */
487                 if ((flags & ESCAPE_NP && isprint(c)) ||
488                     (is_dict && !strchr(only, c))) {
489                         /* do nothing */
490                 } else {
491                         if (flags & ESCAPE_SPACE && escape_space(c, &p, end))
492                                 continue;
493
494                         if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end))
495                                 continue;
496
497                         if (flags & ESCAPE_NULL && escape_null(c, &p, end))
498                                 continue;
499
500                         /* ESCAPE_OCTAL and ESCAPE_HEX always go last */
501                         if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end))
502                                 continue;
503
504                         if (flags & ESCAPE_HEX && escape_hex(c, &p, end))
505                                 continue;
506                 }
507
508                 escape_passthrough(c, &p, end);
509         }
510
511         return p - dst;
512 }
513 EXPORT_SYMBOL(string_escape_mem);