13c9f3681SJames Bottomley /* 23c9f3681SJames Bottomley * Helpers for formatting and printing strings 33c9f3681SJames Bottomley * 43c9f3681SJames Bottomley * Copyright 31 August 2008 James Bottomley 516c7fa05SAndy Shevchenko * Copyright (C) 2013, Intel Corporation 63c9f3681SJames Bottomley */ 73c9f3681SJames Bottomley #include <linux/kernel.h> 83c9f3681SJames Bottomley #include <linux/math64.h> 98bc3bcc9SPaul Gortmaker #include <linux/export.h> 1016c7fa05SAndy Shevchenko #include <linux/ctype.h> 11c8250381SAndy Shevchenko #include <linux/errno.h> 12c8250381SAndy Shevchenko #include <linux/string.h> 133c9f3681SJames Bottomley #include <linux/string_helpers.h> 143c9f3681SJames Bottomley 153c9f3681SJames Bottomley /** 163c9f3681SJames Bottomley * string_get_size - get the size in the specified units 173c9f3681SJames Bottomley * @size: The size to be converted 183c9f3681SJames Bottomley * @units: units to use (powers of 1000 or 1024) 193c9f3681SJames Bottomley * @buf: buffer to format to 203c9f3681SJames Bottomley * @len: length of buffer 213c9f3681SJames Bottomley * 223c9f3681SJames Bottomley * This function returns a string formatted to 3 significant figures 23*d1214c65SRasmus Villemoes * giving the size in the required units. @buf should have room for 24*d1214c65SRasmus Villemoes * at least 9 bytes and will always be zero terminated. 253c9f3681SJames Bottomley * 263c9f3681SJames Bottomley */ 27*d1214c65SRasmus Villemoes void string_get_size(u64 size, const enum string_size_units units, 283c9f3681SJames Bottomley char *buf, int len) 293c9f3681SJames Bottomley { 30142cda5dSMathias Krause static const char *const units_10[] = { 317eed8fdeSRasmus Villemoes "B", "kB", "MB", "GB", "TB", "PB", "EB" 32142cda5dSMathias Krause }; 33142cda5dSMathias Krause static const char *const units_2[] = { 347eed8fdeSRasmus Villemoes "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" 35142cda5dSMathias Krause }; 36142cda5dSMathias Krause static const char *const *const units_str[] = { 373c9f3681SJames Bottomley [STRING_UNITS_10] = units_10, 383c9f3681SJames Bottomley [STRING_UNITS_2] = units_2, 393c9f3681SJames Bottomley }; 4068aecfb9SAndrew Morton static const unsigned int divisor[] = { 413c9f3681SJames Bottomley [STRING_UNITS_10] = 1000, 423c9f3681SJames Bottomley [STRING_UNITS_2] = 1024, 433c9f3681SJames Bottomley }; 443c9f3681SJames Bottomley int i, j; 4584b9fbedSRasmus Villemoes u32 remainder = 0, sf_cap; 463c9f3681SJames Bottomley char tmp[8]; 473c9f3681SJames Bottomley 483c9f3681SJames Bottomley tmp[0] = '\0'; 49a8659597SH. Peter Anvin i = 0; 50a8659597SH. Peter Anvin if (size >= divisor[units]) { 517eed8fdeSRasmus Villemoes while (size >= divisor[units]) { 523c9f3681SJames Bottomley remainder = do_div(size, divisor[units]); 53a8659597SH. Peter Anvin i++; 54a8659597SH. Peter Anvin } 553c9f3681SJames Bottomley 563c9f3681SJames Bottomley sf_cap = size; 573c9f3681SJames Bottomley for (j = 0; sf_cap*10 < 1000; j++) 583c9f3681SJames Bottomley sf_cap *= 10; 593c9f3681SJames Bottomley 603c9f3681SJames Bottomley if (j) { 613c9f3681SJames Bottomley remainder *= 1000; 6284b9fbedSRasmus Villemoes remainder /= divisor[units]; 6384b9fbedSRasmus Villemoes snprintf(tmp, sizeof(tmp), ".%03u", remainder); 643c9f3681SJames Bottomley tmp[j+1] = '\0'; 653c9f3681SJames Bottomley } 66a8659597SH. Peter Anvin } 673c9f3681SJames Bottomley 6884b9fbedSRasmus Villemoes snprintf(buf, len, "%u%s %s", (u32)size, 693c9f3681SJames Bottomley tmp, units_str[units][i]); 703c9f3681SJames Bottomley } 713c9f3681SJames Bottomley EXPORT_SYMBOL(string_get_size); 7216c7fa05SAndy Shevchenko 7316c7fa05SAndy Shevchenko static bool unescape_space(char **src, char **dst) 7416c7fa05SAndy Shevchenko { 7516c7fa05SAndy Shevchenko char *p = *dst, *q = *src; 7616c7fa05SAndy Shevchenko 7716c7fa05SAndy Shevchenko switch (*q) { 7816c7fa05SAndy Shevchenko case 'n': 7916c7fa05SAndy Shevchenko *p = '\n'; 8016c7fa05SAndy Shevchenko break; 8116c7fa05SAndy Shevchenko case 'r': 8216c7fa05SAndy Shevchenko *p = '\r'; 8316c7fa05SAndy Shevchenko break; 8416c7fa05SAndy Shevchenko case 't': 8516c7fa05SAndy Shevchenko *p = '\t'; 8616c7fa05SAndy Shevchenko break; 8716c7fa05SAndy Shevchenko case 'v': 8816c7fa05SAndy Shevchenko *p = '\v'; 8916c7fa05SAndy Shevchenko break; 9016c7fa05SAndy Shevchenko case 'f': 9116c7fa05SAndy Shevchenko *p = '\f'; 9216c7fa05SAndy Shevchenko break; 9316c7fa05SAndy Shevchenko default: 9416c7fa05SAndy Shevchenko return false; 9516c7fa05SAndy Shevchenko } 9616c7fa05SAndy Shevchenko *dst += 1; 9716c7fa05SAndy Shevchenko *src += 1; 9816c7fa05SAndy Shevchenko return true; 9916c7fa05SAndy Shevchenko } 10016c7fa05SAndy Shevchenko 10116c7fa05SAndy Shevchenko static bool unescape_octal(char **src, char **dst) 10216c7fa05SAndy Shevchenko { 10316c7fa05SAndy Shevchenko char *p = *dst, *q = *src; 10416c7fa05SAndy Shevchenko u8 num; 10516c7fa05SAndy Shevchenko 10616c7fa05SAndy Shevchenko if (isodigit(*q) == 0) 10716c7fa05SAndy Shevchenko return false; 10816c7fa05SAndy Shevchenko 10916c7fa05SAndy Shevchenko num = (*q++) & 7; 11016c7fa05SAndy Shevchenko while (num < 32 && isodigit(*q) && (q - *src < 3)) { 11116c7fa05SAndy Shevchenko num <<= 3; 11216c7fa05SAndy Shevchenko num += (*q++) & 7; 11316c7fa05SAndy Shevchenko } 11416c7fa05SAndy Shevchenko *p = num; 11516c7fa05SAndy Shevchenko *dst += 1; 11616c7fa05SAndy Shevchenko *src = q; 11716c7fa05SAndy Shevchenko return true; 11816c7fa05SAndy Shevchenko } 11916c7fa05SAndy Shevchenko 12016c7fa05SAndy Shevchenko static bool unescape_hex(char **src, char **dst) 12116c7fa05SAndy Shevchenko { 12216c7fa05SAndy Shevchenko char *p = *dst, *q = *src; 12316c7fa05SAndy Shevchenko int digit; 12416c7fa05SAndy Shevchenko u8 num; 12516c7fa05SAndy Shevchenko 12616c7fa05SAndy Shevchenko if (*q++ != 'x') 12716c7fa05SAndy Shevchenko return false; 12816c7fa05SAndy Shevchenko 12916c7fa05SAndy Shevchenko num = digit = hex_to_bin(*q++); 13016c7fa05SAndy Shevchenko if (digit < 0) 13116c7fa05SAndy Shevchenko return false; 13216c7fa05SAndy Shevchenko 13316c7fa05SAndy Shevchenko digit = hex_to_bin(*q); 13416c7fa05SAndy Shevchenko if (digit >= 0) { 13516c7fa05SAndy Shevchenko q++; 13616c7fa05SAndy Shevchenko num = (num << 4) | digit; 13716c7fa05SAndy Shevchenko } 13816c7fa05SAndy Shevchenko *p = num; 13916c7fa05SAndy Shevchenko *dst += 1; 14016c7fa05SAndy Shevchenko *src = q; 14116c7fa05SAndy Shevchenko return true; 14216c7fa05SAndy Shevchenko } 14316c7fa05SAndy Shevchenko 14416c7fa05SAndy Shevchenko static bool unescape_special(char **src, char **dst) 14516c7fa05SAndy Shevchenko { 14616c7fa05SAndy Shevchenko char *p = *dst, *q = *src; 14716c7fa05SAndy Shevchenko 14816c7fa05SAndy Shevchenko switch (*q) { 14916c7fa05SAndy Shevchenko case '\"': 15016c7fa05SAndy Shevchenko *p = '\"'; 15116c7fa05SAndy Shevchenko break; 15216c7fa05SAndy Shevchenko case '\\': 15316c7fa05SAndy Shevchenko *p = '\\'; 15416c7fa05SAndy Shevchenko break; 15516c7fa05SAndy Shevchenko case 'a': 15616c7fa05SAndy Shevchenko *p = '\a'; 15716c7fa05SAndy Shevchenko break; 15816c7fa05SAndy Shevchenko case 'e': 15916c7fa05SAndy Shevchenko *p = '\e'; 16016c7fa05SAndy Shevchenko break; 16116c7fa05SAndy Shevchenko default: 16216c7fa05SAndy Shevchenko return false; 16316c7fa05SAndy Shevchenko } 16416c7fa05SAndy Shevchenko *dst += 1; 16516c7fa05SAndy Shevchenko *src += 1; 16616c7fa05SAndy Shevchenko return true; 16716c7fa05SAndy Shevchenko } 16816c7fa05SAndy Shevchenko 169d295634eSAndy Shevchenko /** 170d295634eSAndy Shevchenko * string_unescape - unquote characters in the given string 171d295634eSAndy Shevchenko * @src: source buffer (escaped) 172d295634eSAndy Shevchenko * @dst: destination buffer (unescaped) 173d295634eSAndy Shevchenko * @size: size of the destination buffer (0 to unlimit) 174d295634eSAndy Shevchenko * @flags: combination of the flags (bitwise OR): 175d295634eSAndy Shevchenko * %UNESCAPE_SPACE: 176d295634eSAndy Shevchenko * '\f' - form feed 177d295634eSAndy Shevchenko * '\n' - new line 178d295634eSAndy Shevchenko * '\r' - carriage return 179d295634eSAndy Shevchenko * '\t' - horizontal tab 180d295634eSAndy Shevchenko * '\v' - vertical tab 181d295634eSAndy Shevchenko * %UNESCAPE_OCTAL: 182d295634eSAndy Shevchenko * '\NNN' - byte with octal value NNN (1 to 3 digits) 183d295634eSAndy Shevchenko * %UNESCAPE_HEX: 184d295634eSAndy Shevchenko * '\xHH' - byte with hexadecimal value HH (1 to 2 digits) 185d295634eSAndy Shevchenko * %UNESCAPE_SPECIAL: 186d295634eSAndy Shevchenko * '\"' - double quote 187d295634eSAndy Shevchenko * '\\' - backslash 188d295634eSAndy Shevchenko * '\a' - alert (BEL) 189d295634eSAndy Shevchenko * '\e' - escape 190d295634eSAndy Shevchenko * %UNESCAPE_ANY: 191d295634eSAndy Shevchenko * all previous together 192d295634eSAndy Shevchenko * 193d295634eSAndy Shevchenko * Description: 194d295634eSAndy Shevchenko * The function unquotes characters in the given string. 195d295634eSAndy Shevchenko * 196d295634eSAndy Shevchenko * Because the size of the output will be the same as or less than the size of 197d295634eSAndy Shevchenko * the input, the transformation may be performed in place. 198d295634eSAndy Shevchenko * 199d295634eSAndy Shevchenko * Caller must provide valid source and destination pointers. Be aware that 200d295634eSAndy Shevchenko * destination buffer will always be NULL-terminated. Source string must be 201d295634eSAndy Shevchenko * NULL-terminated as well. 202d295634eSAndy Shevchenko * 203d295634eSAndy Shevchenko * Return: 204d295634eSAndy Shevchenko * The amount of the characters processed to the destination buffer excluding 205d295634eSAndy Shevchenko * trailing '\0' is returned. 206d295634eSAndy Shevchenko */ 20716c7fa05SAndy Shevchenko int string_unescape(char *src, char *dst, size_t size, unsigned int flags) 20816c7fa05SAndy Shevchenko { 20916c7fa05SAndy Shevchenko char *out = dst; 21016c7fa05SAndy Shevchenko 21116c7fa05SAndy Shevchenko while (*src && --size) { 21216c7fa05SAndy Shevchenko if (src[0] == '\\' && src[1] != '\0' && size > 1) { 21316c7fa05SAndy Shevchenko src++; 21416c7fa05SAndy Shevchenko size--; 21516c7fa05SAndy Shevchenko 21616c7fa05SAndy Shevchenko if (flags & UNESCAPE_SPACE && 21716c7fa05SAndy Shevchenko unescape_space(&src, &out)) 21816c7fa05SAndy Shevchenko continue; 21916c7fa05SAndy Shevchenko 22016c7fa05SAndy Shevchenko if (flags & UNESCAPE_OCTAL && 22116c7fa05SAndy Shevchenko unescape_octal(&src, &out)) 22216c7fa05SAndy Shevchenko continue; 22316c7fa05SAndy Shevchenko 22416c7fa05SAndy Shevchenko if (flags & UNESCAPE_HEX && 22516c7fa05SAndy Shevchenko unescape_hex(&src, &out)) 22616c7fa05SAndy Shevchenko continue; 22716c7fa05SAndy Shevchenko 22816c7fa05SAndy Shevchenko if (flags & UNESCAPE_SPECIAL && 22916c7fa05SAndy Shevchenko unescape_special(&src, &out)) 23016c7fa05SAndy Shevchenko continue; 23116c7fa05SAndy Shevchenko 23216c7fa05SAndy Shevchenko *out++ = '\\'; 23316c7fa05SAndy Shevchenko } 23416c7fa05SAndy Shevchenko *out++ = *src++; 23516c7fa05SAndy Shevchenko } 23616c7fa05SAndy Shevchenko *out = '\0'; 23716c7fa05SAndy Shevchenko 23816c7fa05SAndy Shevchenko return out - dst; 23916c7fa05SAndy Shevchenko } 24016c7fa05SAndy Shevchenko EXPORT_SYMBOL(string_unescape); 241c8250381SAndy Shevchenko 242c8250381SAndy Shevchenko static int escape_passthrough(unsigned char c, char **dst, size_t *osz) 243c8250381SAndy Shevchenko { 244c8250381SAndy Shevchenko char *out = *dst; 245c8250381SAndy Shevchenko 246c8250381SAndy Shevchenko if (*osz < 1) 247c8250381SAndy Shevchenko return -ENOMEM; 248c8250381SAndy Shevchenko 249c8250381SAndy Shevchenko *out++ = c; 250c8250381SAndy Shevchenko 251c8250381SAndy Shevchenko *dst = out; 252c8250381SAndy Shevchenko *osz -= 1; 253c8250381SAndy Shevchenko 254c8250381SAndy Shevchenko return 1; 255c8250381SAndy Shevchenko } 256c8250381SAndy Shevchenko 257c8250381SAndy Shevchenko static int escape_space(unsigned char c, char **dst, size_t *osz) 258c8250381SAndy Shevchenko { 259c8250381SAndy Shevchenko char *out = *dst; 260c8250381SAndy Shevchenko unsigned char to; 261c8250381SAndy Shevchenko 262c8250381SAndy Shevchenko if (*osz < 2) 263c8250381SAndy Shevchenko return -ENOMEM; 264c8250381SAndy Shevchenko 265c8250381SAndy Shevchenko switch (c) { 266c8250381SAndy Shevchenko case '\n': 267c8250381SAndy Shevchenko to = 'n'; 268c8250381SAndy Shevchenko break; 269c8250381SAndy Shevchenko case '\r': 270c8250381SAndy Shevchenko to = 'r'; 271c8250381SAndy Shevchenko break; 272c8250381SAndy Shevchenko case '\t': 273c8250381SAndy Shevchenko to = 't'; 274c8250381SAndy Shevchenko break; 275c8250381SAndy Shevchenko case '\v': 276c8250381SAndy Shevchenko to = 'v'; 277c8250381SAndy Shevchenko break; 278c8250381SAndy Shevchenko case '\f': 279c8250381SAndy Shevchenko to = 'f'; 280c8250381SAndy Shevchenko break; 281c8250381SAndy Shevchenko default: 282c8250381SAndy Shevchenko return 0; 283c8250381SAndy Shevchenko } 284c8250381SAndy Shevchenko 285c8250381SAndy Shevchenko *out++ = '\\'; 286c8250381SAndy Shevchenko *out++ = to; 287c8250381SAndy Shevchenko 288c8250381SAndy Shevchenko *dst = out; 289c8250381SAndy Shevchenko *osz -= 2; 290c8250381SAndy Shevchenko 291c8250381SAndy Shevchenko return 1; 292c8250381SAndy Shevchenko } 293c8250381SAndy Shevchenko 294c8250381SAndy Shevchenko static int escape_special(unsigned char c, char **dst, size_t *osz) 295c8250381SAndy Shevchenko { 296c8250381SAndy Shevchenko char *out = *dst; 297c8250381SAndy Shevchenko unsigned char to; 298c8250381SAndy Shevchenko 299c8250381SAndy Shevchenko if (*osz < 2) 300c8250381SAndy Shevchenko return -ENOMEM; 301c8250381SAndy Shevchenko 302c8250381SAndy Shevchenko switch (c) { 303c8250381SAndy Shevchenko case '\\': 304c8250381SAndy Shevchenko to = '\\'; 305c8250381SAndy Shevchenko break; 306c8250381SAndy Shevchenko case '\a': 307c8250381SAndy Shevchenko to = 'a'; 308c8250381SAndy Shevchenko break; 309c8250381SAndy Shevchenko case '\e': 310c8250381SAndy Shevchenko to = 'e'; 311c8250381SAndy Shevchenko break; 312c8250381SAndy Shevchenko default: 313c8250381SAndy Shevchenko return 0; 314c8250381SAndy Shevchenko } 315c8250381SAndy Shevchenko 316c8250381SAndy Shevchenko *out++ = '\\'; 317c8250381SAndy Shevchenko *out++ = to; 318c8250381SAndy Shevchenko 319c8250381SAndy Shevchenko *dst = out; 320c8250381SAndy Shevchenko *osz -= 2; 321c8250381SAndy Shevchenko 322c8250381SAndy Shevchenko return 1; 323c8250381SAndy Shevchenko } 324c8250381SAndy Shevchenko 325c8250381SAndy Shevchenko static int escape_null(unsigned char c, char **dst, size_t *osz) 326c8250381SAndy Shevchenko { 327c8250381SAndy Shevchenko char *out = *dst; 328c8250381SAndy Shevchenko 329c8250381SAndy Shevchenko if (*osz < 2) 330c8250381SAndy Shevchenko return -ENOMEM; 331c8250381SAndy Shevchenko 332c8250381SAndy Shevchenko if (c) 333c8250381SAndy Shevchenko return 0; 334c8250381SAndy Shevchenko 335c8250381SAndy Shevchenko *out++ = '\\'; 336c8250381SAndy Shevchenko *out++ = '0'; 337c8250381SAndy Shevchenko 338c8250381SAndy Shevchenko *dst = out; 339c8250381SAndy Shevchenko *osz -= 2; 340c8250381SAndy Shevchenko 341c8250381SAndy Shevchenko return 1; 342c8250381SAndy Shevchenko } 343c8250381SAndy Shevchenko 344c8250381SAndy Shevchenko static int escape_octal(unsigned char c, char **dst, size_t *osz) 345c8250381SAndy Shevchenko { 346c8250381SAndy Shevchenko char *out = *dst; 347c8250381SAndy Shevchenko 348c8250381SAndy Shevchenko if (*osz < 4) 349c8250381SAndy Shevchenko return -ENOMEM; 350c8250381SAndy Shevchenko 351c8250381SAndy Shevchenko *out++ = '\\'; 352c8250381SAndy Shevchenko *out++ = ((c >> 6) & 0x07) + '0'; 353c8250381SAndy Shevchenko *out++ = ((c >> 3) & 0x07) + '0'; 354c8250381SAndy Shevchenko *out++ = ((c >> 0) & 0x07) + '0'; 355c8250381SAndy Shevchenko 356c8250381SAndy Shevchenko *dst = out; 357c8250381SAndy Shevchenko *osz -= 4; 358c8250381SAndy Shevchenko 359c8250381SAndy Shevchenko return 1; 360c8250381SAndy Shevchenko } 361c8250381SAndy Shevchenko 362c8250381SAndy Shevchenko static int escape_hex(unsigned char c, char **dst, size_t *osz) 363c8250381SAndy Shevchenko { 364c8250381SAndy Shevchenko char *out = *dst; 365c8250381SAndy Shevchenko 366c8250381SAndy Shevchenko if (*osz < 4) 367c8250381SAndy Shevchenko return -ENOMEM; 368c8250381SAndy Shevchenko 369c8250381SAndy Shevchenko *out++ = '\\'; 370c8250381SAndy Shevchenko *out++ = 'x'; 371c8250381SAndy Shevchenko *out++ = hex_asc_hi(c); 372c8250381SAndy Shevchenko *out++ = hex_asc_lo(c); 373c8250381SAndy Shevchenko 374c8250381SAndy Shevchenko *dst = out; 375c8250381SAndy Shevchenko *osz -= 4; 376c8250381SAndy Shevchenko 377c8250381SAndy Shevchenko return 1; 378c8250381SAndy Shevchenko } 379c8250381SAndy Shevchenko 380c8250381SAndy Shevchenko /** 381c8250381SAndy Shevchenko * string_escape_mem - quote characters in the given memory buffer 382c8250381SAndy Shevchenko * @src: source buffer (unescaped) 383c8250381SAndy Shevchenko * @isz: source buffer size 384c8250381SAndy Shevchenko * @dst: destination buffer (escaped) 385c8250381SAndy Shevchenko * @osz: destination buffer size 386c8250381SAndy Shevchenko * @flags: combination of the flags (bitwise OR): 387c8250381SAndy Shevchenko * %ESCAPE_SPACE: 388c8250381SAndy Shevchenko * '\f' - form feed 389c8250381SAndy Shevchenko * '\n' - new line 390c8250381SAndy Shevchenko * '\r' - carriage return 391c8250381SAndy Shevchenko * '\t' - horizontal tab 392c8250381SAndy Shevchenko * '\v' - vertical tab 393c8250381SAndy Shevchenko * %ESCAPE_SPECIAL: 394c8250381SAndy Shevchenko * '\\' - backslash 395c8250381SAndy Shevchenko * '\a' - alert (BEL) 396c8250381SAndy Shevchenko * '\e' - escape 397c8250381SAndy Shevchenko * %ESCAPE_NULL: 398c8250381SAndy Shevchenko * '\0' - null 399c8250381SAndy Shevchenko * %ESCAPE_OCTAL: 400c8250381SAndy Shevchenko * '\NNN' - byte with octal value NNN (3 digits) 401c8250381SAndy Shevchenko * %ESCAPE_ANY: 402c8250381SAndy Shevchenko * all previous together 403c8250381SAndy Shevchenko * %ESCAPE_NP: 404c8250381SAndy Shevchenko * escape only non-printable characters (checked by isprint) 405c8250381SAndy Shevchenko * %ESCAPE_ANY_NP: 406c8250381SAndy Shevchenko * all previous together 407c8250381SAndy Shevchenko * %ESCAPE_HEX: 408c8250381SAndy Shevchenko * '\xHH' - byte with hexadecimal value HH (2 digits) 409c8250381SAndy Shevchenko * @esc: NULL-terminated string of characters any of which, if found in 410c8250381SAndy Shevchenko * the source, has to be escaped 411c8250381SAndy Shevchenko * 412c8250381SAndy Shevchenko * Description: 413c8250381SAndy Shevchenko * The process of escaping byte buffer includes several parts. They are applied 414c8250381SAndy Shevchenko * in the following sequence. 415c8250381SAndy Shevchenko * 1. The character is matched to the printable class, if asked, and in 416c8250381SAndy Shevchenko * case of match it passes through to the output. 417c8250381SAndy Shevchenko * 2. The character is not matched to the one from @esc string and thus 418c8250381SAndy Shevchenko * must go as is to the output. 419c8250381SAndy Shevchenko * 3. The character is checked if it falls into the class given by @flags. 420c8250381SAndy Shevchenko * %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any 421c8250381SAndy Shevchenko * character. Note that they actually can't go together, otherwise 422c8250381SAndy Shevchenko * %ESCAPE_HEX will be ignored. 423c8250381SAndy Shevchenko * 424c8250381SAndy Shevchenko * Caller must provide valid source and destination pointers. Be aware that 425c8250381SAndy Shevchenko * destination buffer will not be NULL-terminated, thus caller have to append 426c8250381SAndy Shevchenko * it if needs. 427c8250381SAndy Shevchenko * 428c8250381SAndy Shevchenko * Return: 429c8250381SAndy Shevchenko * The amount of the characters processed to the destination buffer, or 430c8250381SAndy Shevchenko * %-ENOMEM if the size of buffer is not enough to put an escaped character is 431c8250381SAndy Shevchenko * returned. 432c8250381SAndy Shevchenko * 433c8250381SAndy Shevchenko * Even in the case of error @dst pointer will be updated to point to the byte 434c8250381SAndy Shevchenko * after the last processed character. 435c8250381SAndy Shevchenko */ 436c8250381SAndy Shevchenko int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, 437c8250381SAndy Shevchenko unsigned int flags, const char *esc) 438c8250381SAndy Shevchenko { 439c8250381SAndy Shevchenko char *out = *dst, *p = out; 440c8250381SAndy Shevchenko bool is_dict = esc && *esc; 441c8250381SAndy Shevchenko int ret = 0; 442c8250381SAndy Shevchenko 443c8250381SAndy Shevchenko while (isz--) { 444c8250381SAndy Shevchenko unsigned char c = *src++; 445c8250381SAndy Shevchenko 446c8250381SAndy Shevchenko /* 447c8250381SAndy Shevchenko * Apply rules in the following sequence: 448c8250381SAndy Shevchenko * - the character is printable, when @flags has 449c8250381SAndy Shevchenko * %ESCAPE_NP bit set 450c8250381SAndy Shevchenko * - the @esc string is supplied and does not contain a 451c8250381SAndy Shevchenko * character under question 452c8250381SAndy Shevchenko * - the character doesn't fall into a class of symbols 453c8250381SAndy Shevchenko * defined by given @flags 454c8250381SAndy Shevchenko * In these cases we just pass through a character to the 455c8250381SAndy Shevchenko * output buffer. 456c8250381SAndy Shevchenko */ 457c8250381SAndy Shevchenko if ((flags & ESCAPE_NP && isprint(c)) || 458c8250381SAndy Shevchenko (is_dict && !strchr(esc, c))) { 459c8250381SAndy Shevchenko /* do nothing */ 460c8250381SAndy Shevchenko } else { 461c8250381SAndy Shevchenko if (flags & ESCAPE_SPACE) { 462c8250381SAndy Shevchenko ret = escape_space(c, &p, &osz); 463c8250381SAndy Shevchenko if (ret < 0) 464c8250381SAndy Shevchenko break; 465c8250381SAndy Shevchenko if (ret > 0) 466c8250381SAndy Shevchenko continue; 467c8250381SAndy Shevchenko } 468c8250381SAndy Shevchenko 469c8250381SAndy Shevchenko if (flags & ESCAPE_SPECIAL) { 470c8250381SAndy Shevchenko ret = escape_special(c, &p, &osz); 471c8250381SAndy Shevchenko if (ret < 0) 472c8250381SAndy Shevchenko break; 473c8250381SAndy Shevchenko if (ret > 0) 474c8250381SAndy Shevchenko continue; 475c8250381SAndy Shevchenko } 476c8250381SAndy Shevchenko 477c8250381SAndy Shevchenko if (flags & ESCAPE_NULL) { 478c8250381SAndy Shevchenko ret = escape_null(c, &p, &osz); 479c8250381SAndy Shevchenko if (ret < 0) 480c8250381SAndy Shevchenko break; 481c8250381SAndy Shevchenko if (ret > 0) 482c8250381SAndy Shevchenko continue; 483c8250381SAndy Shevchenko } 484c8250381SAndy Shevchenko 485c8250381SAndy Shevchenko /* ESCAPE_OCTAL and ESCAPE_HEX always go last */ 486c8250381SAndy Shevchenko if (flags & ESCAPE_OCTAL) { 487c8250381SAndy Shevchenko ret = escape_octal(c, &p, &osz); 488c8250381SAndy Shevchenko if (ret < 0) 489c8250381SAndy Shevchenko break; 490c8250381SAndy Shevchenko continue; 491c8250381SAndy Shevchenko } 492c8250381SAndy Shevchenko if (flags & ESCAPE_HEX) { 493c8250381SAndy Shevchenko ret = escape_hex(c, &p, &osz); 494c8250381SAndy Shevchenko if (ret < 0) 495c8250381SAndy Shevchenko break; 496c8250381SAndy Shevchenko continue; 497c8250381SAndy Shevchenko } 498c8250381SAndy Shevchenko } 499c8250381SAndy Shevchenko 500c8250381SAndy Shevchenko ret = escape_passthrough(c, &p, &osz); 501c8250381SAndy Shevchenko if (ret < 0) 502c8250381SAndy Shevchenko break; 503c8250381SAndy Shevchenko } 504c8250381SAndy Shevchenko 505c8250381SAndy Shevchenko *dst = p; 506c8250381SAndy Shevchenko 507c8250381SAndy Shevchenko if (ret < 0) 508c8250381SAndy Shevchenko return ret; 509c8250381SAndy Shevchenko 510c8250381SAndy Shevchenko return p - out; 511c8250381SAndy Shevchenko } 512c8250381SAndy Shevchenko EXPORT_SYMBOL(string_escape_mem); 513