• R/O
  • SSH
  • HTTPS

yash: Commit


Commit MetaInfo

Revision3799 (tree)
Time2017-10-08 15:30:49
Authormagicant

Log Message

Substitute alias recursively after another (#37543)

Change Summary

Incremental Difference

--- yash/trunk/NEWS (revision 3798)
+++ yash/trunk/NEWS (revision 3799)
@@ -13,6 +13,12 @@
1313 * The shell now reads and executes all shell commands line by line.
1414 Previously, commands that are not from a file or the standard
1515 input were parsed all at once before being executed.
16+ * After alias substitution where the alias value ends with a blank,
17+ the next word is also subject to alias substitution, but
18+ previously this substitution was being applied only once, which
19+ was a different behavior from many other shells.
20+ * After alias substitution where the alias value ends with a blank,
21+ global aliases were being applied twice, which is now just once.
1622
1723 ----------------------------------------------------------------------
1824 Yash 2.45
--- yash/trunk/parser.c (revision 3798)
+++ yash/trunk/parser.c (revision 3799)
@@ -1194,7 +1194,7 @@
11941194 void parse_redirect_list(parsestate_T *ps, redir_T **lastp)
11951195 {
11961196 for (;;) {
1197- if (!posixly_correct && ps->enable_alias)
1197+ if (ps->enable_alias)
11981198 if (count_name_length(ps, is_alias_name_char) > 0)
11991199 substitute_alias(&ps->src, ps->index, &ps->aliases, 0);
12001200
--- yash/trunk/alias.c (revision 3798)
+++ yash/trunk/alias.c (revision 3799)
@@ -67,7 +67,9 @@
6767 * infinite recursive substitution of an alias. When an alias is substituted,
6868 * the alias and the end index of the substituted string are saved in the list.
6969 * Substitution of the same alias is not performed before the saved index,
70- * thus preventing recursive substitution. */
70+ * thus preventing recursive substitution.
71+ * `aliaslist_T' is also used to indicate which command words are subject to
72+ * substitution after another substitution that ends with a blank. */
7173
7274 static void free_alias(alias_T *alias);
7375 static inline void vfreealias(kvpair_T kv);
@@ -87,6 +89,8 @@
8789 static size_t remove_expired_aliases(aliaslist_T **list, size_t index)
8890 __attribute__((nonnull));
8991 static void shift_index(aliaslist_T *list, ptrdiff_t inc);
92+static bool is_after_blank(size_t i, size_t j, const xwcsbuf_T *buf)
93+ __attribute__((nonnull));
9094 static bool is_redir_fd(const wchar_t *s)
9195 __attribute__((nonnull,pure));
9296 static bool print_alias(const wchar_t *name, const alias_T *alias, bool prefix);
@@ -271,8 +275,24 @@
271275 }
272276 }
273277
278+/* Tests if the character just before `i` in `buf' is a blank and all the
279+ * characters between `i' and `j' are blanks. */
280+bool is_after_blank(size_t i, size_t j, const xwcsbuf_T *buf)
281+{
282+ assert(i <= j);
283+ assert(j <= buf->length);
284+
285+ if (i == 0)
286+ return false;
287+ for (i--; i < j; i++)
288+ if (!iswblank(buf->contents[i]))
289+ return false;
290+ return true;
291+}
292+
274293 /* Performs alias substitution at index `i' in buffer `buf'.
275- * If AF_NONGLOBAL is not in `flags', only global aliases are substituted.
294+ * If AF_NONGLOBAL is not in `flags' and `i' is not after another substitution
295+ * that ends with a blank, only global aliases are substituted.
276296 * If AF_NORECUR is not in `flags', substitution is repeated until there is
277297 * no more alias applicable.
278298 * Returns true iff any alias was substituted. */
@@ -281,13 +301,17 @@
281301 {
282302 if (aliases.count == 0)
283303 return false;
304+
305+ size_t lastlimitindex = remove_expired_aliases(list, i);
306+ if (is_after_blank(lastlimitindex, i, buf))
307+ flags |= AF_NONGLOBAL;
308+
284309 if (!(flags & AF_NONGLOBAL) && posixly_correct)
285310 return false;
286311
287312 bool subst = false;
288313
289-substitute_alias:
290- remove_expired_aliases(list, i);
314+substitute_alias:;
291315
292316 /* count the length of the alias name */
293317 size_t j = i;
@@ -319,17 +343,6 @@
319343 (ptrdiff_t) alias->valuelen - (ptrdiff_t) (j - i));
320344 subst = true;
321345
322- /* substitute the following word if AF_BLANKEND is set */
323- /* see note below */
324- if ((alias->flags & AF_BLANKEND) && !(alias->flags & AF_GLOBAL)) {
325- size_t ii = i + alias->valuelen;
326- aliaslist_T *savelist = clone_aliaslist(*list);
327- while (iswblank(buf->contents[ii]))
328- ii++;
329- substitute_alias(buf, ii, &savelist, flags);
330- destroy_aliaslist(savelist);
331- }
332-
333346 /* add the alias to the list to track recursion */
334347 add_to_aliaslist(list, alias, i + alias->valuelen);
335348
@@ -343,12 +356,6 @@
343356 }
344357 return subst;
345358 }
346-/* When the value of the alias ends with a blank, we substitute the following
347- * word if and only if the alias is not global. This is required to prevent
348- * infinite substitution that would happen in some cases such as:
349- * alias -g a='a a '
350- * echo a
351- */
352359
353360 /* Returns true iff the specified string starts with any number of digits
354361 * followed by L'<' or L'>'. */
Show on old repository browser