readline changes for MSVC wide chars; check for more write errors

This commit is contained in:
Chet Ramey
2021-07-16 15:11:03 -04:00
parent 9e3495c9e9
commit 8ede7a904f
19 changed files with 165 additions and 69 deletions
+21
View File
@@ -10713,3 +10713,24 @@ lib/readline/misc.c
calling _rl_free_history_entry directly. Fixes memory leak reported
by Trung Dam <trungdam@yahoo.com>
7/12
----
lib/readline/search.c
- make_history_line_current: free rl_undo_list before replacing the
current line with the line from history, since it is a private
undo list from reading the search string
lib/readline/rlmbutil.h
- Since wchar_t/mbrtowc/wcrtomb are limited to 16 bits on Windows
with MSVC, start abstracting the differences using WCHAR_T/
MBRTOWC/WCRTOMB
7/13
----
lib/readline/{complete,display,input,text,util,vi_mode}.c
- use WCHAR_T/MBRTOWC/WCRTOMB. Part of a set of Windows MSVC fixes
from sparrowhawk996@gmail.com
builtins/{enable,hash,help}.def
- enable_builtin: use sh_chkwrite after output to check for write errors
+1
View File
@@ -987,6 +987,7 @@ tests/comsub1.sub f
tests/comsub2.sub f
tests/comsub3.sub f
tests/comsub4.sub f
tests/comsub5.sub f
tests/comsub-eof.tests f
tests/comsub-eof0.sub f
tests/comsub-eof1.sub f
+1
View File
@@ -178,6 +178,7 @@ enable_builtin (list)
filter |= SPECIAL;
list_some_builtins (filter);
result = sh_chkwrite (EXECUTION_SUCCESS);
}
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
else if (flags & FFLAG)
+1 -1
View File
@@ -138,7 +138,7 @@ hash_builtin (list)
(list_portably == 0 || shell_compatibility_level <= 50))
printf (_("%s: hash table empty\n"), this_command_name);
return (EXECUTION_SUCCESS);
return (sh_chkwrite (EXECUTION_SUCCESS));
}
if (expunge_hash_table)
+1 -2
View File
@@ -186,8 +186,7 @@ help_builtin (list)
return (EXECUTION_FAILURE);
}
fflush (stdout);
return (EXECUTION_SUCCESS);
return (sh_chkwrite (EXECUTION_SUCCESS));
}
void
+13 -13
View File
@@ -757,7 +757,7 @@ fnwidth (const char *string)
mbstate_t ps;
int left, w;
size_t clen;
wchar_t wc;
WCHAR_T wc;
left = strlen (string) + 1;
memset (&ps, 0, sizeof (mbstate_t));
@@ -774,7 +774,7 @@ fnwidth (const char *string)
else
{
#if defined (HANDLE_MULTIBYTE)
clen = mbrtowc (&wc, string + pos, left - pos, &ps);
clen = MBRTOWC (&wc, string + pos, left - pos, &ps);
if (MB_INVALIDCH (clen))
{
width++;
@@ -812,7 +812,7 @@ fnprint (const char *to_print, int prefix_bytes, const char *real_pathname)
const char *end;
size_t tlen;
int width;
wchar_t wc;
WCHAR_T wc;
print_len = strlen (to_print);
end = to_print + print_len + 1;
@@ -880,7 +880,7 @@ fnprint (const char *to_print, int prefix_bytes, const char *real_pathname)
else
{
#if defined (HANDLE_MULTIBYTE)
tlen = mbrtowc (&wc, s, end - s, &ps);
tlen = MBRTOWC (&wc, s, end - s, &ps);
if (MB_INVALIDCH (tlen))
{
tlen = 1;
@@ -1321,7 +1321,7 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
int v;
size_t v1, v2;
mbstate_t ps1, ps2;
wchar_t wc1, wc2;
WCHAR_T wc1, wc2;
#endif
/* If only one match, just use that. Otherwise, compare each
@@ -1353,8 +1353,8 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{
v1 = mbrtowc(&wc1, match_list[i]+si, strlen (match_list[i]+si), &ps1);
v2 = mbrtowc (&wc2, match_list[i+1]+si, strlen (match_list[i+1]+si), &ps2);
v1 = MBRTOWC (&wc1, match_list[i]+si, strlen (match_list[i]+si), &ps1);
v2 = MBRTOWC (&wc2, match_list[i+1]+si, strlen (match_list[i+1]+si), &ps2);
if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2))
{
if (c1 != c2) /* do byte comparison */
@@ -1364,7 +1364,7 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
if (_rl_completion_case_fold)
{
wc1 = towlower (wc1);
wc2 = towlower (wc2);
wc2 = towlower (wc2);
}
if (wc1 != wc2)
break;
@@ -2330,7 +2330,7 @@ complete_fncmp (const char *convfn, int convlen, const char *filename, int filen
#if defined (HANDLE_MULTIBYTE)
size_t v1, v2;
mbstate_t ps1, ps2;
wchar_t wc1, wc2;
WCHAR_T wc1, wc2;
#endif
#if defined (HANDLE_MULTIBYTE)
@@ -2357,8 +2357,8 @@ complete_fncmp (const char *convfn, int convlen, const char *filename, int filen
{
do
{
v1 = mbrtowc (&wc1, s1, convlen, &ps1);
v2 = mbrtowc (&wc2, s2, filename_len, &ps2);
v1 = MBRTOWC (&wc1, s1, convlen, &ps1);
v2 = MBRTOWC (&wc2, s2, filename_len, &ps2);
if (v1 == 0 && v2 == 0)
return 1;
else if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2))
@@ -2407,8 +2407,8 @@ complete_fncmp (const char *convfn, int convlen, const char *filename, int filen
{
do
{
v1 = mbrtowc (&wc1, s1, convlen, &ps1);
v2 = mbrtowc (&wc2, s2, filename_len, &ps2);
v1 = MBRTOWC (&wc1, s1, convlen, &ps1);
v2 = MBRTOWC (&wc2, s2, filename_len, &ps2);
if (v1 == 0 && v2 == 0)
return 1;
else if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2))
+15 -15
View File
@@ -749,7 +749,7 @@ rl_redisplay (void)
int hl_begin, hl_end;
int mb_cur_max = MB_CUR_MAX;
#if defined (HANDLE_MULTIBYTE)
wchar_t wc;
WCHAR_T wc;
size_t wc_bytes;
int wc_width;
mbstate_t ps;
@@ -983,11 +983,11 @@ rl_redisplay (void)
memset (&ps, 0, sizeof (mbstate_t));
if (_rl_utf8locale && UTF8_SINGLEBYTE(rl_line_buffer[0]))
{
wc = (wchar_t)rl_line_buffer[0];
wc = (WCHAR_T)rl_line_buffer[0];
wc_bytes = 1;
}
else
wc_bytes = mbrtowc (&wc, rl_line_buffer, rl_end, &ps);
wc_bytes = MBRTOWC (&wc, rl_line_buffer, rl_end, &ps);
}
else
wc_bytes = 1;
@@ -1158,12 +1158,12 @@ rl_redisplay (void)
in += wc_bytes;
if (_rl_utf8locale && UTF8_SINGLEBYTE(rl_line_buffer[in]))
{
wc = (wchar_t)rl_line_buffer[in];
wc = (WCHAR_T)rl_line_buffer[in];
wc_bytes = 1;
memset (&ps, 0, sizeof (mbstate_t)); /* re-init state */
}
else
wc_bytes = mbrtowc (&wc, rl_line_buffer + in, rl_end - in, &ps);
wc_bytes = MBRTOWC (&wc, rl_line_buffer + in, rl_end - in, &ps);
}
else
in++;
@@ -1662,7 +1662,7 @@ update_line (char *old, char *old_face, char *new, char *new_face, int current_l
#if defined (HANDLE_MULTIBYTE)
if (mb_cur_max > 1 && rl_byte_oriented == 0)
{
wchar_t wc;
WCHAR_T wc;
mbstate_t ps;
int oldwidth, newwidth;
int oldbytes, newbytes;
@@ -1681,7 +1681,7 @@ update_line (char *old, char *old_face, char *new, char *new_face, int current_l
/* 1. how many screen positions does first char in old consume? */
memset (&ps, 0, sizeof (mbstate_t));
ret = mbrtowc (&wc, old, mb_cur_max, &ps);
ret = MBRTOWC (&wc, old, mb_cur_max, &ps);
oldbytes = ret;
if (MB_INVALIDCH (ret))
{
@@ -1697,7 +1697,7 @@ update_line (char *old, char *old_face, char *new, char *new_face, int current_l
/* 2. how many screen positions does the first char in new consume? */
memset (&ps, 0, sizeof (mbstate_t));
ret = mbrtowc (&wc, new, mb_cur_max, &ps);
ret = MBRTOWC (&wc, new, mb_cur_max, &ps);
newbytes = ret;
if (MB_INVALIDCH (ret))
{
@@ -1718,7 +1718,7 @@ update_line (char *old, char *old_face, char *new, char *new_face, int current_l
{
int t;
ret = mbrtowc (&wc, new+newbytes, mb_cur_max, &ps);
ret = MBRTOWC (&wc, new+newbytes, mb_cur_max, &ps);
if (MB_INVALIDCH (ret))
{
newwidth += 1;
@@ -1740,7 +1740,7 @@ update_line (char *old, char *old_face, char *new, char *new_face, int current_l
{
int t;
ret = mbrtowc (&wc, old+oldbytes, mb_cur_max, &ps);
ret = MBRTOWC (&wc, old+oldbytes, mb_cur_max, &ps);
if (MB_INVALIDCH (ret))
{
oldwidth += 1;
@@ -1952,14 +1952,14 @@ update_line (char *old, char *old_face, char *new, char *new_face, int current_l
#if defined (HANDLE_MULTIBYTE)
if (mb_cur_max > 1 && rl_byte_oriented == 0 && _rl_utf8locale)
{
wchar_t wc;
WCHAR_T wc;
mbstate_t ps = { 0 };
int t;
/* If the first character in the difference is a zero-width character,
assume it's a combining character and back one up so the two base
characters no longer compare equivalently. */
t = mbrtowc (&wc, ofd, mb_cur_max, &ps);
t = MBRTOWC (&wc, ofd, mb_cur_max, &ps);
if (t > 0 && UNICODE_COMBINING_CHAR (wc) && WCWIDTH (wc) == 0)
{
old_offset = _rl_find_prev_mbchar (old, ofd - old, MB_FIND_ANY);
@@ -3466,7 +3466,7 @@ _rl_refresh_line (void)
static int
_rl_col_width (const char *str, int start, int end, int flags)
{
wchar_t wc;
WCHAR_T wc;
mbstate_t ps;
int tmp, point, width, max;
@@ -3535,10 +3535,10 @@ _rl_col_width (const char *str, int start, int end, int flags)
if (_rl_utf8locale && UTF8_SINGLEBYTE(str[point]))
{
tmp = 1;
wc = (wchar_t) str[point];
wc = (WCHAR_T) str[point];
}
else
tmp = mbrtowc (&wc, str + point, max, &ps);
tmp = MBRTOWC (&wc, str + point, max, &ps);
if (MB_INVALIDCH ((size_t)tmp))
{
/* In this case, the bytes are invalid or too short to compose a
+2 -2
View File
@@ -930,7 +930,7 @@ _rl_read_mbchar (char *mbchar, int size)
{
int mb_len, c;
size_t mbchar_bytes_length;
wchar_t wc;
WCHAR_T wc;
mbstate_t ps, ps_back;
memset(&ps, 0, sizeof (mbstate_t));
@@ -946,7 +946,7 @@ _rl_read_mbchar (char *mbchar, int size)
mbchar[mb_len++] = c;
mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps);
mbchar_bytes_length = MBRTOWC (&wc, mbchar, mb_len, &ps);
if (mbchar_bytes_length == (size_t)(-1))
break; /* invalid byte sequence for the current locale */
else if (mbchar_bytes_length == (size_t)(-2))
+18 -18
View File
@@ -1,6 +1,6 @@
/* mbutil.c -- readline multibyte character utility functions */
/* Copyright (C) 2001-2020 Free Software Foundation, Inc.
/* Copyright (C) 2001-2021 Free Software Foundation, Inc.
This file is part of the GNU Readline Library (Readline), a library
for reading lines of text with interactive input and history editing.
@@ -153,7 +153,7 @@ _rl_find_next_mbchar_internal (char *string, int seed, int count, int find_non_z
size_t tmp, len;
mbstate_t ps;
int point;
wchar_t wc;
WCHAR_T wc;
tmp = 0;
@@ -183,11 +183,11 @@ _rl_find_next_mbchar_internal (char *string, int seed, int count, int find_non_z
if (_rl_utf8locale && UTF8_SINGLEBYTE(string[point]))
{
tmp = 1;
wc = (wchar_t) string[point];
wc = (WCHAR_T) string[point];
memset(&ps, 0, sizeof(mbstate_t));
}
else
tmp = mbrtowc (&wc, string+point, len, &ps);
tmp = MBRTOWC (&wc, string+point, len, &ps);
if (MB_INVALIDCH ((size_t)tmp))
{
/* invalid bytes. assume a byte represents a character */
@@ -216,11 +216,11 @@ _rl_find_next_mbchar_internal (char *string, int seed, int count, int find_non_z
if (find_non_zero)
{
tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
tmp = MBRTOWC (&wc, string + point, strlen (string + point), &ps);
while (MB_NULLWCH (tmp) == 0 && MB_INVALIDCH (tmp) == 0 && WCWIDTH (wc) == 0)
{
point += tmp;
tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
tmp = MBRTOWC (&wc, string + point, strlen (string + point), &ps);
}
}
@@ -231,11 +231,11 @@ static inline int
_rl_test_nonzero (char *string, int ind, int len)
{
size_t tmp;
wchar_t wc;
WCHAR_T wc;
mbstate_t ps;
memset (&ps, 0, sizeof (mbstate_t));
tmp = mbrtowc (&wc, string + ind, len - ind, &ps);
tmp = MBRTOWC (&wc, string + ind, len - ind, &ps);
/* treat invalid multibyte sequences as non-zero-width */
return (MB_INVALIDCH (tmp) || MB_NULLWCH (tmp) || WCWIDTH (wc) > 0);
}
@@ -293,7 +293,7 @@ _rl_find_prev_mbchar_internal (char *string, int seed, int find_non_zero)
mbstate_t ps;
int prev, non_zero_prev, point, length;
size_t tmp;
wchar_t wc;
WCHAR_T wc;
if (_rl_utf8locale)
return (_rl_find_prev_utf8char (string, seed, find_non_zero));
@@ -312,11 +312,11 @@ _rl_find_prev_mbchar_internal (char *string, int seed, int find_non_zero)
if (_rl_utf8locale && UTF8_SINGLEBYTE(string[point]))
{
tmp = 1;
wc = (wchar_t) string[point];
wc = (WCHAR_T) string[point];
memset(&ps, 0, sizeof(mbstate_t));
}
else
tmp = mbrtowc (&wc, string + point, length - point, &ps);
tmp = MBRTOWC (&wc, string + point, length - point, &ps);
if (MB_INVALIDCH ((size_t)tmp))
{
/* in this case, bytes are invalid or too short to compose
@@ -470,27 +470,27 @@ _rl_is_mbchar_matched (char *string, int seed, int end, char *mbchar, int length
return 1;
}
wchar_t
WCHAR_T
_rl_char_value (char *buf, int ind)
{
size_t tmp;
wchar_t wc;
WCHAR_T wc;
mbstate_t ps;
int l;
if (MB_LEN_MAX == 1 || rl_byte_oriented)
return ((wchar_t) buf[ind]);
return ((WCHAR_T) buf[ind]);
if (_rl_utf8locale && UTF8_SINGLEBYTE(buf[ind]))
return ((wchar_t) buf[ind]);
return ((WCHAR_T) buf[ind]);
l = strlen (buf);
if (ind >= l - 1)
return ((wchar_t) buf[ind]);
return ((WCHAR_T) buf[ind]);
if (l < ind) /* Sanity check */
l = strlen (buf+ind);
memset (&ps, 0, sizeof (mbstate_t));
tmp = mbrtowc (&wc, buf + ind, l - ind, &ps);
tmp = MBRTOWC (&wc, buf + ind, l - ind, &ps);
if (MB_INVALIDCH (tmp) || MB_NULLWCH (tmp))
return ((wchar_t) buf[ind]);
return ((WCHAR_T) buf[ind]);
return wc;
}
#endif /* HANDLE_MULTIBYTE */
+1 -1
View File
@@ -631,7 +631,7 @@ rl_get_previous_history (int count, int key)
if (temp == 0)
{
if (had_saved_line == 0)
_rl_free_saved_history_line ();
_rl_free_saved_history_line ();
rl_ding ();
}
else
+16 -3
View File
@@ -81,6 +81,19 @@
/* end of multibyte capability checks for I18N */
/************************************************/
/*
* wchar_t doesn't work for 32-bit values on Windows using MSVC
*/
#ifdef WCHAR_T_BROKEN
# define WCHAR_T char32_t
# define MBRTOWC mbrtoc32
# define WCRTOMB c32rtomb
#else /* normal systems */
# define WCHAR_T wchar_t
# define MBRTOWC mbrtowc
# define WCRTOMB wcrtomb
#endif
/*
* Flags for _rl_find_prev_mbchar and _rl_find_next_mbchar:
*
@@ -105,8 +118,8 @@ extern int _rl_read_mbstring (int, char *, int);
extern int _rl_is_mbchar_matched (char *, int, int, char *, int);
extern wchar_t _rl_char_value (char *, int);
extern int _rl_walphabetic (wchar_t);
extern WCHAR_T _rl_char_value (char *, int);
extern int _rl_walphabetic (WCHAR_T);
#define _rl_to_wupper(wc) (iswlower (wc) ? towupper (wc) : (wc))
#define _rl_to_wlower(wc) (iswupper (wc) ? towlower (wc) : (wc))
@@ -127,7 +140,7 @@ extern int _rl_walphabetic (wchar_t);
calls to a libc wcwidth() */
static inline int
_rl_wcwidth (wc)
wchar_t wc;
WCHAR_T wc;
{
switch (wc)
{
+8
View File
@@ -84,6 +84,12 @@ static int _rl_nsearch_dispatch (_rl_search_cxt *, int);
static void
make_history_line_current (HIST_ENTRY *entry)
{
/* At this point, rl_undo_list points to a private search string list. */
if (rl_undo_list && rl_undo_list != (UNDO_LIST *)entry->data)
rl_free_undo_list ();
/* Now we create a new undo list with a single insert for this text.
WE DON'T CHANGE THE ORIGINAL HISTORY ENTRY UNDO LIST */
_rl_replace_text (entry->line, 0, rl_end);
_rl_fix_point (1);
#if defined (VI_MODE)
@@ -95,6 +101,8 @@ make_history_line_current (HIST_ENTRY *entry)
rl_free_undo_list ();
#endif
/* This will need to free the saved undo list associated with the original
(pre-search) line buffer. */
if (_rl_saved_line_for_history)
_rl_free_saved_history_line ();
}
+8 -8
View File
@@ -735,7 +735,7 @@ _rl_insert_char (int count, int c)
}
else
{
wchar_t wc;
WCHAR_T wc;
size_t ret;
if (stored_count <= 0)
@@ -745,7 +745,7 @@ _rl_insert_char (int count, int c)
ps_back = ps;
pending_bytes[pending_bytes_length++] = c;
ret = mbrtowc (&wc, pending_bytes, pending_bytes_length, &ps);
ret = MBRTOWC (&wc, pending_bytes, pending_bytes_length, &ps);
if (ret == (size_t)-2)
{
@@ -1404,9 +1404,9 @@ rl_change_case (int count, int op)
{
int start, next, end;
int inword, nc, nop;
wchar_t c;
WCHAR_T c;
#if defined (HANDLE_MULTIBYTE)
wchar_t wc, nwc;
WCHAR_T wc, nwc;
char mb[MB_LEN_MAX+1];
int mlen;
size_t m;
@@ -1465,9 +1465,9 @@ rl_change_case (int count, int op)
#if defined (HANDLE_MULTIBYTE)
else
{
m = mbrtowc (&wc, rl_line_buffer + start, end - start, &mps);
m = MBRTOWC (&wc, rl_line_buffer + start, end - start, &mps);
if (MB_INVALIDCH (m))
wc = (wchar_t)rl_line_buffer[start];
wc = (WCHAR_T)rl_line_buffer[start];
else if (MB_NULLWCH (m))
wc = L'\0';
nwc = (nop == UpCase) ? _rl_to_wupper (wc) : _rl_to_wlower (wc);
@@ -1477,12 +1477,12 @@ rl_change_case (int count, int op)
mbstate_t ts;
memset (&ts, 0, sizeof (mbstate_t));
mlen = wcrtomb (mb, nwc, &ts);
mlen = WCRTOMB (mb, nwc, &ts);
if (mlen < 0)
{
nwc = wc;
memset (&ts, 0, sizeof (mbstate_t));
mlen = wcrtomb (mb, nwc, &ts);
mlen = WCRTOMB (mb, nwc, &ts);
if (mlen < 0) /* should not happen */
strncpy (mb, rl_line_buffer + start, mlen = m);
}
+1 -1
View File
@@ -81,7 +81,7 @@ rl_alphabetic (int c)
#if defined (HANDLE_MULTIBYTE)
int
_rl_walphabetic (wchar_t wc)
_rl_walphabetic (WCHAR_T wc)
{
int c;
+4 -4
View File
@@ -927,7 +927,7 @@ rl_vi_arg_digit (int count, int c)
static int
_rl_vi_change_mbchar_case (int count)
{
wchar_t wc;
WCHAR_T wc;
char mb[MB_LEN_MAX+1];
int mlen, p;
size_t m;
@@ -938,9 +938,9 @@ _rl_vi_change_mbchar_case (int count)
count--;
while (count-- && rl_point < rl_end)
{
m = mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps);
m = MBRTOWC (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps);
if (MB_INVALIDCH (m))
wc = (wchar_t)rl_line_buffer[rl_point];
wc = (WCHAR_T)rl_line_buffer[rl_point];
else if (MB_NULLWCH (m))
wc = L'\0';
if (iswupper (wc))
@@ -958,7 +958,7 @@ _rl_vi_change_mbchar_case (int count)
if (wc)
{
p = rl_point;
mlen = wcrtomb (mb, wc, &ps);
mlen = WCRTOMB (mb, wc, &ps);
if (mlen >= 0)
mb[mlen] = '\0';
rl_begin_undo_group ();
+1 -1
View File
@@ -1,4 +1,4 @@
BUILD_DIR=/usr/local/build/chet/bash/bash-current
BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
+9
View File
@@ -55,3 +55,12 @@ d \
g
d \
g
ok 1
ok 2
ok 3
ok 4
ok 5
ok 6
ok 7
ok 8
ok 8
+1
View File
@@ -73,3 +73,4 @@ ${THIS_SH} ./comsub1.sub
${THIS_SH} ./comsub2.sub
${THIS_SH} ./comsub3.sub
${THIS_SH} ./comsub4.sub
${THIS_SH} ./comsub5.sub
+43
View File
@@ -0,0 +1,43 @@
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# this is a new feature: expanding aliases when initially parsing command
# substiitutions
shopt -s expand_aliases
alias switch=case
switch foo in foo) echo ok 1;; esac
echo $( switch foo in foo) echo ok 2;; esac )
echo "$( switch foo in foo) echo ok 3;; esac )"
echo $( switch foo in (foo) echo ok 4;; esac )
echo "$( switch foo in (foo) echo ok 5;; esac )"
alias nest='('
echo $( nest echo ok 6 ) )
echo "$( nest echo ok 7 ) )"
alias short='echo ok 8 )'
echo $( short
echo "$( short "
# remember that short" won't work because you start a new quoting context
# inside $( and the token (`short') won't be delimited by the ending double
# quote, so there's no opportunity to perform the alias expansion that would
# terminate the command substitution