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