@@ -144,6 +144,8 @@ class rich_location;
TK(STRING32_USERDEF, LITERAL) /* U"string"_suffix - C++11 */ \
TK(UTF8STRING_USERDEF,LITERAL) /* u8"string"_suffix - C++11 */ \
\
+ TK(EMBED, LITERAL) /* #embed - C23 */ \
+ \
TK(COMMENT, LITERAL) /* Only if output comments. */ \
/* SPELL_LITERAL happens to DTRT. */ \
TK(MACRO_ARG, NONE) /* Macro argument. */ \
@@ -1240,15 +1240,17 @@ finish_embed (cpp_reader *pfile, _cpp_fi
if (params->limit < limit)
limit = params->limit;
- /* For sizes larger than say 64 bytes, this is just a temporary
- solution, we should emit a single new token which the FEs will
- handle as an optimization. */
+ size_t embed_tokens = 0;
+ if (CPP_OPTION (pfile, directives_only) && limit >= 64)
+ embed_tokens = ((limit - 2) / INT_MAX) + (((limit - 2) % INT_MAX) != 0);
+
size_t max = INTTYPE_MAXIMUM (size_t) / sizeof (cpp_token);
- if (limit > max / 2
+ if ((embed_tokens ? (embed_tokens > (max - 3) / 2) : (limit > max / 2))
|| (limit
? (params->prefix.count > max
|| params->suffix.count > max
- || (limit * 2 + params->prefix.count
+ || ((embed_tokens ? embed_tokens * 2 + 3 : limit * 2 - 1)
+ + params->prefix.count
+ params->suffix.count > max))
: params->if_empty.count > max))
{
@@ -1282,13 +1284,16 @@ finish_embed (cpp_reader *pfile, _cpp_fi
"%s is too large", file->path);
return 0;
}
+ if (embed_tokens && i == 0)
+ i = limit - 2;
}
uchar *s = len ? _cpp_unaligned_alloc (pfile, len) : NULL;
_cpp_buff *tok_buff = NULL;
cpp_token *toks = NULL, *tok = &pfile->directive_result;
size_t count = 0;
if (limit)
- count = (params->prefix.count + limit * 2 - 1
+ count = (params->prefix.count
+ + (embed_tokens ? embed_tokens * 2 + 3 : limit * 2 - 1)
+ params->suffix.count) - 1;
else if (params->if_empty.count)
count = params->if_empty.count - 1;
@@ -1340,6 +1345,34 @@ finish_embed (cpp_reader *pfile, _cpp_fi
tok->flags = NO_EXPAND;
tok++;
}
+ if (i == 0 && embed_tokens)
+ {
+ ++i;
+ for (size_t j = 0; j < embed_tokens; ++j)
+ {
+ tok->src_loc = params->loc;
+ tok->type = CPP_EMBED;
+ tok->flags = NO_EXPAND;
+ tok->val.str.text = &buffer[i];
+ tok->val.str.len
+ = limit - 1 - i > INT_MAX ? INT_MAX : limit - 1 - i;
+ i += tok->val.str.len;
+ if (tok->val.str.len < 32)
+ {
+ /* Avoid CPP_EMBED with a fewer than 32 bytes, shrink the
+ previous CPP_EMBED by 64 and grow this one by 64. */
+ tok[-2].val.str.len -= 64;
+ tok->val.str.text -= 64;
+ tok->val.str.len += 64;
+ }
+ tok++;
+ tok->src_loc = params->loc;
+ tok->type = CPP_COMMA;
+ tok->flags = NO_EXPAND;
+ tok++;
+ }
+ --i;
+ }
}
if (limit && params->suffix.count)
{
@@ -299,6 +299,55 @@ token_streamer::stream (cpp_reader *pfil
maybe_print_line (UNKNOWN_LOCATION);
in_pragma = false;
}
+ else if (token->type == CPP_EMBED)
+ {
+ char buf[65];
+ maybe_print_line (token->src_loc);
+ fputs ("#embed \".\" __gnu__::__base64__(\"", print.outf);
+ print.printed = true;
+ unsigned int j = 0;
+ static const char base64_enc[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ for (unsigned i = 0; i < token->val.str.len; i += 3)
+ {
+ unsigned char a = token->val.str.text[i];
+ unsigned char b = 0, c = 0;
+ unsigned int n = token->val.str.len - i;
+ if (n > 1)
+ b = token->val.str.text[i + 1];
+ if (n > 2)
+ c = token->val.str.text[i + 2];
+ unsigned long v = ((((unsigned long) a) << 16)
+ | (((unsigned long) b) << 8)
+ | c);
+ buf[j++] = base64_enc[(v >> 18) & 63];
+ buf[j++] = base64_enc[(v >> 12) & 63];
+ buf[j++] = base64_enc[(v >> 6) & 63];
+ buf[j++] = base64_enc[v & 63];
+ if (n < 3)
+ {
+ buf[j - 1] = '=';
+ if (n == 1)
+ buf[j - 2] = '=';
+ }
+ if (j == 64)
+ {
+ buf[64] = '\0';
+ fputs (buf, print.outf);
+ j = 0;
+ }
+ if (n < 3)
+ break;
+ }
+ if (j)
+ {
+ buf[j] = '\0';
+ fputs (buf, print.outf);
+ }
+ fputs ("\")", print.outf);
+ maybe_print_line (token->src_loc);
+ return;
+ }
else
{
if (cpp_get_options (parse_in)->debug)