fish-shell/src/autoload.h
Kurtis Rader 509ee64fc9 implement our own assert() function
I recently upgraded the software on my macOS server and was dismayed to
see that cppcheck reported a huge number of format string errors due to
mismatches between the format string and its arguments from calls to
`assert()`. It turns out they are due to the macOS header using `%lu`
for the line number which is obviously wrong since it is using the C
preprocessor `__LINE__` symbol which evaluates to a signed int.

I also noticed that the macOS implementation writes to stdout, rather
than stderr. It also uses `printf()` which can be a problem on some
platforms if the stream is already in wide mode which is the normal case
for fish.

So implement our own `assert()` implementation. This also eliminates
double-negative warnings that we get from some of our calls to
`assert()` on some platforms by oclint.

Also reimplement the `DIE()` macro in terms of our internal
implementation.

Rewrite `assert(0 && msg)` statements to `DIE(msg)` for clarity and to
eliminate oclint warnings about constant expressions.

Fixes #3276, albeit not in the fashion I originally envisioned.
2017-02-14 18:48:27 -08:00

98 lines
3.7 KiB
C++

// The classes responsible for autoloading functions and completions.
#ifndef FISH_AUTOLOAD_H
#define FISH_AUTOLOAD_H
#include <pthread.h>
#include <time.h>
#include <set>
#include "common.h"
#include "lru.h"
/// Record of an attempt to access a file.
struct file_access_attempt_t {
/// Modification time of the file
time_t mod_time;
/// When we last checked the file
time_t last_checked;
/// Whether or not we believe we can access this file
bool accessible;
/// The access attempt is stale
bool stale;
/// If we cannot access the file, the error code encountered.
int error;
};
file_access_attempt_t access_file(const wcstring &path, int mode);
struct autoload_function_t {
explicit autoload_function_t(bool placeholder)
: access(), is_loaded(false), is_placeholder(placeholder), is_internalized(false) {}
/// The last access attempt recorded
file_access_attempt_t access;
/// Have we actually loaded this function?
bool is_loaded;
/// Whether we are a placeholder that stands in for "no such function". If this is true, then
/// is_loaded must be false.
bool is_placeholder;
/// Whether this function came from a builtin "internalized" script.
bool is_internalized;
};
class env_vars_snapshot_t;
/// Class representing a path from which we can autoload and the autoloaded contents.
class autoload_t : public lru_cache_t<autoload_t, autoload_function_t> {
private:
/// Lock for thread safety.
pthread_mutex_t lock;
/// The environment variable name.
const wcstring env_var_name;
/// The path from which we most recently autoloaded.
wcstring last_path;
/// the most reecently autoloaded path, tokenized (split on separators).
wcstring_list_t last_path_tokenized;
/// A table containing all the files that are currently being loaded.
/// This is here to help prevent recursion.
std::set<wcstring> is_loading_set;
// Function invoked when a command is removed
typedef void (*command_removed_function_t)(const wcstring &);
const command_removed_function_t command_removed;
void remove_all_functions() { this->evict_all_nodes(); }
bool locate_file_and_maybe_load_it(const wcstring &cmd, bool really_load, bool reload,
const wcstring_list_t &path_list);
autoload_function_t *get_autoloaded_function_with_creation(const wcstring &cmd,
bool allow_eviction);
public:
// CRTP override
void entry_was_evicted(wcstring key, autoload_function_t node);
// Create an autoload_t for the given environment variable name.
autoload_t(const wcstring &env_var_name_var, command_removed_function_t callback);
~autoload_t();
/// Autoload the specified file, if it exists in the specified path. Do not load it multiple
/// times unless its timestamp changes or parse_util_unload is called.
/// Autoloading one file may unload another.
/// @param cmd the filename to search for. The suffix '.fish' is always added to this name
/// @param reload wheter to recheck file timestamps on already loaded files
int load(const wcstring &cmd, bool reload);
/// Check whether we have tried loading the given command. Does not do any I/O.
bool has_tried_loading(const wcstring &cmd);
/// Tell the autoloader that the specified file, in the specified path, is no longer loaded.
/// Returns non-zero if the file was removed, zero if the file had not yet been loaded
int unload(const wcstring &cmd);
/// Check whether the given command could be loaded, but do not load it.
bool can_load(const wcstring &cmd, const env_vars_snapshot_t &vars);
};
#endif