rc

[fork] interactive rc shell
git clone https://hhvn.uk/rc
git clone git://hhvn.uk/rc
Log | Files | Refs | README | LICENSE

trip.rc (20371B)


      1 # trip.rc -- take a tour of rc
      2 # Invoke as "path-to-new-rc < trip.rc"
      3 
      4 rc=$0
      5 echo tripping $rc $version
      6 
      7 tmpdir=''
      8 fn fail {
      9 	echo >[1=2] trip took a wrong turn: $*
     10 	rm -rf $tmpdir
     11 	fn sigexit
     12 	exit 1
     13 }
     14 fn expect {
     15 	echo >[1=2] -n expect $^*^': '
     16 }
     17 fn submatch {
     18 	if (!~ $#* 3)
     19 		fail incorrect invocation of submatch
     20 	got = `` $nl { prompt=$nl $rc -ic $1>[2=1] }
     21 	if (!~ $got $2) {
     22 		echo got $got expected $2
     23 		fail $3
     24 	}
     25 }
     26 fn sigexit sigint sigquit sigsegv
     27 fn sigexit {
     28 	echo trip complete
     29 }
     30 tmpdir=`{ mktemp -d -t rc-trip.XXXXXX }
     31 tmp=$tmpdir/tmp
     32 nl='
     33 '
     34 
     35 #
     36 # rc -c
     37 #
     38 
     39 if ($rc -c >[2]/dev/null) fail 'rc -c didn''t report a bad exit status'
     40 x=`{$rc -c 'echo $0 $2 $#*' a b c d e f}
     41 if (false) {					# WARNING: this differs from sh
     42 	if (!~ $x(1) a) fail rc -c reports '$0' incorrectly as $x(1)
     43 	if (!~ $x(2) c) fail rc -c reports '$2' incorrectly as $x(2)
     44 	if (!~ $x(3) 5) fail rc -c reports '$#' incorrectly as $x(3)
     45 } else {
     46 	if (!~ $x(1) $rc) fail rc -c reports '$0' incorrectly as $x(1)
     47 	if (!~ $x(2) b) fail rc -c reports '$2' incorrectly as $x(2)
     48 	if (!~ $x(3) 6) fail rc -c reports '$#' incorrectly as $x(3)
     49 }
     50 
     51 #
     52 # umask
     53 #
     54 
     55 umask 0
     56 > $tmp
     57 x=`{ls -l $tmp}
     58 if (!~ $x(1) -rw-rw-rw-*) fail umask 0 produced incorrect result: $x(1)
     59 rm -f $tmp
     60 umask 027
     61 > $tmp
     62 y=`{ls -l $tmp}
     63 if (!~ $y(1) -rw-r-----*) fail umask 027 produced incorrect file: $y(1)
     64 rm -f $tmp
     65 if (!~ `umask 027) fail umask reported bad value: `umask
     66 
     67 submatch 'umask bad' 'bad umask' 'bad umask'
     68 submatch 'umask -027' 'bad umask' 'bad umask'
     69 submatch 'umask 999999' 'bad umask' 'bad umask'
     70 submatch 'umask hi there' 'rc: too many arguments to umask' 'umask arg count'
     71 
     72 if (!~ `umask 027) fail bad umask changed umask value to `umask
     73 
     74 #
     75 # redirections
     76 #
     77 
     78 fn bytes { for (i) x=`{wc -c $i} echo $x(1) }
     79 echo foo > foo > bar
     80 if (!~ `{bytes foo} 0) fail double redirection created non-empty empty file
     81 if (!~ `{bytes bar} 4) fail double redirection created wrong sized file: `{bytes bar}
     82 rm -f foo bar
     83 echo -n >1 >[2]2 >[1=2] foo
     84 x = `` '' {cat 1}
     85 if (!~ $#x 0) fail dup created non-empty empty file: `` '' {cat 1}
     86 if (!~ `` '' {cat 2} foo) fail dup put wrong contents in file : `` '' {cat 2}
     87 rm -f 1 2
     88 
     89 expect error from cat, closing stdin
     90 cat >[0=]
     91 
     92 submatch 'cat>(1 2 3)' 'rc: multi-word filename in redirection' 'redirection error'
     93 submatch 'cat>()' 'rc: null filename in redirection' 'redirection error'
     94 
     95 #
     96 # blow the input stack
     97 #
     98 
     99 if (!~ hi `{
    100 eval eval eval eval eval eval eval eval eval eval eval eval eval \
    101 eval eval eval eval eval eval eval eval eval eval eval eval eval \
    102 eval eval eval eval eval eval eval eval eval eval eval eval eval \
    103 eval eval eval eval eval eval eval eval eval eval eval eval eval \
    104 eval eval eval eval eval eval eval eval eval eval eval eval eval \
    105 eval eval eval eval eval eval eval eval eval eval eval eval eval \
    106 eval eval eval eval eval eval eval eval eval eval eval eval eval \
    107 eval eval eval eval eval eval eval eval eval eval eval eval eval \
    108 eval eval eval eval eval eval eval eval eval eval eval eval eval \
    109 eval eval eval eval eval eval eval eval eval eval eval eval eval \
    110 eval eval eval eval eval eval eval eval eval eval eval echo hi
    111 })
    112 	fail huge eval
    113 
    114 #
    115 # heredocs and herestrings
    116 #
    117 
    118 bigfile=$tmpdir/big.$pid
    119 od $rc | sed 5000q > $bigfile
    120 abc=(this is a)
    121 x=()
    122 result='this is a heredoc
    123 this is an heredoc
    124 '
    125 if (!~ `` '' {<<[5] EOF cat <[0=5]} $result) fail unquoted heredoc
    126 $abc heredoc$x
    127 $abc^n $x^here$x^doc
    128 EOF
    129 {if (!~ `` $nl cat '	') fail quoted heredoc} << ' '
    130 	
    131  
    132 
    133 <<<[9] ``''{cat $bigfile} \
    134 {
    135 	if(!~ ``''{cat <[0=9]}``'' cat)fail large herestrings
    136 } < \
    137 $bigfile
    138 
    139 rm -f $bigfile
    140 
    141 if (!~ `{cat<<eof
    142 $$
    143 eof
    144 } '$')
    145 	fail quoting '$' in heredoc
    146 
    147 submatch 'cat<<eof' 'rc: heredoc incomplete' 'incomplete heredoc'
    148 submatch 'cat<<eof
    149 ' 'rc: heredoc incomplete' 'incomplete heredoc'
    150 
    151 submatch 'cat<<(eof eof)' 'rc: eof-marker not a single literal word' 'bad heredoc marker'
    152 
    153 #
    154 # lexical analysis
    155 #
    156 
    157 expect warning
    158 ./tripping 0 > $tmp
    159 $rc $tmp
    160 rm -f $tmp
    161 
    162 echo here_is_a_really_long_word.It_has_got_to_be_longer_than_1000_characters_for_the_lexical_analyzers_buffer_to_overflow_but_that_should_not_be_too_difficult_to_do.Let_me_start_writing_some_Lewis_Carroll.Twas_brillig_and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe.All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.Beware_the_Jabberwock_my_son,The_jaws_that_bite,the_claws_that_catch.Beware_the_Jub-jub_bird,and_shun_The_frumious_Bandersnatch.He_took_his_vorpal_sword_in_hand,Long_time_the_manxome_foe_he_sought,So_rested_he_by_the_Tumtum_tree,And_stood_awhile_in_thought.And_as_in_uffish_thought_he_stood,The_Jabberwock,with_eyes_of_flame,Came_whiffling_through_the_tulgey_wood,And_burbled_as_it_came.One_two,one_two.And_through_and_through_The_vorpal_blade_went_snicker-snack.He_left_it_dead_and_with_its_head,He_went_galumphing_back.And_hast_thou_slain_the_Jabberwock?Come_to_my_arms,my_beamish_boy,Oh_frabjous_day.Callooh_callay.He_chortled_in_his_joy.Twas_brillig,and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe,All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe. > $tmpdir/$pid.lw
    163 
    164 echo 'here_is_a_really_long_word.It_has_got_to_be_longer_than_1000_characters_for_the_lexical_analyzers_buffer_to_overflow_but_that_should_not_be_too_difficult_to_do.Let_me_start_writing_some_Lewis_Carroll.Twas_brillig_and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe.All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.Beware_the_Jabberwock_my_son,The_jaws_that_bite,the_claws_that_catch.Beware_the_Jub-jub_bird,and_shun_The_frumious_Bandersnatch.He_took_his_vorpal_sword_in_hand,Long_time_the_manxome_foe_he_sought,So_rested_he_by_the_Tumtum_tree,And_stood_awhile_in_thought.And_as_in_uffish_thought_he_stood,The_Jabberwock,with_eyes_of_flame,Came_whiffling_through_the_tulgey_wood,And_burbled_as_it_came.One_two,one_two.And_through_and_through_The_vorpal_blade_went_snicker-snack.He_left_it_dead_and_with_its_head,He_went_galumphing_back.And_hast_thou_slain_the_Jabberwock?Come_to_my_arms,my_beamish_boy,Oh_frabjous_day.Callooh_callay.He_chortled_in_his_joy.Twas_brillig,and_the_slithy_toves,Did_gyre_and_gimble_in_the_wabe,All_mimsy_were_the_borogoves,And_the_mome-raths_outgrabe.' > $tmpdir/$pid.lq
    165 
    166 if (!~ ``(){cat $tmpdir/$pid.lw} ``(){cat $tmpdir/$pid.lq})
    167 	fail expected long string and long word to be identical
    168 if (! x=`{wc -c $tmpdir/$pid.lw} ~ $x(1) 1088)
    169 	fail expected long word to be 1088 bytes
    170 if (! x=`{wc -c $tmpdir/$pid.lq} ~ $x(1) 1088)
    171 	fail expected long quote to be 1088 bytes
    172 
    173 rm $tmpdir/$pid.lw
    174 rm $tmpdir/$pid.lq
    175 
    176 submatch 'echo hi |[2' 'rc: expected ''='' or '']'' after digit' 'scan error'
    177 submatch 'echo hi |[92=]' 'rc: expected digit after ''=''' 'scan error'
    178 submatch 'echo hi |[a]' 'rc: expected digit after ''[''' 'scan error'
    179 submatch 'echo hi |[2-' 'rc: expected ''='' or '']'' after digit' 'scan error'
    180 submatch 'echo hi |[2=99a]' 'rc: expected '']'' after digit' 'scan error'
    181 submatch 'echo hi |[2=a99]' 'rc: expected digit or '']'' after ''=''' 'scan error'
    182 submatch 'echo ''hi' 'rc: eof in quoted string' 'scan error'
    183 
    184 ifs='' {
    185 	if (!~ 'h i' `{echo -n h\
    186 i})
    187 		fail backslash-newline to space conversion
    188 	if (!~ $rc^\rc `{echo -n $rc\rc})
    189 		fail backslash after variable name did not terminate variable name scan
    190 	if (!~ $rc^' rc' `{echo -n $rc\
    191 rc})
    192 		fail backslash-newline after variable name space conversion
    193 	if (!~ 'h\i' `{echo -n h\i})
    194 		fail backslash in the middle of word
    195 	if (!~ 'h \ i' `{echo -n h \ i})
    196 		fail free-standing backslash
    197 }
    198 
    199 if (! $rc -c '# eof in comment')
    200 	fail eof in comment exited with nonzero status
    201 
    202 # test the syntax error printer
    203 
    204 prompt='' if (!~ `` $nl {$rc -cif>[2=1]} 'rc: line 1: '*' error near if')
    205 	fail print syntax error
    206 
    207 prompt='' if (!~ `` $nl {$rc -icif>[2=1]} *' error')
    208 	fail print syntax error
    209 
    210 #
    211 # builtins
    212 #
    213 
    214 fn foo {
    215 	return sigfpe
    216 }
    217 
    218 foo
    219 if (!~ $status sigfpe)
    220 	fail return builtin did not return sigfpe
    221 
    222 fn foo # test deleting of function
    223 fn bar {
    224 	for (i in 1 2 3 4 5)
    225 		if (~ $i 3)
    226 			return
    227 }
    228 
    229 bar
    230 if (!~ $i 3)
    231 	fail return inside loop inside function failed
    232 
    233 submatch return 'rc: return outside of function' 'return outside of function'
    234 submatch 'break 1' 'rc: too many arguments to break' 'break arg count'
    235 submatch break 'rc: break outside of loop' 'break outside of loop'
    236 
    237 for (i in 1 2 3 4 5)
    238 	if (~ $i 2)
    239 		break
    240 if (!~ $i 2)
    241 	fail break out of loop
    242 
    243 submatch 'wait foo' 'rc: `foo'' is a bad number' 'bogus argument to wait'
    244 
    245 if (~ `{echo -n} ?)
    246 	fail echo -n
    247 if (!~ `` '' {echo --} $nl)
    248 	fail echo --
    249 
    250 pwd=`{/bin/pwd -P} cdpath=/ { # some local assignments
    251 	home=/tmp cd
    252 	if (!~ `{/bin/pwd -P} `{sh -c 'cd /tmp; /bin/pwd -P'})
    253 		fail could not cd to '$home'
    254 
    255 	cdpath=/ cd tmp
    256 	if (!~ `{/bin/pwd -P} `{sh -c 'cd /tmp; /bin/pwd -P'})
    257 		fail could not cd to /tmp
    258 
    259 	cd $pwd
    260 	if (!~ `{/bin/pwd -P} `{sh -c 'cd $pwd; /bin/pwd -P'})
    261 		fail could not cd to current directory!
    262 }
    263 
    264 # Test that cd to a directory found via cdpath produces output
    265 # when interactive.
    266 submatch 'cdpath=/ cd tmp' /tmp 'cdpath produced wrong output'
    267 
    268 *=(1 2 3 4 5) {
    269 	expect bad number
    270 	shift foo
    271 	expect arg count
    272 	shift 1 2 3
    273 	expect shift overflow
    274 	shift 123
    275 	shift 3
    276 	if (!~ $#* 2)
    277 		fail shift 3 of '(1 2 3 4 5)' failed
    278 	shift
    279 	if (!~ $* 5)
    280 		fail shift failed to shift left-to-right
    281 }
    282 
    283 false
    284 eval && fail null eval reset '$status'
    285 
    286 if (!~ `{rm=(); fn rm; path=(. /bin); whatis rm} /bin/rm)
    287 	fail rm isn''''t in bin!?
    288 
    289 expect list of signal handlers
    290 whatis -s
    291 
    292 expect list of variables and functions
    293 whatis
    294 
    295 submatch 'whatis -x' 'whatis: bad option: -x' 'bad option to whatis'
    296 
    297 submatch 'whatis /frobnatz' '/frobnatz not found' 'search for /frobnatz'
    298 
    299 if (~ `{whatis limit >[2]/dev/null} builtin) {
    300 	limit coredumpsize 0
    301 	if (!~ `{limit coredumpsize} 0*)
    302 		fail failed to set coredumpsize to zero
    303 	if (!~ `` () {limit coredumpsize} `` () {limit|grep coredumpsize})
    304 		fail limit limit
    305 	submatch 'limit foo' 'no such limit' 'bad limit'
    306 }
    307 
    308 fn cd
    309 
    310 submatch 'cd a b c' 'rc: too many arguments to cd' 'cd arg count'
    311 $rc -c 'cdpath=() cd /frobnatz' >[2]/dev/null && fail 'cd to /frobnatz succeeded!?'
    312 submatch 'cdpath='''' cd frobnatz' 'couldn''t cd to frobnatz' 'cd to frobnatz succeeded!?'
    313 
    314 'if'=keyword {
    315 	{whatis if | fgrep '''if''=keyword' >/dev/null} || fail whatis of keyword is not quoted
    316 }
    317 
    318 #
    319 # wait
    320 #
    321 
    322 submatch 'wait 1 2 3' 'rc: too many arguments to wait' 'wait arg count'
    323 $rc -c 'wait 1' >[2]/dev/null && fail wait 1
    324 
    325 sleep 3&
    326 expect $apid
    327 echo $apids
    328 wait
    329 
    330 if (~ `` '' {wait} ?)
    331 	fail waiting for nothing
    332 
    333 #
    334 # matching
    335 #
    336 touch $tmpdir/abc.$pid $tmpdir/bbc.$pid
    337 mkdir $tmpdir/dir.$pid $tmpdir/dip.$pid
    338 touch $tmpdir/dir.$pid/^(a b c) $tmpdir/dip.$pid/^(a b c)
    339 
    340 if (!~ 123 [~x]?[0-9])
    341 	fail match
    342 if (!~ () *)
    343 	fail match of null list with '*'
    344 if (~ () *v*)
    345 	fail match of null list with '*v*' succeeded
    346 if (!~ (foo bar zar) *****z*****)
    347 	fail match of list by one pattern failed
    348 if (~ (foo bar zar) *c*)
    349 	fail bad match
    350 if (!~ [aaa [aaa)
    351 	fail bad rangematch
    352 if (!~ ']' []])
    353 	fail match right bracket
    354 if (~ x [y])
    355 	fail rangematch out of range
    356 if (~ x x?)
    357 	fail too many characters in pattern
    358 
    359 sh -c 'test -f /////$tmpdir//////a?c.'^$pid || fail glob with many slashes
    360 if (!~ /////$tmpdir//////a*.$pid /////$tmpdir//////a?c.$pid)
    361 	fail glob with many slashes
    362 if (!~ ////$tmpdir////di?.$pid////* ////$tmpdir////dir.$pid////*b*)
    363 	fail glob with more slashes
    364 if (! @{cd $tmpdir; ~ *.$pid/a d*/*})
    365 	fail glob in current directory
    366 if (!~ $tmpdir/?bc.$pid $tmpdir/bbc.$pid)
    367 	fail match of bbc.$pid against '('abc.$pid bbc.$pid')'
    368 
    369 rm $tmpdir/abc.$pid $tmpdir/bbc.$pid
    370 rm -rf $tmpdir/dir.$pid $tmpdir/dip.$pid
    371 
    372 #
    373 # signals
    374 #
    375 fn sigint {eval}
    376 kill -2 $pid
    377 fn sigint
    378 
    379 #
    380 # path searching
    381 #
    382 $rc -c /frobnatz >[2]/dev/null && fail 'search error'
    383 
    384 touch $tmpdir/noexec.$pid
    385 chmod a-x $tmpdir/noexec.$pid
    386 $rc -c $tmpdir/noexec.$pid >[2]/dev/null && fail $tmpdir/noexec.$pid is found!?
    387 rm $tmpdir/noexec.$pid
    388 
    389 submatch 'path='''' frobnatz' 'rc: cannot find `frobnatz''' 'search error'
    390 
    391 {path=() /bin/sh -c 'exit 0'} || fail abs pathname with path set to null
    392 
    393 #
    394 # options
    395 #
    396 
    397 # this test is meaningless; not really a trip
    398 expect prompt, echo hi
    399 home=/frobnatz $rc -nolpeivdxc 'echo hi'
    400 if (!~ `` $nl {$rc -c>[2=1]} *': option requires an argument -- c')
    401 	fail getopt on -c
    402 if (!~ `` $nl {$rc -q>[2=1]} *': bad option: -q')
    403 	fail getopt on -q (bogus option)
    404 if (!~ `{echo '#echo' | $rc -v |[2] sed 's/#//'} echo)
    405 	fail rc -v
    406 
    407 #
    408 # dot
    409 #
    410 
    411 if (~ `` '' . ?*)
    412 	fail null dot
    413 if (~ `` '' {. -i} ?*)
    414 	fail null dot -i
    415 
    416 cat > $tmpdir/dot.$pid << eof
    417 echo hi
    418 eof
    419 
    420 prompt=';' if (!~ `` '' {. -i $tmpdir/dot.$pid>[2=1]} ';hi'^$nl';')
    421 	fail dot -i
    422 submatch .' '$tmpdir/dot.$pid hi dot
    423 
    424 rm $tmpdir/dot.$pid
    425 
    426 $rc -c '. /frobnatz' >[2]/dev/null && fail 'dot of a nonexistent file'
    427 
    428 #
    429 # stdin
    430 #
    431 if (!~ `{echo echo hi | $rc} hi)
    432 	fail piping stdin to rc
    433 
    434 #
    435 # functions, variables & environment
    436 #
    437 fn --- {for(i)a|[2=3]b>>c<<<e&f>[2=1]}
    438 
    439 if (whatis printenv >/dev/null>[2=1]) {
    440 	printenv=printenv
    441 } else if (whatis env >/dev/null>[2=1]) {
    442 	printenv=env
    443 } else
    444 	printenv=()
    445 
    446 if (~ $#printenv 1 && !~ `` $nl {$printenv | grep fn___2d__2d__2d} 'fn___2d__2d__2d={for(i in $*)a|[2=3]b >>c <<<e&f >[2=1]}')
    447 	fail protect_env
    448 
    449 fn --- {replace}
    450 ~ `{whatis -- ---} *replace* || fail replace a function definition
    451 fn ---
    452 whatis -- --- >[2]/dev/null && fail function deletion
    453 foo=bar *=bar
    454 foo=nest *=nest {
    455 	~ $foo nest || fail local assignment
    456 	~ $* nest || fail local assignment to '$*'
    457 	foo=()
    458 	*=()
    459 	~ $foo () || fail local deletion
    460 	~ $* () || fail local deletion to '$*'
    461 }
    462 ~ $foo bar || fail restore of global after local group
    463 ~ $* bar || fail restore of '$*' after local group
    464 ~ `{exec>[2=1];$rc -xc 'foo=()'} 'foo=()' || fail -x echo of variable deletion
    465 
    466 fn_ff='{' prompt='' if (!~ `` $nl {$rc -cff>[2=1]} 'rc: line 1: '*' error near eof')
    467 	fail 'bogus function in environment'
    468 
    469 #
    470 # statuses
    471 #
    472 ~ `{$rc -ec 'sleep 10&kill -9 $apid;wait'>[2=1]} killed ||
    473 	fail status diagnostic
    474 
    475 $rc -c 'exit 0 sigfpe' && fail exit of bad pipeline is true
    476 
    477 submatch 'exit foo' 'bad status' 'exit diagnostic'
    478 
    479 #
    480 # control structures
    481 #
    482 if (!~ `{false || echo hi} hi)
    483 	fail '||'
    484 if (!~ `{true && echo hi} hi)
    485 	fail '&&'
    486 if (~ `{true || echo hi} hi)
    487 	fail '||'
    488 if (~ `{false && echo hi} hi)
    489 	fail '&&'
    490 
    491 while (false)
    492 	fail false while
    493 while (true) {
    494 	break
    495 	fail break in while
    496 }
    497 
    498 switch (foo) {
    499 	case bar
    500 		fail matched bar in switch
    501 	case foo
    502 		eval
    503 	case *
    504 		fail match foo in switch
    505 }
    506 
    507 switch (nothing) {
    508 	case bar
    509 		fail matched bar in switch
    510 	case *
    511 		i=frobnatz
    512 }
    513 
    514 ~ $i frobnatz || fail match '*' in switch
    515 
    516 submatch '()=()' 'rc: null variable name' 'assignment diagnostic'
    517 submatch 'fn () {eval}' 'rc: null function name' 'assigning null function name'
    518 
    519 #
    520 # prompt
    521 #
    522 fn prompt {echo hi}
    523 prompt=() if (!~ `{$rc -i /dev/null>[2]/dev/null} hi) fail fn prompt
    524 fn prompt
    525 
    526 #
    527 # history
    528 #
    529 history=$tmpdir/hist.$pid prompt='' echo 'history=()' | $rc -i
    530 
    531 if (!~ `{cat $tmpdir/hist.$pid} 'history=()')
    532 	fail output to history file
    533 
    534 history=$tmpdir/hist.$pid prompt='' echo 'history=()' | $rc -i
    535 
    536 if (!~ `` () {cat $tmpdir/hist.$pid} 'history=()
    537 history=()
    538 ')
    539 	fail append to history file
    540 
    541 rm $tmpdir/hist.$pid
    542 
    543 if (!~ `{history=/frobnatz/foo prompt='' echo eval | $rc -i >[2=1]} ?*)
    544 	fail accessing bad history file
    545 
    546 #
    547 # regression
    548 #
    549 
    550 expect date
    551 { date & wait } |cat
    552 
    553 # Making rc's input non-blocking should have no untoward side effects.
    554 x=`{ { sleep 1; echo echo foo } | { ./tripping n; $rc >[2=1] } }
    555 if (!~ foo $x)
    556 	fail input file descriptor nonblocking
    557 
    558 # `rc -s' reads from stdin, but should not imply `-i'
    559 expect foo bar qux
    560 $rc -s foo bar qux <<'eof'
    561 echo $*
    562 eof
    563 
    564 # Believe it or not, I broke root directory globbing in rc-1.6b1.
    565 x=/*
    566 ~ '/*' $^x && fail root directory globbing
    567 
    568 # fn sigexit should be cleared in children
    569 
    570 x = ()
    571 expect rc: cannot find '`nonesuch'''
    572 x = `{true | nonesuch}; if (~ $x trip) fail sigexit in children
    573 x = `{ < /dev/null wc |grep xxx }; if (~ $x trip) fail sigexit in children
    574 x = `{{ wc | wc } < /dev/null }; if (~ $x trip) fail sigexit in children
    575 
    576 # core dumps in glob.c
    577 ~ () '*' && fail globber problem
    578 ~ () '**' && fail globber problem
    579 
    580 # check for ctrl-a bug
    581 x=`{./tripping a}
    582 ~ `{$rc -c 'echo $x'} $x || fail ctrl-a bug detected
    583 
    584 # check for hilarious quoting bug introduced while fixing ctrl-a
    585 x=('#' '#' '#')
    586 eval z^`{whatis -v x}
    587 ~ $#zx 3 || fail hilarious quoting bug
    588 
    589 # parens bypass quote detector bug
    590 fn x {echo x.y $(x.y)}
    591 ~ ``''{whatis -f x} 'fn x {echo x.y $(x^.y)}
    592 ' || fail sneaky parens bug
    593 
    594 # before rc-1.7.1, certain glob patterns could fail on broken symlinks
    595 mkdir $tmpdir/qux
    596 ln -s /frobnatz $tmpdir/qux/foo
    597 x=$tmpdir/qux/foo*
    598 ~ $x $tmpdir/qux/foo || { rm -rf $tmpdir/qux; fail broken symlink globbing }
    599 x=$tmpdir/qux*/foo
    600 ~ $x $tmpdir/qux/foo || { rm -rf $tmpdir/qux; fail broken symlink globbing }
    601 
    602 rm -rf $tmpdir
    603 
    604 #############################################################################
    605 ## Check builtin continue in while loop.
    606 #############################################################################
    607 q=''''
    608 C=$q^while-continue$q
    609 L=()
    610 
    611 save_star = *
    612 ten = a^(1 2 3 4 5 6 7 8 9 10)
    613 * = $ten
    614 while (! ~ $#* 0) {
    615   n = $1; shift
    616   if (~ $n a2 a3) {
    617     continue
    618   }
    619   L=($L $n)
    620 }
    621 * = $save_star; save_star = ()
    622 
    623 if (!~ $#L 8) {
    624   fail Wrong length of list from $C: $#L
    625 }
    626 if (!~ $L(1) a1) {
    627   fail First element of $C list is not a1: $L(1)
    628 }
    629 if (!~ $L(2) a4) {
    630   fail Second element of $C list is not a4: $L(2)
    631 }
    632 C=() L=()
    633 
    634 #############################################################################
    635 ## Check builtin continue in for loop.
    636 #############################################################################
    637 C=$q^for-continue$q
    638 L=()
    639 
    640 for (x in a b c d e f g) {
    641   if (~ $x c f) {
    642     continue
    643   }
    644   L=($L $x)
    645 }
    646 if (!~ $#L 5) {
    647   fail Wrong length of list from $C
    648 }
    649 if (!~ $L(1) a) {
    650   fail First element of $C list is not a: $L(1)
    651 }
    652 if (!~ $L(3) d) {
    653   fail Third element of $C list is not d: $L(3)
    654 }
    655 if (!~ $L(5) g) {
    656   fail Fifth element of $C list is not g: $L(5)
    657 }
    658 C=() L=()
    659 
    660 submatch continue 'rc: continue outside of loop' 'continue outside of loop'
    661 
    662 #############################################################################
    663 ## check builtin continue in for loop (2)
    664 #############################################################################
    665 L=()
    666 for (x in a b c d e f g) {
    667   if (~ $x b d) {
    668     continue
    669   }
    670   L=($L $x)
    671   if (~ $x f) {
    672     break;
    673   }
    674 }
    675 
    676 if (!~ $^L 'a c e f') {
    677   fail List should be '(a c e f)', but is $L
    678 }
    679 
    680 # test support for unquoted =
    681 submatch 'echo foo = bar' 'foo = bar' 'unquoted equals 1'
    682 submatch 'echo foo=bar' 'foo=bar' 'unquoted equals 2'
    683 submatch 'echo foo=' 'foo=' 'unquoted equals 3'
    684 submatch 'echo =bar; whatis -v echo' 'echo=bar' 'unquoted equals 4'
    685 
    686 # test for github issue #34
    687 X=`{ $rc -ec 'b=true; while($b){b=false}; echo YYY' }
    688 if (! ~ $X YYY) {
    689     fail '"rc -e" exits when condition in the while statement fails in the second iteration'
    690 }
    691 
    692 # test for counter intuitive redirection parse
    693 A=``($nl){ $rc -c 'mkdir / >[2=1] | tr a-z A-Z' }
    694 B=``($nl){ $rc -c '>[2=1] mkdir / | tr a-z A-Z' }
    695 ~ $A $B || fail counter intuitive redirection bug, $A '!=' $B
    696 
    697 # test for github issue #40
    698 $rc -ec 'false | false'
    699 if (~ $status 0) {
    700 	fail '"rc -e" exits with zero status when command in pipeline returns non-zero'
    701 }
    702 $rc -ec 'X=`{false}'
    703 if (~ $status 0) {
    704 	fail '"rc -e" exits with zero status when backquote command returns non-zero'
    705 }
    706 
    707 # exercise "if not"
    708 submatch 'if (false) echo foo; if not echo bar' 'bar' 'if not 1'
    709 submatch 'if (false) echo -n foo; if not echo -n bar; echo qux' 'barqux' 'if not 2'
    710 submatch 'if (false) echo foo; echo qux; if not echo bar' 'rc: `if not'' must follow `if''' 'if not 3'
    711 submatch 'if (false) { echo foo } else echo qux; if not echo bar' 'rc: `if not'' must follow `if''' 'if not 4'
    712 
    713 # if-not stack if_state regression
    714 s='
    715 L=()
    716 if (true) {
    717     if (false) {
    718         L=($L  a1)
    719     }
    720     if not L=($L  a2)
    721 }
    722 if not L=($L  a3)
    723 echo $L
    724 '
    725 
    726 m=`{$rc -c $s}
    727 if (! ~ $^m a2) {
    728     fail '"if not" not correct'
    729 }
    730 
    731 # exercise flag builtin
    732 submatch 'flag' 'rc: not enough arguments to flag' 'flag no args'
    733 submatch 'flag a b c' 'usage: flag f [ + | - ]' 'flag 3 args'
    734 submatch 'flag xx' 'usage: flag f [ + | - ]' 'flag wrong first arg'
    735 submatch 'flag x x' 'usage: flag f [ + | - ]' 'flag wrong second arg'
    736 submatch 'flag c && echo yes' yes 'flag c'
    737 submatch 'flag x +; flag x -' 'flag x -' 'setting x flag'