1 // Prototypes for string expansion functions. These functions perform several kinds of parameter 2 // expansion. There are a lot of issues with regards to memory allocation. Overall, these functions 3 // would benefit from using a more clever memory allocation scheme, perhaps an evil combination of 4 // talloc, string buffers and reference counting. 5 #ifndef FISH_EXPAND_H 6 #define FISH_EXPAND_H 7 8 #include "config.h" 9 10 #include <stddef.h> 11 12 #include <map> 13 #include <string> 14 #include <vector> 15 16 #include "common.h" 17 #include "enum_set.h" 18 #include "maybe.h" 19 #include "parse_constants.h" 20 21 class environment_t; 22 class env_var_t; 23 class environment_t; 24 class operation_context_t; 25 26 /// Set of flags controlling expansions. 27 enum class expand_flag { 28 /// Skip command substitutions. 29 skip_cmdsubst, 30 /// Skip variable expansion. 31 skip_variables, 32 /// Skip wildcard expansion. 33 skip_wildcards, 34 /// The expansion is being done for tab or auto completions. Returned completions may have the 35 /// wildcard as a prefix instead of a match. 36 for_completions, 37 /// Only match files that are executable by the current user. 38 executables_only, 39 /// Only match directories. 40 directories_only, 41 /// Generate descriptions, stored in the description field of completions. 42 gen_descriptions, 43 /// Don't expand home directories. 44 skip_home_directories, 45 /// Allow fuzzy matching. 46 fuzzy_match, 47 /// Disallow directory abbreviations like /u/l/b for /usr/local/bin. Only applicable if 48 /// fuzzy_match is set. 49 no_fuzzy_directories, 50 /// Do expansions specifically to support cd. This means using CDPATH as a list of potential 51 /// working directories, and to use logical instead of physical paths. 52 special_for_cd, 53 /// Do expansions specifically for cd autosuggestion. This is to differentiate between cd 54 /// completions and cd autosuggestions. 55 special_for_cd_autosuggestion, 56 /// Do expansions specifically to support external command completions. This means using PATH as 57 /// a list of potential working directories. 58 special_for_command, 59 60 COUNT, 61 }; 62 63 template <> 64 struct enum_info_t<expand_flag> { 65 static constexpr auto count = expand_flag::COUNT; 66 }; 67 68 using expand_flags_t = enum_set_t<expand_flag>; 69 70 class completion_t; 71 using completion_list_t = std::vector<completion_t>; 72 class completion_receiver_t; 73 74 enum : wchar_t { 75 /// Character representing a home directory. 76 HOME_DIRECTORY = EXPAND_RESERVED_BASE, 77 /// Character representing process expansion for %self. 78 PROCESS_EXPAND_SELF, 79 /// Character representing variable expansion. 80 VARIABLE_EXPAND, 81 /// Character representing variable expansion into a single element. 82 VARIABLE_EXPAND_SINGLE, 83 /// Character representing the start of a bracket expansion. 84 BRACE_BEGIN, 85 /// Character representing the end of a bracket expansion. 86 BRACE_END, 87 /// Character representing separation between two bracket elements. 88 BRACE_SEP, 89 /// Character that takes the place of any whitespace within non-quoted text in braces 90 BRACE_SPACE, 91 /// Separate subtokens in a token with this character. 92 INTERNAL_SEPARATOR, 93 /// Character representing an empty variable expansion. Only used transitively while expanding 94 /// variables. 95 VARIABLE_EXPAND_EMPTY, 96 /// This is a special pseudo-char that is not used other than to mark the end of the the special 97 /// characters so we can sanity check the enum range. 98 EXPAND_SENTINEL 99 }; 100 101 /// These are the possible return values for expand_string. 102 struct expand_result_t { 103 enum result_t { 104 /// There was an error, for example, unmatched braces. 105 error, 106 /// Expansion succeeded. 107 ok, 108 /// Expansion was cancelled (e.g. control-C). 109 cancel, 110 /// Expansion succeeded, but a wildcard in the string matched no files, 111 /// so the output is empty. 112 wildcard_no_match, 113 }; 114 115 /// The result of expansion. 116 result_t result; 117 118 /// If expansion resulted in an error, this is an appropriate value with which to populate 119 /// $status. 120 int status{0}; 121 122 /* implicit */ expand_result_t(result_t result) : result(result) {} 123 124 /// operator== allows for comparison against result_t values. 125 bool operator==(result_t rhs) const { return result == rhs; } 126 bool operator!=(result_t rhs) const { return !(*this == rhs); } 127 128 /// Make an error value with the given status. 129 static expand_result_t make_error(int status) { 130 assert(status != 0 && "status cannot be 0 for an error result"); 131 expand_result_t result(error); 132 result.status = status; 133 return result; 134 } 135 }; 136 137 /// The string represented by PROCESS_EXPAND_SELF 138 #define PROCESS_EXPAND_SELF_STR L"%self" 139 #define PROCESS_EXPAND_SELF_STR_LEN 5 140 141 /// Perform various forms of expansion on in, such as tilde expansion (\~USER becomes the users home 142 /// directory), variable expansion (\$VAR_NAME becomes the value of the environment variable 143 /// VAR_NAME), cmdsubst expansion and wildcard expansion. The results are inserted into the list 144 /// out. 145 /// 146 /// If the parameter does not need expansion, it is copied into the list out. 147 /// 148 /// \param input The parameter to expand 149 /// \param output The list to which the result will be appended. 150 /// \param flags Specifies if any expansion pass should be skipped. Legal values are any combination 151 /// of skip_cmdsubst skip_variables and skip_wildcards 152 /// \param ctx The parser, variables, and cancellation checker for this operation. The parser may 153 /// be null. \param errors Resulting errors, or nullptr to ignore 154 /// 155 /// \return An expand_result_t. 156 /// wildcard_no_match and wildcard_match are normal exit conditions used only on 157 /// strings containing wildcards to tell if the wildcard produced any matches. 158 __warn_unused expand_result_t expand_string(wcstring input, completion_list_t *output, 159 expand_flags_t flags, const operation_context_t &ctx, 160 parse_error_list_t *errors = nullptr); 161 162 /// Variant of string that inserts its results into a completion_receiver_t. 163 __warn_unused expand_result_t expand_string(wcstring input, completion_receiver_t *output, 164 expand_flags_t flags, const operation_context_t &ctx, 165 parse_error_list_t *errors = nullptr); 166 167 /// expand_one is identical to expand_string, except it will fail if in expands to more than one 168 /// string. This is used for expanding command names. 169 /// 170 /// \param inout_str The parameter to expand in-place 171 /// \param flags Specifies if any expansion pass should be skipped. Legal values are any combination 172 /// of skip_cmdsubst skip_variables and skip_wildcards 173 /// \param ctx The parser, variables, and cancellation checker for this operation. The parser may be 174 /// null. \param errors Resulting errors, or nullptr to ignore 175 /// 176 /// \return Whether expansion succeeded. 177 bool expand_one(wcstring &string, expand_flags_t flags, const operation_context_t &ctx, 178 parse_error_list_t *errors = nullptr); 179 180 /// Expand a command string like $HOME/bin/cmd into a command and list of arguments. 181 /// Return the command and arguments by reference. 182 /// If the expansion resulted in no or an empty command, the command will be an empty string. Note 183 /// that API does not distinguish between expansion resulting in an empty command (''), and 184 /// expansion resulting in no command (e.g. unset variable). 185 /// If \p skip_wildcards is true, then do not do wildcard expansion 186 /// \return an expand error. 187 expand_result_t expand_to_command_and_args(const wcstring &instr, const operation_context_t &ctx, 188 wcstring *out_cmd, wcstring_list_t *out_args, 189 parse_error_list_t *errors = nullptr, 190 bool skip_wildcards = false); 191 192 /// Convert the variable value to a human readable form, i.e. escape things, handle arrays, etc. 193 /// Suitable for pretty-printing. 194 wcstring expand_escape_variable(const env_var_t &var); 195 196 /// Convert a string value to a human readable form, i.e. escape things, handle arrays, etc. 197 /// Suitable for pretty-printing. 198 wcstring expand_escape_string(const wcstring &el); 199 200 /// Perform tilde expansion and nothing else on the specified string, which is modified in place. 201 /// 202 /// \param input the string to tilde expand 203 void expand_tilde(wcstring &input, const environment_t &vars); 204 205 /// Perform the opposite of tilde expansion on the string, which is modified in place. 206 wcstring replace_home_directory_with_tilde(const wcstring &str, const environment_t &vars); 207 208 /// Abbreviation support. Expand src as an abbreviation, returning the expanded form if found, 209 /// none() if not. 210 maybe_t<wcstring> expand_abbreviation(const wcstring &src, const environment_t &vars); 211 212 /// \return a snapshot of all abbreviations as a map abbreviation->expansion. 213 /// The abbreviations are unescaped, i.e. they may not be valid variable identifiers (#6166). 214 std::map<wcstring, wcstring> get_abbreviations(const environment_t &vars); 215 216 // Terrible hacks 217 bool fish_xdm_login_hack_hack_hack_hack(std::vector<std::string> *cmds, int argc, 218 const char *const *argv); 219 #endif 220