Alias ending with blank & line continuation (#46532)
If the value of an alias substitution ends with a blank, the shell
checks the next token for another substitution. Previously, yash was
examining the parse buffer content to see if the last character of the
alias value was blank. However, this procedure incorrectly ignored any
line continuation that might be at the end of the value. After this
commit, the shell will test the last character in the alias definition
to determine the character blankness correctly.
@@ -37,6 +37,9 @@ | ||
37 | 37 | updated correctly in the "pushd" and "popd" built-ins. |
38 | 38 | * The effect of "!" no longer applies to the exit status of the |
39 | 39 | "break", "continue", and "return" built-ins. |
40 | + * An alias value ending with a blank followed by a line | |
41 | + continuation no longer subjects the next token to alias | |
42 | + substitution. | |
40 | 43 | . Updated the sample initialization script (yashrc): |
41 | 44 | + The "o" alias for WSL |
42 | 45 |
@@ -1,6 +1,6 @@ | ||
1 | 1 | /* Yash: yet another shell */ |
2 | 2 | /* alias.c: alias substitution */ |
3 | -/* (C) 2007-2018 magicant */ | |
3 | +/* (C) 2007-2023 magicant */ | |
4 | 4 | |
5 | 5 | /* This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
@@ -86,8 +86,10 @@ | ||
86 | 86 | static bool remove_expired_aliases( |
87 | 87 | aliaslist_T **list, size_t index, const xwcsbuf_T *buf) |
88 | 88 | __attribute__((nonnull)); |
89 | -static bool is_after_blank(size_t i, size_t j, const xwcsbuf_T *buf) | |
90 | - __attribute__((nonnull)); | |
89 | +static bool ends_with_blank(const alias_T *alias) | |
90 | + __attribute__((nonnull,pure)); | |
91 | +static bool is_blank_range(const xwcsbuf_T *buf, size_t from, size_t to) | |
92 | + __attribute__((nonnull,pure)); | |
91 | 93 | static bool is_redir_fd(const wchar_t *s) |
92 | 94 | __attribute__((nonnull,pure)); |
93 | 95 | static bool print_alias(const wchar_t *name, const alias_T *alias, bool prefix); |
@@ -222,8 +224,9 @@ | ||
222 | 224 | } |
223 | 225 | |
224 | 226 | /* Removes items that are no longer significant. An item is significant if (1) |
225 | - * its limit index is larger than `index', or (2) it is a non-global alias and | |
226 | - * all the characters are blank between the indexes `limitindex-1' and `index'. | |
227 | + * its limit index is larger than `index', or (2) it is a non-global | |
228 | + * blank-ending alias and all the characters between `limitindex' and `index' | |
229 | + * are blank. | |
227 | 230 | * Returns true iff a significant item of type (2) is left. */ |
228 | 231 | /* If this function returns true, the `index' is just after the result of alias |
229 | 232 | * substitution that ends with a blank, in which case the next word should be |
@@ -236,8 +239,8 @@ | ||
236 | 239 | |
237 | 240 | /* List items are ordered by index; we don't have to check all the items. */ |
238 | 241 | while (item != NULL && item->limitindex <= index) { |
239 | - if (!item->alias->isglobal | |
240 | - && is_after_blank(item->limitindex, index, buf)) { | |
242 | + if (!item->alias->isglobal && ends_with_blank(item->alias) && | |
243 | + is_blank_range(buf, item->limitindex, index)) { | |
241 | 244 | afterblank = true; |
242 | 245 | break; |
243 | 246 | } |
@@ -251,16 +254,17 @@ | ||
251 | 254 | return afterblank; |
252 | 255 | } |
253 | 256 | |
254 | -/* Tests if the character just before `i` in `buf' is a blank and all the | |
255 | - * characters between `i' and `j' are blanks. */ | |
256 | -bool is_after_blank(size_t i, size_t j, const xwcsbuf_T *buf) | |
257 | +/* Tests if the alias value ends with a blank. */ | |
258 | +bool ends_with_blank(const alias_T *alias) | |
257 | 259 | { |
258 | - assert(i <= j); | |
259 | - assert(j <= buf->length); | |
260 | + return alias->valuelen > 0 && iswblank(alias->value[alias->valuelen - 1]); | |
261 | +} | |
260 | 262 | |
261 | - if (i == 0) | |
262 | - return false; | |
263 | - for (i--; i < j; i++) | |
263 | +/* Tests if the characters in the range [from, to) are all blank. */ | |
264 | +bool is_blank_range(const xwcsbuf_T *buf, size_t from, size_t to) | |
265 | +{ | |
266 | + assert(from >= to || to <= buf->length); | |
267 | + for (size_t i = from; i < to; i++) | |
264 | 268 | if (!iswblank(buf->contents[i])) |
265 | 269 | return false; |
266 | 270 | return true; |