Ejemplo n.º 1
0
static char
eat_escape_code(void)
{
    int c, coded_char;

    c = input();

    switch (c) {
      case 0:  /* i.e., EOF */
	unput(c);
	return(c);
      case '\n':
	return(0);
      case 'n':
	return('\n');
      case 't':
	return('\t');
      case 'b':
	return('\b');
      case '0':   case '1':   case '2':   case '3':
      case '4':   case '5':   case '6':   case '7':
	coded_char = c - '0';
	c = input();
	if (!is_octal_digit(c)) {
	    unput(c);
	    return(coded_char);
	}
	coded_char = coded_char*8 + c-'0';
	c = input();
	if (!is_octal_digit(c)) {
	    unput(c);
	    return(coded_char);
	}
	return(coded_char*8 + c-'0');
      default:
	return(c);
    }
}
Ejemplo n.º 2
0
/* Print a \ escape sequence starting at ESCSTART.
   Return the number of characters in the escape sequence
   besides the backslash.
   If OCTAL_0 is nonzero, octal escapes are of the form \0ooo, where o
   is an octal digit; otherwise they are of the form \ooo.  */
long builtin_printf_state_t::print_esc(const wchar_t *escstart, bool octal_0)
{
    const wchar_t *p = escstart + 1;
    int esc_value = 0;		/* Value of \nnn escape. */
    int esc_length;		/* Length of \nnn escape. */

    if (*p == L'x')
    {
        /* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits.  */
        for (esc_length = 0, ++p; esc_length < 2 && is_hex_digit(*p); ++esc_length, ++p)
            esc_value = esc_value * 16 + hex_to_bin(*p);
        if (esc_length == 0)
            this->fatal_error(_(L"missing hexadecimal number in escape"));
        this->append_format_output(L"%lc", esc_value);
    }
    else if (is_octal_digit(*p))
    {
        /* Parse \0ooo (if octal_0 && *p == L'0') or \ooo (otherwise).
        Allow \ooo if octal_0 && *p != L'0'; this is an undocumented
        extension to POSIX that is compatible with Bash 2.05b.  */
        for (esc_length = 0, p += octal_0 && *p == L'0'; esc_length < 3 && is_octal_digit(*p); ++esc_length, ++p)
            esc_value = esc_value * 8 + octal_to_bin(*p);
        this->append_format_output(L"%c", esc_value);
    }
    else if (*p && wcschr(L"\"\\abcfnrtv", *p))
        print_esc_char(*p++);
    else if (*p == L'u' || *p == L'U')
    {
        wchar_t esc_char = *p;
        p++;
        uint32_t uni_value = 0;
        for (size_t esc_length = 0; esc_length < (esc_char == L'u' ? 4 : 8); esc_length++)
        {
            if (! is_hex_digit(*p))
            {
                /* Escape sequence must be done. Complain if we didn't get anything */
                if (esc_length == 0)
                {
                    this->fatal_error(_(L"Missing hexadecimal number in Unicode escape"));
                }
                break;
            }
            uni_value = uni_value * 16 + hex_to_bin(*p);
            p++;
        }
        
        /* PCA GNU printf respects the limitations described in ISO N717, about which universal characters "shall not" be specified. I believe this limitation is for the benefit of compilers; I see no reason to impose it in builtin_printf.
        
          If __STDC_ISO_10646__ is defined, then it means wchar_t can and does hold Unicode code points, so just use that. If not defined, use the %lc printf conversion; this probably won't do anything good if your wide character set is not Unicode, but such platforms are exceedingly rare.
        */
        if (uni_value > 0x10FFFF)
        {
            this->fatal_error(_(L"Unicode character out of range: \\%c%0*x"), esc_char, (esc_char == L'u' ? 4 : 8), uni_value);
        }
        else
        {
#if defined(__STDC_ISO_10646__)
            this->append_output(uni_value);
#else
            this->append_format_output(L"%lc", uni_value);
        }
#endif
    }
    else
    {
        this->append_format_output(L"%lc", L'\\');
        if (*p)
        {
            this->append_format_output(L"%lc", *p);
            p++;
        }
    }
    return p - escstart - 1;
}
Ejemplo n.º 3
0
static bool is_escape_char(char const *& s, unsigned& result) {
    unsigned d1, d2, d3;
    if (*s != '\\' || *(s + 1) == 0) {
        return false;
    }
    if (*(s + 1) == 'x' &&
        is_hex_digit(*(s + 2), d1) && is_hex_digit(*(s + 3), d2)) {
        result = d1*16 + d2;
        s += 4;
        return true;
    }
    /* C-standard octal escapes: either 1, 2, or 3 octal digits,
     * stopping either at 3 digits or at the first non-digit character.
     */
    /* 1 octal digit */
    if (is_octal_digit(*(s + 1), d1) && !is_octal_digit(*(s + 2), d2)) {
        result = d1;
        s += 2;
        return true;
    }
    /* 2 octal digits */
    if (is_octal_digit(*(s + 1), d1) && is_octal_digit(*(s + 2), d2) &&
            !is_octal_digit(*(s + 3), d3)) {
        result = d1 * 8 + d2;
        s += 3;
        return true;
    }
    /* 3 octal digits */
    if (is_octal_digit(*(s + 1), d1) && is_octal_digit(*(s + 2), d2) &&
            is_octal_digit(*(s + 3), d3)) {
        result = d1*64 + d2*8 + d3;
        s += 4;
        return true;
    }
    switch (*(s + 1)) {
    case 'a':
        result = '\a';
        s += 2;
        return true;
    case 'b':
        result = '\b';
        s += 2;
        return true;
#if 0
    case 'e':
        result = '\e';
        s += 2;
        return true;
#endif
    case 'f':
        result = '\f';
        s += 2;
        return true;
    case 'n':
        result = '\n';
        s += 2;
        return true;
    case 'r':
        result = '\r';
        s += 2;
        return true;
    case 't':
        result = '\t';
        s += 2;
        return true;
    case 'v':
        result = '\v';
        s += 2;
        return true;
    default:
        result = *(s + 1);
        s += 2;
        return true;
    }
    return false;
}