# Tests corresponding to the `Redirection' texinfo node.

%prep
  mkdir redir.tmp && cd redir.tmp

  myfd=99
  (echo >&$myfd) 2>msg
  bad_fd_msg="${$(<msg)##*:}"

%test

  print 'This is file redir' >redir  &&  cat redir
0:'>' and '<' redirection
>This is file redir

  rm -f redir
  print 'This is still file redir' <>redir >&0  &&  cat <>redir
0:'<>' redirection
>This is still file redir

  rm -f redir
  print 'With a bar' >|redir  &&  cat redir
0:'>|' redirection
>With a bar

  rm -f redir
  print 'With a bang' >!redir  &&  cat redir
0:'>!' redirection
>With a bang

  rm -f redir
  print 'Line 1' >>redir  &&  print 'Line 2' >>redir  &&  cat redir
0:'>>' redirection
>Line 1
>Line 2

  rm -f redir
  print 'Line a' >>|redir  &&  print 'Line b' >>!redir
0:'>>|' and '>>!' redirection

  foo=bar
  cat <<'  HERE'
  $foo
  HERE
  eval "$(print 'cat <<HERE\n$foo\nHERE')"
0:Here-documents
>  $foo
>bar

  cat <<-HERE
# note tabs at the start of the following lines
	$foo$foo
	HERE
0:Here-documents stripping tabs
>barbar

  cat <<-$'$HERE '`$(THERE) `'$((AND)) '"\EVERYWHERE"
# tabs again.  sorry about the max miller.
	Here's a funny thing.  Here is a funny thing.
	I went home last night.  There's a funny thing.
	Man walks into a $foo.  Ouch, it's an iron $foo.
	$HERE `$(THERE) `$((AND)) \EVERYWHERE
0:Here-documents don't perform shell expansion on the initial word
>Here's a funny thing.  Here is a funny thing.
>I went home last night.  There's a funny thing.
>Man walks into a $foo.  Ouch, it's an iron $foo.

  cat <<-$'\x45\x4e\x44\t\x44\x4f\x43'
# tabs again
	This message is unfathomable.
	END	DOC
0:Here-documents do perform $'...' expansion on the initial word
>This message is unfathomable.

  cat <<<"This is a line with a $foo in it"
0:'<<<' redirection
>This is a line with a bar in it

  cat <<<$'a\nb\nc'
0:here-strings with $'...' quoting
>a
>b
>c

# The following tests check that output of parsed here-documents works.
# This isn't completely trivial because we convert the here-documents
# internally to here-strings.  So we check again that we can output
# the reevaluated here-strings correctly.  Hence there are three slightly
# different stages.  We don't care how the output actually looks, so
# we don't test that.
  heretest() {
    print First line
    cat <<-HERE
	$foo$foo met celeste  'but with extra'  "stuff to test quoting"
	HERE
    print Last line
  }
  heretest
  eval "$(functions heretest)"
  heretest
  eval "$(functions heretest)"
  heretest
0:Re-evaluation of function output with here document, unquoted
>First line
>barbar met celeste  'but with extra'  "stuff to test quoting"
>Last line
>First line
>barbar met celeste  'but with extra'  "stuff to test quoting"
>Last line
>First line
>barbar met celeste  'but with extra'  "stuff to test quoting"
>Last line

  heretest() {
    print First line
    cat <<'    HERE'
    $foo$foo met celeste  'but with extra'  "stuff to test quoting"
    HERE
    print Last line
  }
  heretest
  eval "$(functions heretest)"
  heretest
  eval "$(functions heretest)"
  heretest
0:Re-evaluation of function output with here document, quoted
>First line
>    $foo$foo met celeste  'but with extra'  "stuff to test quoting"
>Last line
>First line
>    $foo$foo met celeste  'but with extra'  "stuff to test quoting"
>Last line
>First line
>    $foo$foo met celeste  'but with extra'  "stuff to test quoting"
>Last line

  read -r line <<'  HERE'
  HERE
1:No input, not even newline, from empty here document.

  #
  # exec tests: perform these in subshells so if they fail the
  # shell won't exit.
  #
  (exec 3>redir  &&  print hello >&3  &&  print goodbye >&3  && cat redir)
