Commit 1be00775 authored by Daniel Kahn Gillmor's avatar Daniel Kahn Gillmor

Import Upstream version 5.0~beta1

parent 9bb82638
File added
This source diff could not be displayed because it is too large. You can view the blob instead.
This document details the changes between this version, bash-5.0-beta, and
the previous version, bash-5.0-alpha.
1. Changes to Bash
a. Fixed a bug that allowed subshells to "inherit" enclosing loops -- this
is where POSIX says the subshell is not "enclosed" by the loop.
b. Added more UTF-8-specific versions of multibyte functions, and optimized
existing functions if the current locale uses UTF-8 encoding.
c. In POSIX mode, assignments preceding regular builtins should not persist
when the builtin completes.
d. Added additional checks to special array assignment (e.g., BASH_ALIASES)
so it can't be used to bypass validity checks performed in other places.
e. The `!!' history expansion now refers to the previous history entry as
expected, even if used on the second or subsequent line of a multi-line
history entry.
f. Fixed a bug that could cause the shell to dereference a NULL pointer if
the environment (`environ') is set to NULL.
g. Bash uses slightly better integer overflow handling for brace sequence
expansion on systems where ints are 32 bits and intmax_t is 64 bits.
h. Fixed a bug setting attributes for a variable named as an argument to
`declare' that also appears as a nameref in the temporary environment.
i. Fixed several bugs that could cause assignments to namerefs to create
variables with invalid names.
j. Fixed a bug that could result in the SIGINT handler being set incorrectly
in asynchronous subshells.
k. Fixed a bug that could cause `bash -t' to not execute the specified command.
l. Fixed several bugs that caused the shell to operate on the wrong variable
when using namerefs with the same name as a global variable in shell
functions.
m. Internal changes to how the shell handles variables with invalid names in
the initial environment and to prevent variables with invalid names from
being added to the environment instead of passing them on to children.
n. Changes to make sure that an expansion that results in a quoted null string
is reflected in the expansion, even if the word expands to nothing.
o. Changes to make sure that $* and ${array[*]} (and $@/${array[@]}) expand
the same way after the recent changes for POSIX interpretation 888.
p. Saving and restoring the positional parameters at function entry and exit
is considerably more efficient; noticeably so when there are large numbers
of positional parameters.
q. Fixed a bug that caused `lastpipe' and `pipefail' to return an incorrect
status for the pipeline if there was more than one external command in a
loop body appearing in the last pipeline element.
r. Fixed a bug that caused value conversion errors with the printf builtin's
%u and %f conversion specifications and invalid constants.
2. Changes to Readline
a. Added more UTF-8-specific versions of multibyte functions, and optimized
existing functions if the current locale uses UTF-8 encoding.
b. Fixed a problem with bracketed-paste inserting more than one character and
interacting with other readline functions.
c. Fixed a bug that caused the history library to attempt to append a history
line to a non-existent history entry.
d. If using bracketed paste mode, output a newline after the \r that is the
last character of the mode disable string to avoid overwriting output.
e. Fixes to the vi-mode `b', `B', `w', `W', `e', and `E' commands to better
handle multibyte characters.
f. Fixed a redisplay problem that caused an extra newline to be generated on
accept-line when the line length is exactly the screenwidth.
3. New Features in Bash
a. Bash no longer allows variable assignments preceding a special builtin that
changes variable attributes to propagate back to the calling environment
unless the compatibility level is 44 or lower.
b. You can set the default value for $HISTSIZE at build time in config-top.h.
c. The `complete' builtin now accepts a -I option that applies the completion
to the initial word on the line.
d. The internal bash malloc now uses mmap (if available) to satisfy requests
greater than 128K bytes, so free can use mfree to return the pages to the
kernel.
e. The shell doesn't automatically set BASH_ARGC and BASH_ARGV at startup
unless it's in debugging mode, as the documentation has always said, but
will dynamically create them if a script references them at the top level
without having enabled debugging mode.
f. The localvar_inherit option will not attempt to inherit a value from a
variable of an incompatible type (indexed vs. associative arrays, for
example).
g. The `globasciiranges' option is now enabled by default; it can be set to
off by default at configuration time.
4. New Features in Readline
a. The history expansion library now understands command and process
substitution and extended globbing and allows them to appear anywhere in a
word.
b. The history library has a new variable that allows applications to set the
initial quoting state, so quoting state can be inherited from a previous
line.
------------------------------------------------------------------------------
This document details the changes between this version, bash-5.0-alpha, and
the previous version, bash-4.4-release.
......@@ -195,11 +316,11 @@ kkk. Fixed a problem with arithmetic expressions containing array references
lll. The `select' command and help builtin will use $COLUMNS before the window
size returned from the kernel as the terminal width.
mmm. `read -n 0' and `read -N 0' now try a zero-length read to attempt to
mmm. `read -n 0' and `read -N 0' now try a zero-length read in an attempt to
detect file descriptor errors.
nnn. The `read' builtin now does a better job of acting on signals that don't
interrrupt read(2).
interrupt read(2).
ooo. Fixed some cases where `printf -v' did not return failure status on a
variable assignment error.
......@@ -208,7 +329,7 @@ ppp. Fixed temporary environment propagation back to the current environment
so that it doesn't happen for special builtins run by the `command'
builtin.
qqq. Fixed a bug when searhing for the end of a here-document delimiter in a
qqq. Fixed a bug when searching for the end of a here-document delimiter in a
command substitution.
rrr. Fixed a bug that could cause `cd ${DIRSTACK[0]}' to fail.
......@@ -359,7 +480,7 @@ d. Added support for keyboard timeouts when an ESC character is the last
e. There are several performance improvements when in a UTF-8 locale.
f. Readline does a better job of preserving the original set of blocked =
f. Readline does a better job of preserving the original set of blocked
signals when using pselect() to wait for input.
g. Fixed a bug that caused multibyte characters in macros to be mishandled.
......
......@@ -396,6 +396,15 @@ above.
BASH_ARGC and BASH_ARGV is available at compatibility levels less than
or equal to 44.
61. Bash-5.0 doesn't allow a `break' or `continue' in a subshell to attempt
to break or continue loop execution inherited from the calling context.
62. Bash-5.0 doesn't allow variable assignments preceding builtins like
export and readonly to modify variables with the same name in preceding
contexts (including the global context) unless the shell is in posix
mode, since export and readonly are special builtins.
Shell Compatibility Level
=========================
......@@ -451,15 +460,22 @@ compat43 set
(declare -a foo='(1 2)')
- word expansion errors are considered non-fatal errors that cause the
current command to fail, even in Posix mode
- when executing a shell function, the loop state (while/until/etc.) is
not reset, so `break' or `continue' in a shell function will break or
continue loops in the calling context. Bash-4.4 and later reset the
loop state to prevent this.
- when executing a shell function, the loop state (while/until/etc.)
is not reset, so `break' or `continue' in that function will break
or continue loops in the calling context. Bash-4.4 and later reset
the loop state to prevent this.
compat44 set
- the shell sets up the values used by BASH_ARGV and BASH_ARGC so
they can expand to the shell's positional parameters even if extended
debug mode is not enabled
- a subshell inherits loops from its parent contenxt, so `break'
or `continue' will cause the subshell to exit
- variable assignments preceding builtins like export and readonly
that set attributes continue to affect variables with the same
name in the calling environment even if the shell is not in posix
mode
-------------------------------------------------------------------------------
......
This diff is collapsed.
......@@ -248,8 +248,8 @@ and linked, rather than changing run-time features.
'--enable-largefile'
Enable support for large files
(http://www.sas.com/standards/large_file/x_open.20Mar96.html) if
the operating system requires special compiler options to build
(http://www.unix.org/version2/whatsnew/lfs20mar.html) if the
operating system requires special compiler options to build
programs which can access large files. This is enabled by default,
if the operating system provides large file support.
......
......@@ -453,6 +453,7 @@ lib/sh/tmpfile.c f
lib/sh/uconvert.c f
lib/sh/ufuncs.c f
lib/sh/unicode.c f
lib/sh/utf8.c f
lib/sh/vprint.c f
lib/sh/wcsdup.c f
lib/sh/wcsnwidth.c f
......@@ -868,6 +869,7 @@ tests/array22.sub f
tests/array23.sub f
tests/array24.sub f
tests/array25.sub f
tests/array26.sub f
tests/array-at-star f
tests/array2.right f
tests/assoc.tests f
......@@ -881,6 +883,7 @@ tests/assoc6.sub f
tests/assoc7.sub f
tests/assoc8.sub f
tests/assoc9.sub f
tests/assoc10.sub f
tests/attr.tests f
tests/attr.right f
tests/attr1.sub f
......@@ -1072,6 +1075,8 @@ tests/histexp1.sub f
tests/histexp2.sub f
tests/histexp3.sub f
tests/histexp4.sub f
tests/histexp5.sub f
tests/histexp6.sub f
tests/histexp.right f
tests/history.tests f
tests/history.right f
......@@ -1136,6 +1141,8 @@ tests/nameref16.sub f
tests/nameref17.sub f
tests/nameref18.sub f
tests/nameref19.sub f
tests/nameref20.sub f
tests/nameref21.sub f
tests/nameref.right f
tests/new-exp.tests f
tests/new-exp1.sub f
......@@ -1179,6 +1186,7 @@ tests/posixexp3.sub f
tests/posixexp4.sub f
tests/posixexp5.sub f
tests/posixexp6.sub f
tests/posixexp7.sub f
tests/posixexp2.tests f
tests/posixexp2.right f
tests/posixpat.tests f
......@@ -1199,6 +1207,7 @@ tests/procsub1.sub f
tests/quote.tests f
tests/quote.right f
tests/quote1.sub f
tests/quote2.sub f
tests/read.tests f
tests/read.right f
tests/read1.sub f
......@@ -1352,7 +1361,7 @@ tests/unicode1.sub f
tests/unicode2.sub f
tests/unicode3.sub f
tests/varenv.right f
tests/varenv.sh f
tests/varenv.tests f
tests/varenv1.sub f
tests/varenv2.sub f
tests/varenv3.sub f
......@@ -1365,6 +1374,10 @@ tests/varenv9.sub f
tests/varenv10.sub f
tests/varenv11.sub f
tests/varenv12.sub f
tests/varenv13.sub f
tests/varenv14.sub f
tests/varenv15.sub f
tests/varenv15.in f
tests/version f
tests/version.mini f
tests/vredir.tests f
......
# Makefile for bash-5.0, version 4.25
# Makefile for bash-5.0, version 4.27
#
# Copyright (C) 1996-2018 Free Software Foundation, Inc.
......@@ -41,6 +41,7 @@ infodir = @infodir@
includedir = @includedir@
datadir = @datadir@
localedir = @localedir@
pkgconfigdir = ${libdir}/pkgconfig
loadablesdir = @loadablesdir@
headersdir = @headersdir@
......@@ -230,7 +231,7 @@ SHLIB_SOURCE = ${SH_LIBSRC}/clktck.c ${SH_LIBSRC}/getcwd.c \
${SH_LIBSRC}/input_avail.c ${SH_LIBSRC}/mbscasecmp.c \
${SH_LIBSRC}/fnxform.c ${SH_LIBSRC}/unicode.c \
${SH_LIBSRC}/wcswidth.c ${SH_LIBSRC}/wcsnwidth.c \
${SH_LIBSRC}/shmbchar.c
${SH_LIBSRC}/shmbchar.c ${SH_LIBSRC}/utf8.c
SHLIB_LIB = -lsh
SHLIB_LIBNAME = libsh.a
......@@ -834,7 +835,7 @@ install-headers-dirs:
@${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(headersdir)
@${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(headersdir)/builtins
@${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(headersdir)/include
@${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(libdir)/pkgconfig
@${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(pkgconfigdir)
install-headers: install-headers-dirs
@for hf in $(INSTALLED_HEADERS) ; do \
......@@ -849,14 +850,14 @@ install-headers: install-headers-dirs
@for hf in $(CREATED_HEADERS) ; do \
${INSTALL_DATA} $(BUILD_DIR)/"$$hf" $(DESTDIR)$(headersdir)/$$hf; \
done
$(INSTALL_DATA) $(SDIR)/bash.pc $(DESTDIR)$(libdir)/pkgconfig/bash.pc
-$(INSTALL_DATA) $(SDIR)/bash.pc $(DESTDIR)$(pkgconfigdir)/bash.pc
uninstall-headers:
-( cd $(DESTDIR)$(headersdir) && $(RM) $(INSTALLED_HEADERS) )
-( cd $(DESTDIR)$(headersdir)/include && $(RM) $(INSTALLED_INCFILES) )
-( cd $(DESTDIR)$(headersdir)/builtins && $(RM) $(INSTALLED_BUILTINS_HEADERS) )
-( cd $(DESTDIR)$(headersdir) && $(RM) $(CREATED_HEADERS) )
-( $(RM) $(DESTDIR)$(libdir)/pkgconfig/bash.pc )
-( $(RM) $(DESTDIR)$(pkgconfigdir)/bash.pc )
uninstall: .made
$(RM) $(DESTDIR)$(bindir)/$(Program) $(DESTDIR)$(bindir)/bashbug
......
......@@ -85,6 +85,31 @@ z. The `times' builtin now honors the current locale when printing a decimal
aa. There is a new (disabled by default, undocumented) shell option to enable
and disable sending history to syslog at runtime.
bb. Bash no longer allows variable assignments preceding a special builtin that
changes variable attributes to propagate back to the calling environment
unless the compatibility level is 44 or lower.
cc. You can set the default value for $HISTSIZE at build time in config-top.h.
dd. The `complete' builtin now accepts a -I option that applies the completion
to the initial word on the line.
ee. The internal bash malloc now uses mmap (if available) to satisfy requests
greater than 128K bytes, so free can use mfree to return the pages to the
kernel.
ff. The shell doesn't automatically set BASH_ARGC and BASH_ARGV at startup
unless it's in debugging mode, as the documentation has always said, but
will dynamically create them if a script references them at the top level
without having enabled debugging mode.
gg. The localvar_inherit option will not attempt to inherit a value from a
variable of an incompatible type (indexed vs. associative arrays, for
example).
hh. The `globasciiranges' option is now enabled by default; it can be set to
off by default at configuration time.
2. New Features in Readline
a. Non-incremental vi-mode search (`N', `n') can search for a shell pattern, as
......@@ -112,6 +137,14 @@ g. There is a simple variable comparison facility available for use within an
either `on' or `off'; variable names are separated from the operator by
whitespace.
h. The history expansion library now understands command and process
substitution and extended globbing and allows them to appear anywhere in a
word.
i. The history library has a new variable that allows applications to set the
initial quoting state, so quoting state can be inherited from a previous
line.
-------------------------------------------------------------------------------
This is a terse description of the new features added to bash-4.4 since
the release of bash-4.3. As always, the manual page (doc/bash.1) is
......
This diff is collapsed.
......@@ -1307,7 +1307,7 @@ AC_CACHE_VAL(bash_cv_must_reinstall_sighandlers,
typedef RETSIGTYPE sigfunc();
int nsigint;
volatile int nsigint;
#ifdef HAVE_POSIX_SIGNALS
sigfunc *
......
......@@ -406,8 +406,8 @@ int starsub, quoted;
ARRAY *a2;
ARRAY_ELEMENT *h, *p;
arrayind_t i;
char *ifs, *sifs, *t;
int slen;
char *t;
WORD_LIST *wl;
p = a ? array_head (a) : 0;
if (p == 0 || array_empty (a) || start > array_max_index(a))
......@@ -432,32 +432,12 @@ int starsub, quoted;
a2 = array_slice(a, h, p);
if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
array_quote(a2);
else
array_quote_escapes(a2);
if (starsub && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) {
/* ${array[*]} */
array_remove_quoted_nulls (a2);
sifs = ifs_firstchar ((int *)NULL);
t = array_to_string (a2, sifs, 0);
free (sifs);
} else if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) {
/* ${array[@]} */
sifs = ifs_firstchar (&slen);
ifs = getifs ();
if (ifs == 0 || *ifs == 0) {
if (slen < 2)
sifs = xrealloc(sifs, 2);
sifs[0] = ' ';
sifs[1] = '\0';
}
t = array_to_string (a2, sifs, 0);
free (sifs);
} else
t = array_to_string (a2, " ", 0);
wl = array_to_word_list(a2);
array_dispose(a2);
if (wl == 0)
return (char *)NULL;
t = string_list_pos_params(starsub ? '*' : '@', wl, quoted);
dispose_words(wl);
return t;
}
......@@ -468,50 +448,28 @@ ARRAY *a;
char *pat, *rep;
int mflags;
{
ARRAY *a2;
ARRAY_ELEMENT *e;
char *t, *sifs, *ifs;
int slen;
char *t;
int pchar, qflags;
WORD_LIST *wl, *save;
if (a == 0 || array_head(a) == 0 || array_empty(a))
return ((char *)NULL);
a2 = array_copy(a);
for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) {
t = pat_subst(element_value(e), pat, rep, mflags);
FREE(element_value(e));
e->value = t;
wl = array_to_word_list(a);
if (wl == 0)
return (char *)NULL;
for (save = wl; wl; wl = wl->next) {
t = pat_subst (wl->word->word, pat, rep, mflags);
FREE (wl->word->word);
wl->word->word = t;
}
if (mflags & MATCH_QUOTED)
array_quote(a2);
else
array_quote_escapes(a2);
if (mflags & MATCH_STARSUB) {
array_remove_quoted_nulls (a2);
if ((mflags & MATCH_QUOTED) == 0 && ifs_is_null)
sifs = spacesep;
else
sifs = ifs_firstchar((int *)NULL);
t = array_to_string (a2, sifs, 0);
if (sifs != spacesep)
free(sifs);
} else if (mflags & MATCH_QUOTED) {
/* ${array[@]} */
sifs = ifs_firstchar (&slen);
ifs = getifs ();
if (ifs == 0 || *ifs == 0) {
if (slen < 2)
sifs = xrealloc (sifs, 2);
sifs[0] = ' ';
sifs[1] = '\0';
}
t = array_to_string (a2, sifs, 0);
free(sifs);
} else
t = array_to_string (a2, " ", 0);
array_dispose (a2);
pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
t = string_list_pos_params (pchar, save, qflags);
dispose_words(save);
return t;
}
......@@ -523,53 +481,32 @@ char *pat;
int modop;
int mflags;
{
ARRAY *a2;
ARRAY_ELEMENT *e;
char *t, *sifs, *ifs;
int slen;
char *t;
int pchar, qflags;
WORD_LIST *wl, *save;
if (a == 0 || array_head(a) == 0 || array_empty(a))
return ((char *)NULL);
a2 = array_copy(a);
for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) {
t = sh_modcase(element_value(e), pat, modop);
FREE(element_value(e));
e->value = t;
wl = array_to_word_list(a);
if (wl == 0)
return ((char *)NULL);
for (save = wl; wl; wl = wl->next) {
t = sh_modcase(wl->word->word, pat, modop);
FREE(wl->word->word);
wl->word->word = t;
}
if (mflags & MATCH_QUOTED)
array_quote(a2);
else
array_quote_escapes(a2);
if (mflags & MATCH_STARSUB) {
array_remove_quoted_nulls (a2);
if ((mflags & MATCH_QUOTED) == 0 && ifs_is_null)
sifs = spacesep;
else
sifs = ifs_firstchar((int *)NULL);
t = array_to_string (a2, sifs, 0);
if (sifs != spacesep)
free(sifs);
} else if (mflags & MATCH_QUOTED) {
/* ${array[@]} */
sifs = ifs_firstchar (&slen);
ifs = getifs ();
if (ifs == 0 || *ifs == 0) {
if (slen < 2)
sifs = xrealloc (sifs, 2);
sifs[0] = ' ';
sifs[1] = '\0';
}
t = array_to_string (a2, sifs, 0);
free(sifs);
} else
t = array_to_string (a2, " ", 0);
array_dispose (a2);
pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
t = string_list_pos_params (pchar, save, qflags);
dispose_words(save);
return t;
}
/*
* Allocate and return a new array element with index INDEX and value
* VALUE.
......
......@@ -199,6 +199,8 @@ bind_array_var_internal (entry, ind, key, value, flags)
FREE (newval);
VUNSETATTR (entry, att_invisible); /* no longer invisible */
/* check mark_modified_variables if we ever want to export array vars */
return (entry);
}
......
......@@ -305,54 +305,29 @@ assoc_patsub (h, pat, rep, mflags)
char *pat, *rep;
int mflags;
{
BUCKET_CONTENTS *tlist;
int i, slen;
HASH_TABLE *h2;
char *t, *sifs, *ifs;
char *t;
int pchar, qflags;
WORD_LIST *wl, *save;
if (h == 0 || assoc_empty (h))
return ((char *)NULL);
h2 = assoc_copy (h);
for (i = 0; i < h2->nbuckets; i++)
for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
{
t = pat_subst ((char *)tlist->data, pat, rep, mflags);
FREE (tlist->data);
tlist->data = t;
}
if (mflags & MATCH_QUOTED)
assoc_quote (h2);
else
assoc_quote_escapes (h2);
wl = assoc_to_word_list (h);
if (wl == 0)
return (char *)NULL;
if (mflags & MATCH_STARSUB)
for (save = wl; wl; wl = wl->next)
{
assoc_remove_quoted_nulls (h2);
sifs = ifs_firstchar ((int *)NULL);
t = assoc_to_string (h2, sifs, 0);
free (sifs);
t = pat_subst (wl->word->word, pat, rep, mflags);
FREE (wl->word->word);
wl->word->word = t;
}
else if (mflags & MATCH_QUOTED)
{
/* ${array[@]} */
sifs = ifs_firstchar (&slen);
ifs = getifs ();
if (ifs == 0 || *ifs == 0)
{
if (slen < 2)
sifs = xrealloc (sifs, 2);
sifs[0] = ' ';
sifs[1] = '\0';
}
t = assoc_to_string (h2, sifs, 0);
free(sifs);
}
else
t = assoc_to_string (h2, " ", 0);
assoc_dispose (h2);
pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@';
qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0;
t = string_list_pos_params (pchar, save, qflags);
dispose_words (save);
return t;
}
......@@ -364,54 +339,29 @@ assoc_modcase (h, pat, modop, mflags)
int modop;
int mflags;
{
BUCKET_CONTENTS *tlist;
int i, slen;
HASH_TABLE *h2;
char *t, *sifs, *ifs;
char *t;
int pchar, qflags;
WORD_LIST *wl, *save;
if (h == 0 || assoc_empty (h))
return ((char *)NULL);
h2 = assoc_copy (h);
for (i = 0; i < h2->nbuckets; i++)
for (tlist = hash_items (i, h2); tlist; tlist = tlist->next)
{
t = sh_modcase ((char *)tlist->data, pat, modop);
FREE (tlist->data);
tlist->data = t;
}
if (mflags & MATCH_QUOTED)
assoc_quote (h2);
else
assoc_quote_escapes (h2);
wl = assoc_to_word_list (h);
if (wl == 0)
return ((char *)NULL);
if (mflags & MATCH_STARSUB)
{
assoc_remove_quoted_nulls (h2);
sifs = ifs_firstchar ((int *)NULL);
t = assoc_to_string (h2, sifs, 0);
free (sifs);
}
else if (mflags & MATCH_QUOTED)
for (save = wl; wl; wl = wl->next)
{
/* ${array[@]} */
sifs = ifs_firstchar (&slen);
ifs = getifs ();
if (ifs == 0 || *ifs == 0)
{
if (slen < 2)
sifs = xrealloc (sifs, 2);
sifs[0] = ' ';
sifs[1] = '\0';
}