aboutsummaryrefslogtreecommitdiff
path: root/libcpp/files.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libcpp/files.cc')
-rw-r--r--libcpp/files.cc378
1 files changed, 362 insertions, 16 deletions
diff --git a/libcpp/files.cc b/libcpp/files.cc
index fc66b9c..52b1850 100644
--- a/libcpp/files.cc
+++ b/libcpp/files.cc
@@ -87,6 +87,9 @@ struct _cpp_file
/* As filled in by stat(2) for the file. */
struct stat st;
+ /* Size for #embed, perhaps smaller than st.st_size. */
+ size_t limit;
+
/* File descriptor. Invalid if -1, otherwise open. */
int fd;
@@ -113,6 +116,9 @@ struct _cpp_file
and error should be emitted if it is included normally. */
bool deferred_error : 1;
+ /* File loaded from #embed. */
+ bool embed : 1;
+
/* > 0: Known C++ Module header unit, <0: known not. ==0, unknown */
int header_unit : 2;
};
@@ -187,7 +193,8 @@ static const char *dir_name_of_file (_cpp_file *file);
static void open_file_failed (cpp_reader *pfile, _cpp_file *file, int,
location_t);
static struct cpp_file_hash_entry *search_cache (struct cpp_file_hash_entry *head,
- const cpp_dir *start_dir);
+ const cpp_dir *start_dir,
+ bool is_embed);
static _cpp_file *make_cpp_file (cpp_dir *, const char *fname);
static void destroy_cpp_file (_cpp_file *);
static cpp_dir *make_cpp_dir (cpp_reader *, const char *dir_name, int sysp);
@@ -425,7 +432,7 @@ find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch,
}
file->path = path;
- if (pch_open_file (pfile, file, invalid_pch))
+ if (!file->embed && pch_open_file (pfile, file, invalid_pch))
return true;
if (open_file (file))
@@ -514,7 +521,9 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir,
bool invalid_pch = false;
bool saw_bracket_include = false;
bool saw_quote_include = false;
+ bool saw_embed_include = false;
struct cpp_dir *found_in_cache = NULL;
+ bool is_embed = kind == _cpp_FFK_EMBED || kind == _cpp_FFK_HAS_EMBED;
/* Ensure we get no confusion between cached files and directories. */
if (start_dir == NULL)
@@ -526,10 +535,12 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir,
/* First check the cache before we resort to memory allocation. */
cpp_file_hash_entry *entry
- = search_cache ((struct cpp_file_hash_entry *) *hash_slot, start_dir);
+ = search_cache ((struct cpp_file_hash_entry *) *hash_slot, start_dir,
+ is_embed);
if (entry)
{
- if (entry->u.file->deferred_error && kind == _cpp_FFK_NORMAL)
+ if (entry->u.file->deferred_error
+ && (kind == _cpp_FFK_NORMAL || kind == _cpp_FFK_EMBED))
{
open_file_failed (pfile, entry->u.file, angle_brackets, loc);
entry->u.file->deferred_error = false;
@@ -541,6 +552,7 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir,
file->implicit_preinclude
= (kind == _cpp_FFK_PRE_INCLUDE
|| (pfile->buffer && pfile->buffer->file->implicit_preinclude));
+ file->embed = is_embed;
if (kind == _cpp_FFK_FAKE)
file->dont_read = true;
@@ -551,10 +563,17 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir,
if (find_file_in_dir (pfile, file, &invalid_pch, loc))
break;
- file->dir = file->dir->next;
+ if (is_embed
+ && file->dir == start_dir
+ && start_dir != pfile->embed_include
+ && start_dir != &pfile->no_search_path)
+ file->dir = pfile->embed_include;
+ else
+ file->dir = file->dir->next;
if (file->dir == NULL)
{
- if (search_path_exhausted (pfile, fname, file))
+ if (!is_embed
+ && search_path_exhausted (pfile, fname, file))
{
/* Although this file must not go in the cache,
because the file found might depend on things (like
@@ -601,7 +620,7 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir,
return NULL;
}
- if (kind != _cpp_FFK_HAS_INCLUDE)
+ if (kind != _cpp_FFK_HAS_INCLUDE && kind != _cpp_FFK_HAS_EMBED)
open_file_failed (pfile, file, angle_brackets, loc);
else
file->deferred_error = true;
@@ -615,11 +634,14 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir,
saw_bracket_include = true;
else if (file->dir == pfile->quote_include)
saw_quote_include = true;
+ else if (file->dir == pfile->embed_include)
+ saw_embed_include = true;
else
continue;
entry
- = search_cache ((struct cpp_file_hash_entry *) *hash_slot, file->dir);
+ = search_cache ((struct cpp_file_hash_entry *) *hash_slot,
+ file->dir, is_embed);
if (entry)
{
found_in_cache = file->dir;
@@ -673,6 +695,17 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir,
entry->u.file = file;
*hash_slot = (void *) entry;
}
+ if (saw_embed_include
+ && pfile->embed_include != start_dir
+ && found_in_cache != pfile->embed_include)
+ {
+ entry = new_file_hash_entry (pfile);
+ entry->next = (struct cpp_file_hash_entry *) *hash_slot;
+ entry->start_dir = pfile->embed_include;
+ entry->location = loc;
+ entry->u.file = file;
+ *hash_slot = (void *) entry;
+ }
return file;
}
@@ -760,7 +793,7 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file, location_t loc,
if (pfile && regular && total != size && STAT_SIZE_RELIABLE (file->st))
cpp_error_at (pfile, CPP_DL_WARNING, loc,
- "%s is shorter than expected", file->path);
+ "%s is shorter than expected", file->path);
file->buffer = _cpp_convert_input (pfile,
input_charset,
@@ -871,6 +904,9 @@ has_unique_contents (cpp_reader *pfile, _cpp_file *file, bool import,
if (f == file)
continue; /* It'sa me! */
+ if (f->embed)
+ continue;
+
if ((import || f->once_only)
&& f->err_no == 0
&& f->st.st_mtime == file->st.st_mtime
@@ -1062,12 +1098,12 @@ search_path_head (cpp_reader *pfile, const char *fname, int angle_brackets,
&& file->dir != &pfile->no_search_path)
dir = file->dir->next;
else if (angle_brackets)
- dir = pfile->bracket_include;
+ dir = type == IT_EMBED ? pfile->embed_include : pfile->bracket_include;
else if (type == IT_CMDLINE)
/* -include and -imacros use the #include "" chain with the
preprocessor's cwd prepended. */
return make_cpp_dir (pfile, "./", false);
- else if (pfile->quote_ignores_source_dir)
+ else if (pfile->quote_ignores_source_dir && type != IT_EMBED)
dir = pfile->quote_include;
else
return make_cpp_dir (pfile, dir_name_of_file (file),
@@ -1181,6 +1217,306 @@ cpp_probe_header_unit (cpp_reader *pfile, const char *name, bool angle,
return nullptr;
}
+/* Try to load FNAME with #embed/__has_embed parameters PARAMS.
+ If !PARAMS->has_embed, return new token in pfile->directive_result
+ (first token) and rest in a pushed non-macro context.
+ Returns 0 for not found/errors, 1 for non-empty resource and 2
+ for empty resource. */
+
+int
+_cpp_stack_embed (cpp_reader *pfile, const char *fname, bool angle,
+ struct cpp_embed_params *params)
+{
+ cpp_dir *dir = search_path_head (pfile, fname, angle, IT_EMBED,
+ params->has_embed);
+ if (!dir)
+ return 0;
+ _cpp_file *file = _cpp_find_file (pfile, fname, dir, angle,
+ params->has_embed
+ ? _cpp_FFK_HAS_EMBED : _cpp_FFK_EMBED,
+ params->loc);
+ if (!file)
+ return 0;
+ if (file->dont_read || file->err_no)
+ return 0;
+ _cpp_file *orig_file = file;
+ if (file->buffer_valid
+ && (!S_ISREG (file->st.st_mode)
+ || (file->limit < file->st.st_size + (size_t) 0
+ && file->limit < params->limit)))
+ {
+ bool found = false;
+ if (S_ISREG (file->st.st_mode))
+ {
+ while (file->next_file
+ && file->next_file->embed
+ && file->next_file->buffer_valid
+ && file->next_file->dir == file->dir
+ && strcmp (file->name, file->next_file->name) == 0
+ && strcmp (file->path, file->next_file->path) == 0)
+ {
+ file = file->next_file;
+ if (file->limit >= file->st.st_size + (size_t) 0
+ || file->limit >= params->limit)
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ _cpp_file *file2 = make_cpp_file (file->dir, file->name);
+ file2->path = xstrdup (file->path);
+ file2->next_file = file->next_file;
+ file2->embed = true;
+ file->next_file = file2;
+ file = file2;
+ }
+ }
+ if (!file->buffer_valid)
+ {
+ if (file->fd == -1 && !open_file (file))
+ {
+ if (params->has_embed)
+ file->deferred_error = true;
+ else
+ open_file_failed (pfile, file, 0, params->loc);
+ return 0;
+ }
+ if (S_ISBLK (file->st.st_mode))
+ {
+ if (params->has_embed)
+ {
+ close (file->fd);
+ file->fd = -1;
+ return 0;
+ }
+ cpp_error_at (pfile, CPP_DL_ERROR, params->loc,
+ "%s is a block device", file->path);
+ fail:
+ close (file->fd);
+ file->fd = -1;
+ file->dont_read = true;
+ return 0;
+ }
+
+ if (CPP_OPTION (pfile, deps.style)
+ && !params->has_embed
+ && file == orig_file
+ && file->path[0])
+ deps_add_dep (pfile->deps, file->path);
+
+ bool regular = S_ISREG (file->st.st_mode) != 0;
+ ssize_t size, total, count;
+ uchar *buf;
+ if (regular)
+ {
+ cpp_num_part limit;
+ if (file->st.st_size + (cpp_num_part) 0 < params->limit)
+ limit = file->st.st_size;
+ else
+ limit = params->limit;
+ if (params->has_embed)
+ return limit != 0 ? 1 : 2;
+ if (limit > INTTYPE_MAXIMUM (ssize_t))
+ {
+ cpp_error_at (pfile, CPP_DL_ERROR, params->loc,
+ "%s is too large", file->path);
+ goto fail;
+ }
+ file->limit = limit;
+ size = limit;
+ }
+ else if (params->has_embed)
+ return 2;
+ else if (params->limit > 8 * 1024)
+ size = 8 * 1024;
+ else
+ size = params->limit;
+ buf = XNEWVEC (uchar, size ? size : 1);
+ total = 0;
+
+ while ((count = read (file->fd, buf + total, size - total)) > 0)
+ {
+ total += count;
+ if (total == size)
+ {
+ if (regular || size + (cpp_num_part) 0 == params->limit)
+ break;
+ size = (size_t) size * 2;
+ if (size < 0)
+ {
+ if (params->limit <= INTTYPE_MAXIMUM (ssize_t))
+ size = params->limit;
+ else
+ {
+ cpp_error_at (pfile, CPP_DL_ERROR, params->loc,
+ "%s is too large", file->path);
+ free (buf);
+ goto fail;
+ }
+ }
+ else if (size + (cpp_num_part) 0 > params->limit)
+ size = params->limit;
+ buf = XRESIZEVEC (uchar, buf, size);
+ }
+ }
+
+ if (count < 0)
+ {
+ cpp_errno_filename (pfile, CPP_DL_ERROR, file->path, params->loc);
+ free (buf);
+ goto fail;
+ }
+
+ if (regular && total != size && STAT_SIZE_RELIABLE (file->st))
+ {
+ cpp_error_at (pfile, CPP_DL_WARNING, params->loc,
+ "%s is shorter than expected", file->path);
+ file->limit = total;
+ }
+ else if (!regular)
+ file->limit = total;
+
+ file->buffer_start = buf;
+ file->buffer = buf;
+ file->buffer_valid = 1;
+ close (file->fd);
+ file->fd = -1;
+ }
+ else if (params->has_embed)
+ return file->limit && params->limit ? 1 : 2;
+
+ size_t limit = file->limit;
+ 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 max = INTTYPE_MAXIMUM (size_t) / sizeof (cpp_token);
+ if (limit > max / 2
+ || (limit
+ ? (params->prefix.count > max
+ || params->suffix.count > max
+ || (limit * 2 + params->prefix.count
+ + params->suffix.count > max))
+ : params->if_empty.count > max))
+ {
+ cpp_error_at (pfile, CPP_DL_ERROR, params->loc,
+ "%s is too large", file->path);
+ return 0;
+ }
+
+ size_t len = 0;
+ for (size_t i = 0; i < limit; ++i)
+ {
+ if (file->buffer[i] < 10)
+ len += 2;
+ else if (file->buffer[i] < 100)
+ len += 3;
+#if UCHAR_MAX == 255
+ else
+ len += 4;
+#else
+ else if (file->buffer[i] < 1000)
+ len += 4;
+ else
+ {
+ char buf[64];
+ len += sprintf (buf, "%d", file->buffer[i]) + 1;
+ }
+#endif
+ if (len > INTTYPE_MAXIMUM (ssize_t))
+ {
+ cpp_error_at (pfile, CPP_DL_ERROR, params->loc,
+ "%s is too large", file->path);
+ return 0;
+ }
+ }
+ 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
+ + params->suffix.count) - 1;
+ else if (params->if_empty.count)
+ count = params->if_empty.count - 1;
+ if (count)
+ {
+ tok_buff = _cpp_get_buff (pfile, count * sizeof (cpp_token));
+ toks = (cpp_token *) tok_buff->base;
+ }
+ cpp_embed_params_tokens *prefix
+ = limit ? &params->prefix : &params->if_empty;
+ if (prefix->count)
+ {
+ *tok = *prefix->base_run.base;
+ tok = toks;
+ tokenrun *cur_run = &prefix->base_run;
+ while (cur_run)
+ {
+ size_t cnt = (cur_run->next ? cur_run->limit
+ : prefix->cur_token) - cur_run->base;
+ cpp_token *t = cur_run->base;
+ if (cur_run == &prefix->base_run)
+ {
+ t++;
+ cnt--;
+ }
+ memcpy (tok, t, cnt * sizeof (cpp_token));
+ tok += cnt;
+ cur_run = cur_run->next;
+ }
+ }
+ for (size_t i = 0; i < limit; ++i)
+ {
+ tok->src_loc = params->loc;
+ tok->type = CPP_NUMBER;
+ tok->flags = NO_EXPAND;
+ if (i == 0)
+ tok->flags |= PREV_WHITE;
+ tok->val.str.text = s;
+ tok->val.str.len = sprintf ((char *) s, "%d", file->buffer[i]);
+ s += tok->val.str.len + 1;
+ if (tok == &pfile->directive_result)
+ tok = toks;
+ else
+ tok++;
+ if (i < limit - 1)
+ {
+ tok->src_loc = params->loc;
+ tok->type = CPP_COMMA;
+ tok->flags = NO_EXPAND;
+ tok++;
+ }
+ }
+ if (limit && params->suffix.count)
+ {
+ tokenrun *cur_run = &params->suffix.base_run;
+ cpp_token *orig_tok = tok;
+ while (cur_run)
+ {
+ size_t cnt = (cur_run->next ? cur_run->limit
+ : params->suffix.cur_token) - cur_run->base;
+ cpp_token *t = cur_run->base;
+ memcpy (tok, t, cnt * sizeof (cpp_token));
+ tok += cnt;
+ cur_run = cur_run->next;
+ }
+ orig_tok->flags |= PREV_WHITE;
+ }
+ pfile->directive_result.flags |= PREV_WHITE;
+ if (count)
+ {
+ _cpp_push_token_context (pfile, NULL, toks, count);
+ pfile->context->buff = tok_buff;
+ }
+ return limit ? 1 : 2;
+}
+
/* Retrofit the just-entered main file asif it was an include. This
will permit correct include_next use, and mark it as a system
header if that's where it resides. We use filesystem-appropriate
@@ -1256,9 +1592,11 @@ open_file_failed (cpp_reader *pfile, _cpp_file *file, int angle_brackets,
/* Search in the chain beginning at HEAD for a file whose search path
started at START_DIR != NULL. */
static struct cpp_file_hash_entry *
-search_cache (struct cpp_file_hash_entry *head, const cpp_dir *start_dir)
+search_cache (struct cpp_file_hash_entry *head, const cpp_dir *start_dir,
+ bool is_embed)
{
- while (head && head->start_dir != start_dir)
+ while (head && (head->start_dir != start_dir
+ || head->u.file->embed != is_embed))
head = head->next;
return head;
@@ -1692,21 +2030,24 @@ _cpp_get_file_name (_cpp_file *file)
struct stat *
_cpp_get_file_stat (_cpp_file *file)
{
- return &file->st;
+ return &file->st;
}
/* Set the include chain for "" to QUOTE, for <> to BRACKET. If
QUOTE_IGNORES_SOURCE_DIR, then "" includes do not look in the
directory of the including file.
- If BRACKET does not lie in the QUOTE chain, it is set to QUOTE. */
+ If BRACKET does not lie in the QUOTE chain, it is set to QUOTE.
+
+ EMBED is include chain for #embed <>. */
void
cpp_set_include_chains (cpp_reader *pfile, cpp_dir *quote, cpp_dir *bracket,
- int quote_ignores_source_dir)
+ cpp_dir *embed, int quote_ignores_source_dir)
{
pfile->quote_include = quote;
pfile->bracket_include = quote;
pfile->quote_ignores_source_dir = quote_ignores_source_dir;
+ pfile->embed_include = embed;
for (; quote; quote = quote->next)
{
@@ -1715,6 +2056,11 @@ cpp_set_include_chains (cpp_reader *pfile, cpp_dir *quote, cpp_dir *bracket,
if (quote == bracket)
pfile->bracket_include = bracket;
}
+ for (; embed; embed = embed->next)
+ {
+ embed->name_map = NULL;
+ embed->len = strlen (embed->name);
+ }
}
/* Append the file name to the directory to create the path, but don't