0:'>&' redirection
>hello
>goodbye

  (exec 3<redir && read foo <&3 && print $foo && read foo <&3 && print $foo)
0:'<&' redirection
>hello
>goodbye

  ({ exec 3<&- } 2>/dev/null
  exec 3<&-
  read foo <&-)
1:'<&-' redirection
*?\(eval\):*: failed to close file descriptor 3:*

  print foo >&-
0:'>&-' redirection

  (exec >&-
  print foo)
0:'>&-' with attempt to use closed fd
*?\(eval\):2: write error:*

  fn() { local foo; read foo; print $foo; }
  coproc fn
  print test output >&p
  read bar <&p
  print $bar
0:'>&p' and '<&p' redirection
>test output

  ( print Output; print Error >& 2 ) >&errout  &&  cat errout
0:'>&FILE' handling
>Output
>Error

  rm -f errout
  ( print Output2; print Error2 >& 2 ) &>errout  &&  cat errout
0:'&>FILE' handling
>Output2
>Error2

  rm -f errout
  ( print Output3; print Error3 >& 2 ) >&|errout  &&  cat errout
  ( print Output4; print Error4 >& 2 ) >&!errout  &&  cat errout
  ( print Output5; print Error5 >& 2 ) &>|errout  &&  cat errout
  ( print Output6; print Error6 >& 2 ) &>!errout  &&
  ( print Output7; print Error7 >& 2 ) >>&errout  &&
  ( print Output8; print Error8 >& 2 ) &>>errout  &&
  ( print Output9; print Error9 >& 2 ) >>&|errout  &&
  ( print Output10; print Error10 >& 2 ) &>>|errout  &&
  ( print Output11; print Error11 >& 2 ) >>&!errout  &&
  ( print Output12; print Error12 >& 2 ) &>>!errout  &&  cat errout
0:'>&|', '>&!', '&>|', '&>!' redirection
>Output3
>Error3
>Output4
>Error4
>Output5
>Error5
>Output6
>Error6
>Output7
>Error7
>Output8
>Error8
>Output9
>Error9
>Output10
>Error10
>Output11
>Error11
>Output12
>Error12

  rm -f errout
  ( print Output; print Error 1>&2 ) 1>errout 2>&1  && cat errout
0:'Combining > with >& (1)'
>Output
>Error

  rm -f errout
  ( print Output; print Error 1>&2 ) 2>&1 1>errout   &&  print errout:  &&
  cat errout
0:'Combining > with >& (2)'
>Error
>errout:
>Output

  rm -f errout
  print doo be doo be doo >foo >bar 
  print "foo: $(<foo)\nbar: $(<bar)"
0:2-file multio
>foo: doo be doo be doo
>bar: doo be doo be doo

  rm -f foo bar
  print dont be dont be dont >foo | sed 's/dont/wont/g' >bar
0:setup file+pipe multio

  print "foo: $(<foo)\nbar: $(<bar)"
0:read file+pipe multio
>foo: dont be dont be dont
>bar: wont be wont be wont

  rm -f *
  touch out1 out2
  print All files >*
  print *
  print "out1: $(<out1)\nout2: $(<out2)"
0:multio with globbing
>out1 out2
>out1: All files
>out2: All files

  print This is out1 >out1
  print This is out2 >out2
0:setup multio for input

# Currently, <out{1,2} doesn't work: this is a bug.
  cat <out*
0:read multio input
>This is out1
>This is out2

  cat out1 | sed s/out/bout/ <out2
0:read multio input with pipe
>This is bout1
>This is bout2

  unset NULLCMD
  >out1
1:null redir with NULLCMD unset
?(eval):2: redirection with no command

  echo this should still work >out1
  print "$(<out1)"
0:null redir in $(...) with NULLCMD unset
>this should still work

  READNULLCMD=cat
  print cat input >out1
  <out1
1:READNULLCMD with NULLCMD unset
?(eval):3: redirection with no command

  NULLCMD=:
  >out1
  [[ ! -s out1 ]] || print out1 is not empty
0:null redir with NULLCMD=:
<input

  print cat input >out1
  <out1
0:READNULLCMD
>cat input

  NULLCMD=cat
  >out1
  cat out1
