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