Branch data Line data Source code
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/string_helpers.h>
12 : :
13 : : /**
14 : : * string_get_size - get the size in the specified units
15 : : * @size: The size to be converted
16 : : * @units: units to use (powers of 1000 or 1024)
17 : : * @buf: buffer to format to
18 : : * @len: length of buffer
19 : : *
20 : : * This function returns a string formatted to 3 significant figures
21 : : * giving the size in the required units. Returns 0 on success or
22 : : * error on failure. @buf is always zero terminated.
23 : : *
24 : : */
25 : 0 : int string_get_size(u64 size, const enum string_size_units units,
26 : : char *buf, int len)
27 : : {
28 : : static const char *units_10[] = { "B", "kB", "MB", "GB", "TB", "PB",
29 : : "EB", "ZB", "YB", NULL};
30 : : static const char *units_2[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB",
31 : : "EiB", "ZiB", "YiB", NULL };
32 : : static const char **units_str[] = {
33 : : [STRING_UNITS_10] = units_10,
34 : : [STRING_UNITS_2] = units_2,
35 : : };
36 : : static const unsigned int divisor[] = {
37 : : [STRING_UNITS_10] = 1000,
38 : : [STRING_UNITS_2] = 1024,
39 : : };
40 : : int i, j;
41 : : u64 remainder = 0, sf_cap;
42 : : char tmp[8];
43 : :
44 : 0 : tmp[0] = '\0';
45 : : i = 0;
46 [ # # ]: 0 : if (size >= divisor[units]) {
47 [ # # ][ # # ]: 0 : while (size >= divisor[units] && units_str[units][i]) {
48 [ # # ][ # # ]: 0 : remainder = do_div(size, divisor[units]);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
49 : 0 : i++;
50 : : }
51 : :
52 : : sf_cap = size;
53 [ # # ]: 0 : for (j = 0; sf_cap*10 < 1000; j++)
54 : : sf_cap *= 10;
55 : :
56 [ # # ]: 0 : if (j) {
57 : 0 : remainder *= 1000;
58 [ # # ][ # # ]: 0 : do_div(remainder, divisor[units]);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
59 : 0 : snprintf(tmp, sizeof(tmp), ".%03lld",
60 : : (unsigned long long)remainder);
61 : 0 : tmp[j+1] = '\0';
62 : : }
63 : : }
64 : :
65 : 0 : snprintf(buf, len, "%lld%s %s", (unsigned long long)size,
66 : 0 : tmp, units_str[units][i]);
67 : :
68 : 0 : return 0;
69 : : }
70 : : EXPORT_SYMBOL(string_get_size);
71 : :
72 : 0 : static bool unescape_space(char **src, char **dst)
73 : : {
74 : 0 : char *p = *dst, *q = *src;
75 : :
76 [ # # # # : 0 : switch (*q) {
# # ]
77 : : case 'n':
78 : 0 : *p = '\n';
79 : 0 : break;
80 : : case 'r':
81 : 0 : *p = '\r';
82 : 0 : break;
83 : : case 't':
84 : 0 : *p = '\t';
85 : 0 : break;
86 : : case 'v':
87 : 0 : *p = '\v';
88 : 0 : break;
89 : : case 'f':
90 : 0 : *p = '\f';
91 : 0 : break;
92 : : default:
93 : : return false;
94 : : }
95 : 0 : *dst += 1;
96 : 0 : *src += 1;
97 : 0 : return true;
98 : : }
99 : :
100 : 0 : static bool unescape_octal(char **src, char **dst)
101 : : {
102 : 0 : char *p = *dst, *q = *src;
103 : : u8 num;
104 : :
105 [ # # ]: 0 : if (isodigit(*q) == 0)
106 : : return false;
107 : :
108 : 0 : num = (*q++) & 7;
109 [ # # ][ # # ]: 0 : while (num < 32 && isodigit(*q) && (q - *src < 3)) {
[ # # ]
110 : 0 : num <<= 3;
111 : 0 : num += (*q++) & 7;
112 : : }
113 : 0 : *p = num;
114 : 0 : *dst += 1;
115 : 0 : *src = q;
116 : 0 : return true;
117 : : }
118 : :
119 : 0 : static bool unescape_hex(char **src, char **dst)
120 : : {
121 : 0 : char *p = *dst, *q = *src;
122 : : int digit;
123 : : u8 num;
124 : :
125 [ # # ]: 0 : if (*q++ != 'x')
126 : : return false;
127 : :
128 : 0 : num = digit = hex_to_bin(*q++);
129 [ # # ]: 0 : if (digit < 0)
130 : : return false;
131 : :
132 : 0 : digit = hex_to_bin(*q);
133 [ # # ]: 0 : if (digit >= 0) {
134 : 0 : q++;
135 : 0 : num = (num << 4) | digit;
136 : : }
137 : 0 : *p = num;
138 : 0 : *dst += 1;
139 : 0 : *src = q;
140 : 0 : return true;
141 : : }
142 : :
143 : 0 : static bool unescape_special(char **src, char **dst)
144 : : {
145 : 0 : char *p = *dst, *q = *src;
146 : :
147 [ # # # # : 0 : switch (*q) {
# ]
148 : : case '\"':
149 : 0 : *p = '\"';
150 : 0 : break;
151 : : case '\\':
152 : 0 : *p = '\\';
153 : 0 : break;
154 : : case 'a':
155 : 0 : *p = '\a';
156 : 0 : break;
157 : : case 'e':
158 : 0 : *p = '\e';
159 : 0 : break;
160 : : default:
161 : : return false;
162 : : }
163 : 0 : *dst += 1;
164 : 0 : *src += 1;
165 : 0 : return true;
166 : : }
167 : :
168 : 0 : int string_unescape(char *src, char *dst, size_t size, unsigned int flags)
169 : : {
170 : 0 : char *out = dst;
171 : :
172 [ # # ][ # # ]: 0 : while (*src && --size) {
173 [ # # ][ # # ]: 0 : if (src[0] == '\\' && src[1] != '\0' && size > 1) {
[ # # ]
174 : 0 : src++;
175 : 0 : size--;
176 : :
177 [ # # # # ]: 0 : if (flags & UNESCAPE_SPACE &&
178 : 0 : unescape_space(&src, &out))
179 : 0 : continue;
180 : :
181 [ # # # # ]: 0 : if (flags & UNESCAPE_OCTAL &&
182 : 0 : unescape_octal(&src, &out))
183 : 0 : continue;
184 : :
185 [ # # # # ]: 0 : if (flags & UNESCAPE_HEX &&
186 : 0 : unescape_hex(&src, &out))
187 : 0 : continue;
188 : :
189 [ # # # # ]: 0 : if (flags & UNESCAPE_SPECIAL &&
190 : 0 : unescape_special(&src, &out))
191 : 0 : continue;
192 : :
193 : 0 : *out++ = '\\';
194 : : }
195 : 0 : *out++ = *src++;
196 : : }
197 : 0 : *out = '\0';
198 : :
199 : 0 : return out - dst;
200 : : }
201 : : EXPORT_SYMBOL(string_unescape);
|