aboutsummaryrefslogtreecommitdiffstats
path: root/lib/string_helpers.c
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2014-10-13 18:55:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-13 20:18:26 -0400
commitc8250381c8272a9828fdd353171727b154fbd296 (patch)
tree050650d45d87d430334939f0552deafbe36561f9 /lib/string_helpers.c
parent45ff337a54c154680edf0c538e5c9eb4a2f862cc (diff)
lib / string_helpers: introduce string_escape_mem()
This is almost the opposite function to string_unescape(). Nevertheless it handles \0 and could be used for any byte buffer. The documentation is supplied together with the function prototype. The test cases covers most of the scenarios and would be expanded later on. [akpm@linux-foundation.org: avoid 1k stack consumption] Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: "John W . Linville" <linville@tuxdriver.com> Cc: Johannes Berg <johannes@sipsolutions.net> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Joe Perches <joe@perches.com> Cc: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib/string_helpers.c')
-rw-r--r--lib/string_helpers.c274
1 files changed, 274 insertions, 0 deletions
diff --git a/lib/string_helpers.c b/lib/string_helpers.c
index 74ec60469640..58b78ba57439 100644
--- a/lib/string_helpers.c
+++ b/lib/string_helpers.c
@@ -8,6 +8,8 @@
8#include <linux/math64.h> 8#include <linux/math64.h>
9#include <linux/export.h> 9#include <linux/export.h>
10#include <linux/ctype.h> 10#include <linux/ctype.h>
11#include <linux/errno.h>
12#include <linux/string.h>
11#include <linux/string_helpers.h> 13#include <linux/string_helpers.h>
12 14
13/** 15/**
@@ -240,3 +242,275 @@ int string_unescape(char *src, char *dst, size_t size, unsigned int flags)
240 return out - dst; 242 return out - dst;
241} 243}
242EXPORT_SYMBOL(string_unescape); 244EXPORT_SYMBOL(string_unescape);
245
246static int escape_passthrough(unsigned char c, char **dst, size_t *osz)
247{
248 char *out = *dst;
249
250 if (*osz < 1)
251 return -ENOMEM;
252
253 *out++ = c;
254
255 *dst = out;
256 *osz -= 1;
257
258 return 1;
259}
260
261static int escape_space(unsigned char c, char **dst, size_t *osz)
262{
263 char *out = *dst;
264 unsigned char to;
265
266 if (*osz < 2)
267 return -ENOMEM;
268
269 switch (c) {
270 case '\n':
271 to = 'n';
272 break;
273 case '\r':
274 to = 'r';
275 break;
276 case '\t':
277 to = 't';
278 break;
279 case '\v':
280 to = 'v';
281 break;
282 case '\f':
283 to = 'f';
284 break;
285 default:
286 return 0;
287 }
288
289 *out++ = '\\';
290 *out++ = to;
291
292 *dst = out;
293 *osz -= 2;
294
295 return 1;
296}
297
298static int escape_special(unsigned char c, char **dst, size_t *osz)
299{
300 char *out = *dst;
301 unsigned char to;
302
303 if (*osz < 2)
304 return -ENOMEM;
305
306 switch (c) {
307 case '\\':
308 to = '\\';
309 break;
310 case '\a':
311 to = 'a';
312 break;
313 case '\e':
314 to = 'e';
315 break;
316 default:
317 return 0;
318 }
319
320 *out++ = '\\';
321 *out++ = to;
322
323 *dst = out;
324 *osz -= 2;
325
326 return 1;
327}
328
329static int escape_null(unsigned char c, char **dst, size_t *osz)
330{
331 char *out = *dst;
332
333 if (*osz < 2)
334 return -ENOMEM;
335
336 if (c)
337 return 0;
338
339 *out++ = '\\';
340 *out++ = '0';
341
342 *dst = out;
343 *osz -= 2;
344
345 return 1;
346}
347
348static int escape_octal(unsigned char c, char **dst, size_t *osz)
349{
350 char *out = *dst;
351
352 if (*osz < 4)
353 return -ENOMEM;
354
355 *out++ = '\\';
356 *out++ = ((c >> 6) & 0x07) + '0';
357 *out++ = ((c >> 3) & 0x07) + '0';
358 *out++ = ((c >> 0) & 0x07) + '0';
359
360 *dst = out;
361 *osz -= 4;
362
363 return 1;
364}
365
366static int escape_hex(unsigned char c, char **dst, size_t *osz)
367{
368 char *out = *dst;
369
370 if (*osz < 4)
371 return -ENOMEM;
372
373 *out++ = '\\';
374 *out++ = 'x';
375 *out++ = hex_asc_hi(c);
376 *out++ = hex_asc_lo(c);
377
378 *dst = out;
379 *osz -= 4;
380
381 return 1;
382}
383
384/**
385 * string_escape_mem - quote characters in the given memory buffer
386 * @src: source buffer (unescaped)
387 * @isz: source buffer size
388 * @dst: destination buffer (escaped)
389 * @osz: destination buffer size
390 * @flags: combination of the flags (bitwise OR):
391 * %ESCAPE_SPACE:
392 * '\f' - form feed
393 * '\n' - new line
394 * '\r' - carriage return
395 * '\t' - horizontal tab
396 * '\v' - vertical tab
397 * %ESCAPE_SPECIAL:
398 * '\\' - backslash
399 * '\a' - alert (BEL)
400 * '\e' - escape
401 * %ESCAPE_NULL:
402 * '\0' - null
403 * %ESCAPE_OCTAL:
404 * '\NNN' - byte with octal value NNN (3 digits)
405 * %ESCAPE_ANY:
406 * all previous together
407 * %ESCAPE_NP:
408 * escape only non-printable characters (checked by isprint)
409 * %ESCAPE_ANY_NP:
410 * all previous together
411 * %ESCAPE_HEX:
412 * '\xHH' - byte with hexadecimal value HH (2 digits)
413 * @esc: NULL-terminated string of characters any of which, if found in
414 * the source, has to be escaped
415 *
416 * Description:
417 * The process of escaping byte buffer includes several parts. They are applied
418 * in the following sequence.
419 * 1. The character is matched to the printable class, if asked, and in
420 * case of match it passes through to the output.
421 * 2. The character is not matched to the one from @esc string and thus
422 * must go as is to the output.
423 * 3. The character is checked if it falls into the class given by @flags.
424 * %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any
425 * character. Note that they actually can't go together, otherwise
426 * %ESCAPE_HEX will be ignored.
427 *
428 * Caller must provide valid source and destination pointers. Be aware that
429 * destination buffer will not be NULL-terminated, thus caller have to append
430 * it if needs.
431 *
432 * Return:
433 * The amount of the characters processed to the destination buffer, or
434 * %-ENOMEM if the size of buffer is not enough to put an escaped character is
435 * returned.
436 *
437 * Even in the case of error @dst pointer will be updated to point to the byte
438 * after the last processed character.
439 */
440int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz,
441 unsigned int flags, const char *esc)
442{
443 char *out = *dst, *p = out;
444 bool is_dict = esc && *esc;
445 int ret = 0;
446
447 while (isz--) {
448 unsigned char c = *src++;
449
450 /*
451 * Apply rules in the following sequence:
452 * - the character is printable, when @flags has
453 * %ESCAPE_NP bit set
454 * - the @esc string is supplied and does not contain a
455 * character under question
456 * - the character doesn't fall into a class of symbols
457 * defined by given @flags
458 * In these cases we just pass through a character to the
459 * output buffer.
460 */
461 if ((flags & ESCAPE_NP && isprint(c)) ||
462 (is_dict && !strchr(esc, c))) {
463 /* do nothing */
464 } else {
465 if (flags & ESCAPE_SPACE) {
466 ret = escape_space(c, &p, &osz);
467 if (ret < 0)
468 break;
469 if (ret > 0)
470 continue;
471 }
472
473 if (flags & ESCAPE_SPECIAL) {
474 ret = escape_special(c, &p, &osz);
475 if (ret < 0)
476 break;
477 if (ret > 0)
478 continue;
479 }
480
481 if (flags & ESCAPE_NULL) {
482 ret = escape_null(c, &p, &osz);
483 if (ret < 0)
484 break;
485 if (ret > 0)
486 continue;
487 }
488
489 /* ESCAPE_OCTAL and ESCAPE_HEX always go last */
490 if (flags & ESCAPE_OCTAL) {
491 ret = escape_octal(c, &p, &osz);
492 if (ret < 0)
493 break;
494 continue;
495 }
496 if (flags & ESCAPE_HEX) {
497 ret = escape_hex(c, &p, &osz);
498 if (ret < 0)
499 break;
500 continue;
501 }
502 }
503
504 ret = escape_passthrough(c, &p, &osz);
505 if (ret < 0)
506 break;
507 }
508
509 *dst = p;
510
511 if (ret < 0)
512 return ret;
513
514 return p - out;
515}
516EXPORT_SYMBOL(string_escape_mem);