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