sd, mmc, virtio_blk, string_helpers: fix block size units
[firefly-linux-kernel-4.4.55.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         if (size >= exp) {
63                 remainder = do_div(size, divisor[units]);
64                 remainder *= blk_size;
65                 i++;
66         } else {
67                 remainder *= size;
68         }
69
70         size *= blk_size;
71         size += remainder / divisor[units];
72         remainder %= divisor[units];
73
74         while (size >= divisor[units]) {
75                 remainder = do_div(size, divisor[units]);
76                 i++;
77         }
78
79         sf_cap = size;
80         for (j = 0; sf_cap*10 < 1000; j++)
81                 sf_cap *= 10;
82
83         if (j) {
84                 remainder *= 1000;
85                 remainder /= divisor[units];
86                 snprintf(tmp, sizeof(tmp), ".%03u", remainder);
87                 tmp[j+1] = '\0';
88         }
89
90  out:
91         if (i >= ARRAY_SIZE(units_2))
92                 unit = "UNK";
93         else
94                 unit = units_str[units][i];
95
96         snprintf(buf, len, "%u%s %s", (u32)size,
97                  tmp, unit);
98 }
99 EXPORT_SYMBOL(string_get_size);
100
101 static bool unescape_space(char **src, char **dst)
102 {
103         char *p = *dst, *q = *src;
104
105         switch (*q) {
106         case 'n':
107                 *p = '\n';
108                 break;
109         case 'r':
110                 *p = '\r';
111                 break;
112         case 't':
113                 *p = '\t';
114                 break;
115         case 'v':
116                 *p = '\v';
117                 break;
118         case 'f':
119                 *p = '\f';
120                 break;
121         default:
122                 return false;
123         }
124         *dst += 1;
125         *src += 1;
126         return true;
127 }
128
129 static bool unescape_octal(char **src, char **dst)
130 {
131         char *p = *dst, *q = *src;
132         u8 num;
133
134         if (isodigit(*q) == 0)
135                 return false;
136
137         num = (*q++) & 7;
138         while (num < 32 && isodigit(*q) && (q - *src < 3)) {
139                 num <<= 3;
140                 num += (*q++) & 7;
141         }
142         *p = num;
143         *dst += 1;
144         *src = q;
145         return true;
146 }
147
148 static bool unescape_hex(char **src, char **dst)
149 {
150         char *p = *dst, *q = *src;
151         int digit;
152         u8 num;
153
154         if (*q++ != 'x')
155                 return false;
156
157         num = digit = hex_to_bin(*q++);
158         if (digit < 0)
159                 return false;
160
161         digit = hex_to_bin(*q);
162         if (digit >= 0) {
163                 q++;
164                 num = (num << 4) | digit;
165         }
166         *p = num;
167         *dst += 1;
168         *src = q;
169         return true;
170 }
171
172 static bool unescape_special(char **src, char **dst)
173 {
174         char *p = *dst, *q = *src;
175
176         switch (*q) {
177         case '\"':
178                 *p = '\"';
179                 break;
180         case '\\':
181                 *p = '\\';
182                 break;
183         case 'a':
184                 *p = '\a';
185                 break;
186         case 'e':
187                 *p = '\e';
188                 break;
189         default:
190                 return false;
191         }
192         *dst += 1;
193         *src += 1;
194         return true;
195 }
196
197 /**
198  * string_unescape - unquote characters in the given string
199  * @src:        source buffer (escaped)
200  * @dst:        destination buffer (unescaped)
201  * @size:       size of the destination buffer (0 to unlimit)
202  * @flags:      combination of the flags (bitwise OR):
203  *      %UNESCAPE_SPACE:
204  *              '\f' - form feed
205  *              '\n' - new line
206  *              '\r' - carriage return
207  *              '\t' - horizontal tab
208  *              '\v' - vertical tab
209  *      %UNESCAPE_OCTAL:
210  *              '\NNN' - byte with octal value NNN (1 to 3 digits)
211  *      %UNESCAPE_HEX:
212  *              '\xHH' - byte with hexadecimal value HH (1 to 2 digits)
213  *      %UNESCAPE_SPECIAL:
214  *              '\"' - double quote
215  *              '\\' - backslash
216  *              '\a' - alert (BEL)
217  *              '\e' - escape
218  *      %UNESCAPE_ANY:
219  *              all previous together
220  *
221  * Description:
222  * The function unquotes characters in the given string.
223  *
224  * Because the size of the output will be the same as or less than the size of
225  * the input, the transformation may be performed in place.
226  *
227  * Caller must provide valid source and destination pointers. Be aware that
228  * destination buffer will always be NULL-terminated. Source string must be
229  * NULL-terminated as well.
230  *
231  * Return:
232  * The amount of the characters processed to the destination buffer excluding
233  * trailing '\0' is returned.
234  */
235 int string_unescape(char *src, char *dst, size_t size, unsigned int flags)
236 {
237         char *out = dst;
238
239         while (*src && --size) {
240                 if (src[0] == '\\' && src[1] != '\0' && size > 1) {
241                         src++;
242                         size--;
243
244                         if (flags & UNESCAPE_SPACE &&
245                                         unescape_space(&src, &out))
246                                 continue;
247
248                         if (flags & UNESCAPE_OCTAL &&
249                                         unescape_octal(&src, &out))
250                                 continue;
251
252                         if (flags & UNESCAPE_HEX &&
253                                         unescape_hex(&src, &out))
254                                 continue;
255
256                         if (flags & UNESCAPE_SPECIAL &&
257                                         unescape_special(&src, &out))
258                                 continue;
259
260                         *out++ = '\\';
261                 }
262                 *out++ = *src++;
263         }
264         *out = '\0';
265
266         return out - dst;
267 }
268 EXPORT_SYMBOL(string_unescape);
269
270 static int escape_passthrough(unsigned char c, char **dst, size_t *osz)
271 {
272         char *out = *dst;
273
274         if (*osz < 1)
275                 return -ENOMEM;
276
277         *out++ = c;
278
279         *dst = out;
280         *osz -= 1;
281
282         return 1;
283 }
284
285 static int escape_space(unsigned char c, char **dst, size_t *osz)
286 {
287         char *out = *dst;
288         unsigned char to;
289
290         if (*osz < 2)
291                 return -ENOMEM;
292
293         switch (c) {
294         case '\n':
295                 to = 'n';
296                 break;
297         case '\r':
298                 to = 'r';
299                 break;
300         case '\t':
301                 to = 't';
302                 break;
303         case '\v':
304                 to = 'v';
305                 break;
306         case '\f':
307                 to = 'f';
308                 break;
309         default:
310                 return 0;
311         }
312
313         *out++ = '\\';
314         *out++ = to;
315
316         *dst = out;
317         *osz -= 2;
318
319         return 1;
320 }
321
322 static int escape_special(unsigned char c, char **dst, size_t *osz)
323 {
324         char *out = *dst;
325         unsigned char to;
326
327         if (*osz < 2)
328                 return -ENOMEM;
329
330         switch (c) {
331         case '\\':
332                 to = '\\';
333                 break;
334         case '\a':
335                 to = 'a';
336                 break;
337         case '\e':
338                 to = 'e';
339                 break;
340         default:
341                 return 0;
342         }
343
344         *out++ = '\\';
345         *out++ = to;
346
347         *dst = out;
348         *osz -= 2;
349
350         return 1;
351 }
352
353 static int escape_null(unsigned char c, char **dst, size_t *osz)
354 {
355         char *out = *dst;
356
357         if (*osz < 2)
358                 return -ENOMEM;
359
360         if (c)
361                 return 0;
362
363         *out++ = '\\';
364         *out++ = '0';
365
366         *dst = out;
367         *osz -= 2;
368
369         return 1;
370 }
371
372 static int escape_octal(unsigned char c, char **dst, size_t *osz)
373 {
374         char *out = *dst;
375
376         if (*osz < 4)
377                 return -ENOMEM;
378
379         *out++ = '\\';
380         *out++ = ((c >> 6) & 0x07) + '0';
381         *out++ = ((c >> 3) & 0x07) + '0';
382         *out++ = ((c >> 0) & 0x07) + '0';
383
384         *dst = out;
385         *osz -= 4;
386
387         return 1;
388 }
389
390 static int escape_hex(unsigned char c, char **dst, size_t *osz)
391 {
392         char *out = *dst;
393
394         if (*osz < 4)
395                 return -ENOMEM;
396
397         *out++ = '\\';
398         *out++ = 'x';
399         *out++ = hex_asc_hi(c);
400         *out++ = hex_asc_lo(c);
401
402         *dst = out;
403         *osz -= 4;
404
405         return 1;
406 }
407
408 /**
409  * string_escape_mem - quote characters in the given memory buffer
410  * @src:        source buffer (unescaped)
411  * @isz:        source buffer size
412  * @dst:        destination buffer (escaped)
413  * @osz:        destination buffer size
414  * @flags:      combination of the flags (bitwise OR):
415  *      %ESCAPE_SPACE:
416  *              '\f' - form feed
417  *              '\n' - new line
418  *              '\r' - carriage return
419  *              '\t' - horizontal tab
420  *              '\v' - vertical tab
421  *      %ESCAPE_SPECIAL:
422  *              '\\' - backslash
423  *              '\a' - alert (BEL)
424  *              '\e' - escape
425  *      %ESCAPE_NULL:
426  *              '\0' - null
427  *      %ESCAPE_OCTAL:
428  *              '\NNN' - byte with octal value NNN (3 digits)
429  *      %ESCAPE_ANY:
430  *              all previous together
431  *      %ESCAPE_NP:
432  *              escape only non-printable characters (checked by isprint)
433  *      %ESCAPE_ANY_NP:
434  *              all previous together
435  *      %ESCAPE_HEX:
436  *              '\xHH' - byte with hexadecimal value HH (2 digits)
437  * @esc:        NULL-terminated string of characters any of which, if found in
438  *              the source, has to be escaped
439  *
440  * Description:
441  * The process of escaping byte buffer includes several parts. They are applied
442  * in the following sequence.
443  *      1. The character is matched to the printable class, if asked, and in
444  *         case of match it passes through to the output.
445  *      2. The character is not matched to the one from @esc string and thus
446  *         must go as is to the output.
447  *      3. The character is checked if it falls into the class given by @flags.
448  *         %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any
449  *         character. Note that they actually can't go together, otherwise
450  *         %ESCAPE_HEX will be ignored.
451  *
452  * Caller must provide valid source and destination pointers. Be aware that
453  * destination buffer will not be NULL-terminated, thus caller have to append
454  * it if needs.
455  *
456  * Return:
457  * The amount of the characters processed to the destination buffer, or
458  * %-ENOMEM if the size of buffer is not enough to put an escaped character is
459  * returned.
460  *
461  * Even in the case of error @dst pointer will be updated to point to the byte
462  * after the last processed character.
463  */
464 int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz,
465                       unsigned int flags, const char *esc)
466 {
467         char *out = *dst, *p = out;
468         bool is_dict = esc && *esc;
469         int ret = 0;
470
471         while (isz--) {
472                 unsigned char c = *src++;
473
474                 /*
475                  * Apply rules in the following sequence:
476                  *      - the character is printable, when @flags has
477                  *        %ESCAPE_NP bit set
478                  *      - the @esc string is supplied and does not contain a
479                  *        character under question
480                  *      - the character doesn't fall into a class of symbols
481                  *        defined by given @flags
482                  * In these cases we just pass through a character to the
483                  * output buffer.
484                  */
485                 if ((flags & ESCAPE_NP && isprint(c)) ||
486                     (is_dict && !strchr(esc, c))) {
487                         /* do nothing */
488                 } else {
489                         if (flags & ESCAPE_SPACE) {
490                                 ret = escape_space(c, &p, &osz);
491                                 if (ret < 0)
492                                         break;
493                                 if (ret > 0)
494                                         continue;
495                         }
496
497                         if (flags & ESCAPE_SPECIAL) {
498                                 ret = escape_special(c, &p, &osz);
499                                 if (ret < 0)
500                                         break;
501                                 if (ret > 0)
502                                         continue;
503                         }
504
505                         if (flags & ESCAPE_NULL) {
506                                 ret = escape_null(c, &p, &osz);
507                                 if (ret < 0)
508                                         break;
509                                 if (ret > 0)
510                                         continue;
511                         }
512
513                         /* ESCAPE_OCTAL and ESCAPE_HEX always go last */
514                         if (flags & ESCAPE_OCTAL) {
515                                 ret = escape_octal(c, &p, &osz);
516                                 if (ret < 0)
517                                         break;
518                                 continue;
519                         }
520                         if (flags & ESCAPE_HEX) {
521                                 ret = escape_hex(c, &p, &osz);
522                                 if (ret < 0)
523                                         break;
524                                 continue;
525                         }
526                 }
527
528                 ret = escape_passthrough(c, &p, &osz);
529                 if (ret < 0)
530                         break;
531         }
532
533         *dst = p;
534
535         if (ret < 0)
536                 return ret;
537
538         return p - out;
539 }
540 EXPORT_SYMBOL(string_escape_mem);