0:null redir with NULLCMD=cat
<input
>input

  (myfd=
  exec {myfd}>logfile
  if [[ -z $myfd ]]; then
    print "Ooops, failed to set myfd to a file descriptor." >&2
  else
    print This is my logfile. >&$myfd
    print Examining contents of logfile...
    cat logfile
  fi)
0:Using {fdvar}> syntax to open a new file descriptor
>Examining contents of logfile...
>This is my logfile.

  (setopt noclobber
   exec {myfd}>logfile2
   echo $myfd
   exec {myfd}>logfile3) | read myfd
  (( ! ${pipestatus[1]} ))
1q:NO_CLOBBER prevents overwriting parameter with allocated fd
?(eval):4: can't clobber parameter myfd containing file descriptor $myfd

  (exec {myfd}>logfile4
  echo $myfd
  exec {myfd}>&-
  print This message should disappear >&$myfd) | read myfd
  (( ! ${pipestatus[1]} ))
1q:Closing file descriptor using brace syntax
?(eval):4: $myfd:$bad_fd_msg

  typeset -r myfd
  echo This should not appear {myfd}>nologfile
1:Error opening file descriptor using readonly variable
?(eval):2: can't allocate file descriptor to readonly parameter myfd

  (typeset +r myfd
  exec {myfd}>newlogfile
  typeset -r myfd
  exec {myfd}>&-)
1:Error closing file descriptor using readonly variable
?(eval):4: can't close file descriptor from readonly parameter myfd

# This tests the here-string to filename optimisation; we can't
# test that it's actually being optimised, but we can test that it
# still works.
  cat =(<<<$'This string has been replaced\nby a file containing it.\n')
0:Optimised here-string to filename
>This string has been replaced
>by a file containing it.

  print This f$'\x69'le contains d$'\x61'ta. >redirfile
  print redirection:
  cat<redirfile>outfile
  print output:
  cat outfile
  print append:
  cat>>outfile<redirfile
  print more output:
  cat outfile
0:Parsing of redirection operators (no space required before operators)
>redirection:
>output:
>This file contains data.
>append:
>more output:
>This file contains data.
>This file contains data.

  $ZTST_testdir/../Src/zsh -fc 'exec >/nonexistent/nonexistent
  echo output'
0:failed exec redir, no POSIX_BUILTINS
>output
?zsh:1: no such file or directory: /nonexistent/nonexistent

  $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c '
  exec >/nonexistent/nonexistent
  echo output'
1:failed exec redir, POSIX_BUILTINS
?zsh:2: no such file or directory: /nonexistent/nonexistent

  $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c '
  set >/nonexistent/nonexistent
  echo output'
1:failed special builtin redir, POSIX_BUILTINS
?zsh:2: no such file or directory: /nonexistent/nonexistent

  $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c '
  command set >/nonexistent/nonexistent
  echo output'
0:failed special builtin redir with command prefix, POSIX_BUILTINS
>output
?zsh:2: no such file or directory: /nonexistent/nonexistent

  $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c '
  echo >/nonexistent/nonexistent
  echo output'
0:failed unspecial builtin redir, POSIX_BUILTINS
>output
?zsh:2: no such file or directory: /nonexistent/nonexistent

  $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c '
  . /nonexistent/nonexistent
  echo output'
1:failed dot, POSIX_BUILTINS
?zsh:.:2: no such file or directory: /nonexistent/nonexistent

  $ZTST_testdir/../Src/zsh -f -c '
  . /nonexistent/nonexistent
  echo output'
0:failed dot, NO_POSIX_BUILTINS
>output
?zsh:.:2: no such file or directory: /nonexistent/nonexistent

  $ZTST_testdir/../Src/zsh -f <<<'
  readonly foo
  foo=bar set output
  echo output'
0:failed assignment on posix special, NO_POSIX_BUILTINS
>output
?zsh: read-only variable: foo

  $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS <<<'
  readonly foo
  foo=bar set output
  echo output'
1:failed assignment on posix special, POSIX_BUILTINS
?zsh: read-only variable: foo

  $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS <<<'
  readonly foo
  foo=bar echo output
  echo output'
0:failed assignment on non-posix-special, POSIX_BUILTINS
>output
?zsh: read-only variable: foo
