~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/lib/string_helpers.c

Version: ~ [ linux-5.3-rc5 ] ~ [ linux-5.2.9 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.67 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.139 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.189 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.189 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.72 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 bool escape_passthrough(unsigned char c, char **dst, char *end)
271 {
272         char *out = *dst;
273 
274         if (out < end)
275                 *out = c;
276         *dst = out + 1;
277         return true;
278 }
279 
280 static bool escape_space(unsigned char c, char **dst, char *end)
281 {
282         char *out = *dst;
283         unsigned char to;
284 
285         switch (c) {
286         case '\n':
287                 to = 'n';
288                 break;
289         case '\r':
290                 to = 'r';
291                 break;
292         case '\t':
293                 to = 't';
294                 break;
295         case '\v':
296                 to = 'v';
297                 break;
298         case '\f':
299                 to = 'f';
300                 break;
301         default:
302                 return false;
303         }
304 
305         if (out < end)
306                 *out = '\\';
307         ++out;
308         if (out < end)
309                 *out = to;
310         ++out;
311 
312         *dst = out;
313         return true;
314 }
315 
316 static bool escape_special(unsigned char c, char **dst, char *end)
317 {
318         char *out = *dst;
319         unsigned char to;
320 
321         switch (c) {
322         case '\\':
323                 to = '\\';
324                 break;
325         case '\a':
326                 to = 'a';
327                 break;
328         case '\e':
329                 to = 'e';
330                 break;
331         default:
332                 return false;
333         }
334 
335         if (out < end)
336                 *out = '\\';
337         ++out;
338         if (out < end)
339                 *out = to;
340         ++out;
341 
342         *dst = out;
343         return true;
344 }
345 
346 static bool escape_null(unsigned char c, char **dst, char *end)
347 {
348         char *out = *dst;
349 
350         if (c)
351                 return false;
352 
353         if (out < end)
354                 *out = '\\';
355         ++out;
356         if (out < end)
357                 *out = '';
358         ++out;
359 
360         *dst = out;
361         return true;
362 }
363 
364 static bool escape_octal(unsigned char c, char **dst, char *end)
365 {
366         char *out = *dst;
367 
368         if (out < end)
369                 *out = '\\';
370         ++out;
371         if (out < end)
372                 *out = ((c >> 6) & 0x07) + '';
373         ++out;
374         if (out < end)
375                 *out = ((c >> 3) & 0x07) + '';
376         ++out;
377         if (out < end)
378                 *out = ((c >> 0) & 0x07) + '';
379         ++out;
380 
381         *dst = out;
382         return true;
383 }
384 
385 static bool escape_hex(unsigned char c, char **dst, char *end)
386 {
387         char *out = *dst;
388 
389         if (out < end)
390                 *out = '\\';
391         ++out;
392         if (out < end)
393                 *out = 'x';
394         ++out;
395         if (out < end)
396                 *out = hex_asc_hi(c);
397         ++out;
398         if (out < end)
399                 *out = hex_asc_lo(c);
400         ++out;
401 
402         *dst = out;
403         return true;
404 }
405 
406 /**
407  * string_escape_mem - quote characters in the given memory buffer
408  * @src:        source buffer (unescaped)
409  * @isz:        source buffer size
410  * @dst:        destination buffer (escaped)
411  * @osz:        destination buffer size
412  * @flags:      combination of the flags (bitwise OR):
413  *      %ESCAPE_SPACE:
414  *              '\f' - form feed
415  *              '\n' - new line
416  *              '\r' - carriage return
417  *              '\t' - horizontal tab
418  *              '\v' - vertical tab
419  *      %ESCAPE_SPECIAL:
420  *              '\\' - backslash
421  *              '\a' - alert (BEL)
422  *              '\e' - escape
423  *      %ESCAPE_NULL:
424  *              '\0' - null
425  *      %ESCAPE_OCTAL:
426  *              '\NNN' - byte with octal value NNN (3 digits)
427  *      %ESCAPE_ANY:
428  *              all previous together
429  *      %ESCAPE_NP:
430  *              escape only non-printable characters (checked by isprint)
431  *      %ESCAPE_ANY_NP:
432  *              all previous together
433  *      %ESCAPE_HEX:
434  *              '\xHH' - byte with hexadecimal value HH (2 digits)
435  * @esc:        NULL-terminated string of characters any of which, if found in
436  *              the source, has to be escaped
437  *
438  * Description:
439  * The process of escaping byte buffer includes several parts. They are applied
440  * in the following sequence.
441  *      1. The character is matched to the printable class, if asked, and in
442  *         case of match it passes through to the output.
443  *      2. The character is not matched to the one from @esc string and thus
444  *         must go as is to the output.
445  *      3. The character is checked if it falls into the class given by @flags.
446  *         %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any
447  *         character. Note that they actually can't go together, otherwise
448  *         %ESCAPE_HEX will be ignored.
449  *
450  * Caller must provide valid source and destination pointers. Be aware that
451  * destination buffer will not be NULL-terminated, thus caller have to append
452  * it if needs.
453  *
454  * Return:
455  * The total size of the escaped output that would be generated for
456  * the given input and flags. To check whether the output was
457  * truncated, compare the return value to osz. There is room left in
458  * dst for a '\0' terminator if and only if ret < osz.
459  */
460 int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
461                       unsigned int flags, const char *esc)
462 {
463         char *p = dst;
464         char *end = p + osz;
465         bool is_dict = esc && *esc;
466 
467         while (isz--) {
468                 unsigned char c = *src++;
469 
470                 /*
471                  * Apply rules in the following sequence:
472                  *      - the character is printable, when @flags has
473                  *        %ESCAPE_NP bit set
474                  *      - the @esc string is supplied and does not contain a
475                  *        character under question
476                  *      - the character doesn't fall into a class of symbols
477                  *        defined by given @flags
478                  * In these cases we just pass through a character to the
479                  * output buffer.
480                  */
481                 if ((flags & ESCAPE_NP && isprint(c)) ||
482                     (is_dict && !strchr(esc, c))) {
483                         /* do nothing */
484                 } else {
485                         if (flags & ESCAPE_SPACE && escape_space(c, &p, end))
486                                 continue;
487 
488                         if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end))
489                                 continue;
490 
491                         if (flags & ESCAPE_NULL && escape_null(c, &p, end))
492                                 continue;
493 
494                         /* ESCAPE_OCTAL and ESCAPE_HEX always go last */
495                         if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end))
496                                 continue;
497 
498                         if (flags & ESCAPE_HEX && escape_hex(c, &p, end))
499                                 continue;
500                 }
501 
502                 escape_passthrough(c, &p, end);
503         }
504 
505         return p - dst;
506 }
507 EXPORT_SYMBOL(string_escape_mem);
508 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp