#include "EXTERN.h"
#define PERL_IN_DQUOTE_C
#include "perl.h"
bool
Perl_grok_bslash_c(pTHX_
const
char
source,
U8 * result,
const
char
** message,
U32 * packed_warn)
{
PERL_ARGS_ASSERT_GROK_BSLASH_C;
*message = NULL;
if
(packed_warn) *packed_warn = 0;
if
(! isPRINT_A(source)) {
*message =
"Character following \"\\c\" must be printable ASCII"
;
return
FALSE;
}
if
(source ==
'{'
) {
const
char
control = toCTRL(
'{'
);
if
(isPRINT_A(control)) {
*message = Perl_form(aTHX_ PERL_DIAG_DIE_SYNTAX(
"Use \"%c\" instead of \"\\c{\""
), control);
}
else
{
*message =
"Sequence \"\\c{\" invalid"
;
}
return
FALSE;
}
*result = toCTRL(source);
if
(isPRINT_A(*result) && ckWARN(WARN_SYNTAX)) {
U8 clearer[3];
U8 i = 0;
char
format[] = PERL_DIAG_WARN_SYNTAX(
"\"\\c%c\" is more clearly written simply as \"%s\""
);
if
(! isWORDCHAR(*result)) {
clearer[i++] =
'\\'
;
}
clearer[i++] = *result;
clearer[i++] =
'\0'
;
if
(packed_warn) {
*message = Perl_form(aTHX_ format, source, clearer);
*packed_warn = packWARN(WARN_SYNTAX);
}
else
{
Perl_warner(aTHX_ packWARN(WARN_SYNTAX), format, source, clearer);
}
}
return
TRUE;
}
const
char
*
Perl_form_alien_digit_msg(pTHX_
const
U8 which,
const
STRLEN valids_len,
const
char
*
const
first_bad,
const
char
*
const
send,
const
bool
UTF,
const
bool
braced)
{
SV * display_char = newSV(2 * UTF8_MAXBYTES + 4);
SV * message_sv = sv_newmortal();
char
symbol;
PERL_ARGS_ASSERT_FORM_ALIEN_DIGIT_MSG;
assert
(which == 8 || which == 16);
if
( UVCHR_IS_INVARIANT(*first_bad)
|| (UTF && isUTF8_CHAR((U8 *) first_bad, (U8 *) send)))
{
pv_uni_display(display_char, (U8 *) first_bad, UTF8SKIP(first_bad),
(STRLEN) -1, UNI_DISPLAY_QQ);
}
else
{
Perl_sv_setpvf(aTHX_ display_char,
"\\x{%02x}"
, *first_bad);
}
sv_setpvs(message_sv,
"Non-"
);
if
(which == 8) {
sv_catpvs(message_sv,
"octal"
);
if
(braced) {
symbol =
'o'
;
}
else
{
symbol =
'0'
;
}
}
else
{
sv_catpvs(message_sv,
"hex"
);
symbol =
'x'
;
}
sv_catpvs(message_sv,
" character "
);
if
(isPRINT(*first_bad)) {
sv_catpvs(message_sv,
"'"
);
}
sv_catsv(message_sv, display_char);
if
(isPRINT(*first_bad)) {
sv_catpvs(message_sv,
"'"
);
}
Perl_sv_catpvf(aTHX_ message_sv,
" terminates \\%c early. Resolved as "
"\"\\%c"
, symbol, symbol);
if
(braced) {
sv_catpvs(message_sv,
"{"
);
}
if
(symbol ==
'o'
&& valids_len < 3) {
sv_catpvs(message_sv,
"0"
);
}
if
(valids_len == 0) {
sv_catpvs(message_sv,
"00"
);
}
else
if
(valids_len == 1) {
sv_catpvs(message_sv,
"0"
);
}
sv_catpvn(message_sv, first_bad - valids_len, valids_len);
if
(braced) {
sv_catpvs(message_sv,
"}"
);
}
else
{
sv_catsv(message_sv, display_char);
}
sv_catpvs(message_sv,
"\""
);
SvREFCNT_dec_NN(display_char);
return
SvPVX_const(message_sv);
}
const
char
*
Perl_form_cp_too_large_msg(pTHX_
const
U8 which,
const
char
* string,
const
Size_t len,
const
UV cp)
{
SV * message_sv = sv_newmortal();
const
char
* format;
const
char
* prefix;
PERL_ARGS_ASSERT_FORM_CP_TOO_LARGE_MSG;
assert
(which == 8 || which == 16);
assert
((string != NULL) ^ (cp != 0));
assert
((string == NULL) || len);
if
(which == 8) {
format =
"%"
UVof;
prefix =
"0"
;
}
else
{
format =
"%"
UVXf;
prefix =
"0x"
;
}
Perl_sv_setpvf(aTHX_ message_sv,
"Use of code point %s"
, prefix);
if
(string) {
Perl_sv_catpvf(aTHX_ message_sv,
"%.*s"
, (
int
) len, string);
}
else
{
Perl_sv_catpvf(aTHX_ message_sv, format, cp);
}
Perl_sv_catpvf(aTHX_ message_sv,
" is not allowed; the permissible max is %s"
, prefix);
Perl_sv_catpvf(aTHX_ message_sv, format, MAX_LEGAL_CP);
return
SvPVX_const(message_sv);
}
bool
Perl_grok_bslash_o(pTHX_
char
**s,
const
char
*
const
send, UV *uv,
const
char
** message,
U32 * packed_warn,
const
bool
strict,
const
bool
allow_UV_MAX,
const
bool
UTF)
{
char
* e;
char
* rbrace;
STRLEN numbers_len;
STRLEN trailing_blanks_len = 0;
I32 flags = PERL_SCAN_ALLOW_UNDERSCORES
| PERL_SCAN_DISALLOW_PREFIX
| PERL_SCAN_SILENT_NON_PORTABLE
| PERL_SCAN_SILENT_ILLDIGIT
| PERL_SCAN_SILENT_OVERFLOW;
PERL_ARGS_ASSERT_GROK_BSLASH_O;
assert
(*(*s - 1) ==
'\\'
);
assert
(* *s ==
'o'
);
*message = NULL;
if
(packed_warn) *packed_warn = 0;
(*s)++;
if
(send <= *s || **s !=
'{'
) {
*message =
"Missing braces on \\o{}"
;
return
FALSE;
}
rbrace = (
char
*)
memchr
(*s,
'}'
, send - *s);
if
(!rbrace) {
(*s)++;
while
(*s < send && isBLANK(**s)) {
(*s)++;
}
while
(*s < send && isOCTAL(**s)) {
(*s)++;
}
*message =
"Missing right brace on \\o{}"
;
return
FALSE;
}
(*s)++;
while
(isBLANK(**s)) {
(*s)++;
}
e = rbrace;
while
(*s < e && isBLANK(*(e - 1))) {
e--;
}
numbers_len = e - *s;
if
(numbers_len == 0) {
(*s)++;
*message =
"Empty \\o{}"
;
return
FALSE;
}
*uv = grok_oct(*s, &numbers_len, &flags, NULL);
if
(UNLIKELY( (flags & PERL_SCAN_GREATER_THAN_UV_MAX)
|| (! allow_UV_MAX && *uv == UV_MAX)))
{
*message = form_cp_too_large_msg(8, *s, numbers_len, 0);
*s = rbrace + 1;
return
FALSE;
}
while
(isBLANK(**s)) {
trailing_blanks_len++;
(*s)++;
}
if
(numbers_len + trailing_blanks_len != (STRLEN) (e - *s)) {
*s += numbers_len;
if
(strict) {
*s += (UTF) ? UTF8_SAFE_SKIP(*s, send) : 1;
*message =
"Non-octal character"
;
return
FALSE;
}
if
(ckWARN(WARN_DIGIT)) {
const
char
* failure = form_alien_digit_msg(8, numbers_len, *s, send,
UTF, TRUE);
if
(packed_warn) {
*message = failure;
*packed_warn = packWARN(WARN_DIGIT);
}
else
{
Perl_warner(aTHX_ packWARN(WARN_DIGIT),
"%s"
, failure);
}
}
}
*s = rbrace + 1;
return
TRUE;
}
bool
Perl_grok_bslash_x(pTHX_
char
** s,
const
char
*
const
send, UV *uv,
const
char
** message,
U32 * packed_warn,
const
bool
strict,
const
bool
allow_UV_MAX,
const
bool
UTF)
{
char
* e;
char
* rbrace;
STRLEN numbers_len;
STRLEN trailing_blanks_len = 0;
I32 flags = PERL_SCAN_DISALLOW_PREFIX
| PERL_SCAN_SILENT_ILLDIGIT
| PERL_SCAN_NOTIFY_ILLDIGIT
| PERL_SCAN_SILENT_NON_PORTABLE
| PERL_SCAN_SILENT_OVERFLOW;
PERL_ARGS_ASSERT_GROK_BSLASH_X;
assert
(*(*s - 1) ==
'\\'
);
assert
(* *s ==
'x'
);
*message = NULL;
if
(packed_warn) *packed_warn = 0;
(*s)++;
if
(send <= *s) {
if
(strict) {
*message =
"Empty \\x"
;
return
FALSE;
}
*uv = 0;
return
TRUE;
}
if
(**s !=
'{'
) {
numbers_len = (strict) ? 3 : 2;
*uv = grok_hex(*s, &numbers_len, &flags, NULL);
*s += numbers_len;
if
(numbers_len != 2 && (strict || (flags & PERL_SCAN_NOTIFY_ILLDIGIT))) {
if
(numbers_len == 3) {
*message =
"Use \\x{...} for more than two hex characters"
;
return
FALSE;
}
else
if
(strict) {
*s += (UTF) ? UTF8_SAFE_SKIP(*s, send) : 1;
*message =
"Non-hex character"
;
return
FALSE;
}
else
if
(ckWARN(WARN_DIGIT)) {
const
char
* failure = form_alien_digit_msg(16, numbers_len, *s,
send, UTF, FALSE);
if
(! packed_warn) {
Perl_warner(aTHX_ packWARN(WARN_DIGIT),
"%s"
, failure);
}
else
{
*message = failure;
*packed_warn = packWARN(WARN_DIGIT);
}
}
}
return
TRUE;
}
rbrace = (
char
*)
memchr
(*s,
'}'
, send - *s);
if
(!rbrace) {
(*s)++;
while
(*s < send && isBLANK(**s)) {
(*s)++;
}
while
(*s < send && isXDIGIT(**s)) {
(*s)++;
}
*message =
"Missing right brace on \\x{}"
;
return
FALSE;
}
(*s)++;
while
(isBLANK(**s)) {
(*s)++;
}
e = rbrace;
while
(*s < e && isBLANK(*(e - 1))) {
e--;
}
numbers_len = e - *s;
if
(numbers_len == 0) {
if
(strict) {
(*s)++;
*message =
"Empty \\x{}"
;
return
FALSE;
}
*s = rbrace + 1;
*uv = 0;
return
TRUE;
}
flags |= PERL_SCAN_ALLOW_UNDERSCORES;
*uv = grok_hex(*s, &numbers_len, &flags, NULL);
if
(UNLIKELY( (flags & PERL_SCAN_GREATER_THAN_UV_MAX)
|| (! allow_UV_MAX && *uv == UV_MAX)))
{
*message = form_cp_too_large_msg(16, *s, numbers_len, 0);
*s = e + 1;
return
FALSE;
}
while
(isBLANK(**s)) {
trailing_blanks_len++;
(*s)++;
}
if
(numbers_len + trailing_blanks_len != (STRLEN) (e - *s)) {
*s += numbers_len;
if
(strict) {
*s += (UTF) ? UTF8_SAFE_SKIP(*s, send) : 1;
*message =
"Non-hex character"
;
return
FALSE;
}
if
(ckWARN(WARN_DIGIT)) {
const
char
* failure = form_alien_digit_msg(16, numbers_len, *s,
send, UTF, TRUE);
if
(! packed_warn) {
Perl_warner(aTHX_ packWARN(WARN_DIGIT),
"%s"
, failure);
}
else
{
*message = failure;
*packed_warn = packWARN(WARN_DIGIT);
}
}
}
*s = rbrace + 1;
return
TRUE;
}