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