D04parameter.ztst   [plain text]


# Test parameter expansion.  Phew.
# (By the way, did I say "phew"?)

%prep

  mkdir parameter.tmp

  cd parameter.tmp

  touch boringfile evenmoreboringfile

%test

  foo='the first parameter'
  bar='the second parameter'
  print -l $foo ${bar}
0:Basic scalar parameter substitution
>the first parameter
>the second parameter

  array1=(the first array)
  array2=(the second array)
  print -l $array1 ${array2}
0:Basic array parameter substitution
>the
>first
>array
>the
>second
>array

  setopt ksharrays
  print -l $array1 ${array2}
  unsetopt ksharrays
0:Basic ksharray substitution
>the
>the

  setopt shwordsplit
  print -l $foo ${bar}
  print -l ${==bar}
  unsetopt shwordsplit
0:Basic shwordsplit option handling
>the
>first
>parameter
>the
>second
>parameter
>the second parameter

  print $+foo ${+foo} $+notappearinginthistest ${+notappearinginthistest}
0:$+...
>1 1 0 0

  x=()
  print ${+x} ${+x[1]} ${+x[(r)foo]} ${+x[(r)bar]}
  x=(foo)
  print ${+x} ${+x[1]} ${+x[(r)foo]} ${+x[(r)bar]}
0:$+... with arrays
>1 0 0 0
>1 1 1 0

  set1=set1v
  null1=
  print ${set1:-set1d} ${set1-set2d} ${null1:-null1d} ${null1-null2d} x
  print ${unset1:-unset1d} ${unset1-unset2d} x
0:${...:-...} and ${...-...}
>set1v set1v null1d x
>unset1d unset2d x

  set2=irrelevant
  print ${set1:=set1d} ${set2::=set2d}
  print $set2
  wasnull1=
  wasnull2=
  print ${wasnull1=wasnull1d} ${wasnull2:=wasnull2d}
  print $wasnull1 $wasnull2
0:${...:=...}, ${...::=...}, ${...=...}
>set1v set2d
>set2d
>wasnull2d
>wasnull2d

  (print ${set1:?okhere}; print ${unset1:?exiting1}; print not reached;)
  (print ${null1?okhere}; print ${null1:?exiting2}; print not reached;)
1:${...:?...}, ${...?...}
>set1v
>
?(eval):1: unset1: exiting1
?(eval):2: null1: exiting2

  print ${set1:+word1} ${set1+word2} ${null1:+word3} ${null1+word4}
  print ${unset1:+word5} ${unset1+word6}
0:${...:+...}, ${...+...}
>word1 word2 word4
>

  str1='This is very boring indeed.'
  print ${str1#*s}
  print ${str1##*s}
  print $str1##s
0:${...#...}, ${...##...}
> is very boring indeed.
> very boring indeed.
>This is very boring indeed.##s

  str2='If you'\''re reading this you should go and fix some bugs instead.'
  print ${str2%d*}
  print ${str2%%d*}
0:${...%...}, ${...%%...}
>If you're reading this you should go and fix some bugs instea
>If you're rea

  str1='does match'
  str2='does not match'
  print ${str1:#does * match}
  print ${str2:#does * match}
0:${...:#...}
>does match
>

  array1=(arthur boldly claws dogs every fight)
  print ${array1:#[aeiou]*}
  print ${(M)array1:#[aeiou]*}
0:${...:#...}, ${(M)...:#...} with array
>boldly claws dogs fight
>arthur every

  str1="$array1"
  print ${str1/[aeiou]*g/a braw bricht moonlicht nicht the nic}
  print ${(S)str1/[aeiou]*g/relishe}
0:scalar ${.../.../...}, ${(S).../.../...}
>a braw bricht moonlicht nicht the nicht
>relishes every fight

  print ${array1/[aeiou]*/Y}
  print ${(S)array1/[aeiou]*/Y}
0:array ${.../.../...}, ${(S).../.../...}
>Y bY clY dY Y fY
>Yrthur bYldly clYws dYgs Yvery fYght

  str1='o this is so, so so very dull'
  print ${str1//o*/Please no}
  print ${(S)str1//o*/Please no}
0:scalar ${...//.../...}, ${(S)...//.../...}
>Please no
>Please no this is sPlease no, sPlease no sPlease no very dull

  print ${array1//[aeiou]*/Y}
  print ${(S)array1//[aeiou]*/Y}
0:array ${...//.../...}, ${(S)...//.../...}
>Y bY clY dY Y fY
>YrthYr bYldly clYws dYgs YvYry fYght

  print ${array1:/[aeiou]*/expletive deleted}
0:array ${...:/...}
>expletive deleted boldly claws dogs expletive deleted fight

  str1='a\string\with\backslashes'
  str2='a/string/with/slashes'
  print "${str1//\\/-}"
  print ${str1//\\/-}
  print "${str2//\//-}"
  print ${str2//\//-}
0:use of backslashes in //-substitutions
>a-string-with-backslashes
>a-string-with-backslashes
>a-string-with-slashes
>a-string-with-slashes

  str1='twocubed'
  array=(the number of protons in an oxygen nucleus)
  print $#str1 ${#str1} "$#str1 ${#str1}" $#array ${#array} "$#array ${#array}"
0:${#...}, $#...
>8 8 8 8 8 8 8 8

  array=(once bitten twice shy)
  print IF${array}THEN
  print IF${^array}THEN
0:basic ${^...}
>IFonce bitten twice shyTHEN
>IFonceTHEN IFbittenTHEN IFtwiceTHEN IFshyTHEN

  # Quote ${array} here because {...,...} doesn't like unquoted spaces.
  print IF{"${array}",THEN}ELSE
  print IF{${^array},THEN}ELSE
0:combined ${^...} and {...,...}
>IFonce bitten twice shyELSE IFTHENELSE
>IFonceELSE IFTHENELSE IFbittenELSE IFTHENELSE IFtwiceELSE IFTHENELSE IFshyELSE IFTHENELSE

  str1='one word'
  print -l $str1 ${=str1} "split ${=str1}wise"
0:${=...}
>one word
>one
>word
>split one
>wordwise

  str1='*'
  print $str1 ${~str1} $~str1
  setopt globsubst
  print $str1
  unsetopt globsubst
0:${~...} and globsubst
>* boringfile evenmoreboringfile boringfile evenmoreboringfile
>boringfile evenmoreboringfile

# The following tests a bug where globsubst didn't preserve
# backslashes when printing out the original string.
  str1='\\*\\'
  (
  setopt globsubst nonomatch
  [[ \\\\ = $str1 ]] && print -r '\\ matched by' $str1
  [[ \\foo\\ = $str1 ]] && print -r '\\foo matched by' $str1
  [[ a\\b\\ = $str1 ]] || print -r 'a\\b not matched by' $str1
  )
0:globsubst with backslashes
>\\ matched by \\*\\
>\\foo matched by \\*\\
>a\\b not matched by \\*\\

  (
    setopt globsubst
    foo="boring*"
    print ${foo+$foo}
    print ${foo+"$foo"}
    print ${~foo+"$foo"}
  )
0:globsubst together with nested quoted expansion
>boringfile
>boring*
>boringfile

  print -l "${$(print one word)}" "${=$(print two words)}"
0:splitting of $(...) inside ${...}
>one word
>two
>words

  print -l "${(f)$(print first line\\nsecond line\\nthird line)}"
0:${(f)$(...)}
>first line
>second line
>third line

  array1=( uno )
  print -l ${(A)newarray=splitting by numbers}
  print -l ${(t)newarray}
  print -l ${(A)=newarray::=splitting by spaces, actually}
  print -l ${(t)newarray}
  print -l ${(A)newarray::=$array1}
  print -l ${(t)newarray}
  print -l ${newarray::=$array1}
  print -l ${(t)newarray}
  print -l ${newarray::=$array2}
  print -l ${(t)newarray}
0:${(A)...=...}, ${(A)...::=...}, ${scalar=$array}
>splitting by numbers
>array
>splitting
>by
>spaces,
>actually
>array
>uno
>array
>uno
>scalar
>the second array
>scalar

  newarray=("split me" "split me" "I\'m yours")
  print -l "${(@)newarray}"
0:"${(@)...}"
>split me
>split me
>I'm yours

  foo='$(print Howzat usay)'
  print -l ${(e)foo}
0:${(e)...}
>Howzat
>usay

  foo='`print Howzat usay`'
  print -l ${(e)foo}
0:Regress ${(e)...} with backticks (see zsh-workers/15871)
>Howzat
>usay

  foo='I'\''m nearly out of my mind with tedium'
  bar=foo
  print ${(P)bar}
0:${(P)...}
>I'm nearly out of my mind with tedium
#' deconfuse emacs

  foo=(I could be watching that programme I recorded)
  print ${(o)foo}
  print ${(oi)foo}
  print ${(O)foo}
  print ${(Oi)foo}
0:${(o)...}, ${(O)...}
>I I be could programme recorded that watching
>be could I I programme recorded that watching
>watching that recorded programme could be I I
>watching that recorded programme I I could be

  foo=(yOU KNOW, THE ONE WITH wILLIAM dALRYMPLE)
  bar=(doing that tour of India.)
  print ${(L)foo}
  print ${(U)bar}
0:${(L)...}, ${(U)...}
>you know, the one with william dalrymple
>DOING THAT TOUR OF INDIA.

  foo='instead here I am stuck by the computer'
  print ${(C)foo}
0:${(C)...}
>Instead Here I Am Stuck By The Computer

  foo=$'\x7f\x00'
  print ${(V)foo}
0:${(V)...}
>^?^@

  foo='playing '\''stupid'\'' "games" \w\i\t\h $quoting.'
  print -r ${(q)foo}
  print -r ${(qq)foo}
  print -r ${(qqq)foo}
  print -r ${(qqqq)foo}
  print -r ${(q-)foo}
0:${(q...)...}
>playing\ \'stupid\'\ \"games\"\ \\w\\i\\t\\h\ \$quoting.
>'playing '\''stupid'\'' "games" \w\i\t\h $quoting.'
>"playing 'stupid' \"games\" \\w\\i\\t\\h \$quoting."
>$'playing \'stupid\' "games" \\w\\i\\t\\h $quoting.'
>'playing '\'stupid\'' "games" \w\i\t\h $quoting.'

  print -r -- ${(q-):-foo}
  print -r -- ${(q-):-foo bar}
  print -r -- ${(q-):-"*(.)"}
  print -r -- ${(q-):-"wow 'this is cool' or is it?"}
  print -r -- ${(q-):-"no-it's-not"}
0:${(q-)...} minimal single quoting
>foo
>'foo bar'
>'*(.)'
>'wow '\''this is cool'\'' or is it?'
>no-it\'s-not

  foo="'and now' \"even the pubs\" \\a\\r\\e shut."
  print -r ${(Q)foo}
0:${(Q)...}
>and now even the pubs are shut.

  foo="X$'\x41'$'\x42'Y"
  print -r ${(Q)foo}
0:${(Q)...} with handling of $'...'
>XABY

  # The following may look a bit random.
  # For the split we are checking that anything that
  # would normally be followed by a different word has
  # an argument break after it and anything that wouldn't doesn't.
  # For the (Q) we are simply checking that nothing disappears
  # in the parsing.
  foo='<five> {six} (seven) >eight< }nine{ |forty-two| $many$ )ten( more'
  array=(${(z)foo})
  print -l ${(Q)array}
0:${(z)...} and ${(Q)...} for some hard to parse cases
><
>five
>>
>{six}
>(
>seven
>)
>>
>eight
><
>}nine{
>|
>forty-two
>|
>$many$
>)
>ten( more

  strings=(
    'foo=(1 2 3)'
    '(( 3 + 1 == 8 / 2 ))'
    'for (( i = 1 ; i < 10 ; i++ ))'
    '((0.25542 * 60) - 15)*60'
  )
  for string in $strings; do
    array=(${(z)string})
    for (( i = 1; i <= ${#array}; i++ )); do
      print -r -- "${i}:${array[i]}:"
    done
  done
0:Some syntactical expressions that are hard to split into words with (z).
>1:foo=(:
>2:1:
>3:2:
>4:3:
>5:):
>1:(( 3 + 1 == 8 / 2 )):
>1:for:
>2:((:
# Leading whitespace is removed, because the word proper hasn't started;
# trailing whitespace is left because the word is terminated by the
# semicolon or double parentheses.  Bit confusing but sort of consistent.
>3:i = 1 ;:
>4:i < 10 ;:
>5:i++ :
>6:)):
# This one needs resolving between a math expression and
# a command, which causes interesting effects internally.
>1:(:
>2:(:
>3:0.25542:
>4:*:
>5:60:
>6:):
>7:-:
>8:15:
>9:):
>10:*60:


  line=$'A line with # someone\'s comment\nanother line # (1 more\nanother one'
  print "*** Normal ***"
  print -l ${(z)line}
  print "*** Kept ***"
  print -l ${(Z+c+)line}
  print "*** Removed ***"
  print -l ${(Z+C+)line}
0:Comments with (z)
>*** Normal ***
>A
>line
>with
>#
>someone's comment
>another line # (1 more
>another one
>*** Kept ***
>A
>line
>with
># someone's comment
>;
>another
>line
># (1 more
>;
>another
>one
>*** Removed ***
>A
>line
>with
>;
>another
>line
>;
>another
>one

  line='with comment # at the end'
  print -l ${(Z+C+)line}
0:Test we don't get an additional newline token
>with
>comment

  line=$'echo one\necho two # with a comment\necho three'
  print -l ${(Z+nc+)line}
0:Treating zplit newlines as ordinary whitespace
>echo
>one
>echo
>two
># with a comment
>echo
>three

  psvar=(dog)
  setopt promptsubst
  foo='It shouldn'\''t $(happen) to a %1v.'
  bar='But `echo what can you do\?`'
  print -r ${(%)foo}
  print -r ${(%%)bar}
0:${(%)...}
>It shouldn't $(happen) to a dog.
>But what can you do?

  foo='unmatched "'
  print ${(QX)foo}
1:${(QX)...}
?(eval):2: unmatched "
# " deconfuse emacs

  array=(characters in an array)
  print ${(c)#array}
0:${(c)#...}
>22

  print ${(w)#array}
  str='colon::bolon::solon'
  print ${(ws.:.)#str}
  print ${(Ws.:.)#str}
0:${(w)...}, ${(W)...}
>4
>3
>5

  typeset -A assoc
  assoc=(key1 val1 key2 val2)
  print ${(o)assoc}
  print ${(ok)assoc}
  print ${(ov)assoc}
  print ${(okv)assoc}
0:${(k)...}, ${(v)...}
>val1 val2
>key1 key2
>val1 val2
>key1 key2 val1 val2

  word="obfuscatory"
  print !${(l.16.)word}! +${(r.16.)word}+
0:simple padding
>!     obfuscatory! +obfuscatory     +

  foo=(resulting words uproariously padded)
  print ${(pl.10..\x22..X.)foo}
0:${(pl...)...}
>Xresulting """"Xwords roariously """Xpadded
#" deconfuse emacs

  print ${(l.5..X.r.5..Y.)foo}
  print ${(l.6..X.r.4..Y.)foo}
  print ${(l.7..X.r.3..Y.)foo}
  print ${(l.6..X..A.r.6..Y..B.)foo}
  print ${(l.6..X..AROOGA.r.6..Y..BARSOOM.)foo}
0:simultaneous left and right padding
>Xresulting XXXwordsYY proariousl XXpaddedYY
>XXresultin XXXXwordsY uproarious XXXpaddedY
>XXXresulti XXXXXwords Xuproariou XXXXpadded
>XAresultingB XXXAwordsBYY uproariously XXApaddedBYY
>GAresultingB OOGAwordsBAR uproariously OGApaddedBAR

  foo=(why in goodness name am I doing this)
  print ${(r.5..!..?.)foo}
0:${(r...)...}
>why?! in?!! goodn name? am?!! I?!!! doing this?

  array=(I\'m simply putting a brave face on)
  print ${(j:--:)array}
0:${(j)...}
>I'm--simply--putting--a--brave--face--on

  print ${(F)array}
0:${(F)...}
>I'm
>simply
>putting
>a
>brave
>face
>on

  string='zometimez zis getz zplit on a z'
  print -l ${(s?z?)string}
0:${(s...)...}
>ometime
> 
>is get
> 
>plit on a 

  str=s
  arr=(a)
  typeset -A ass
  ass=(a a)
  integer i
  float f
  print ${(t)str} ${(t)arr} ${(t)ass} ${(t)i} ${(t)f}
0:${(t)...}
>scalar array association-local integer-local float-local

  # it's not quite clear that these are actually right unless you know
  # the algorithm:  search along the string for the point at which the
  # first (last) match occurs, for ## (%%), then take the shortest possible
  # version of that for # (%).  it's as good a definition as anything.
  string='where is the white windmill, whispered walter wisely'
  print ${(S)string#h*e}
  print ${(S)string##h*e}
  print ${(S)string%h*e}
  print ${(S)string%%h*e}
0:${(S)...#...} etc.
>wre is the white windmill, whispered walter wisely
>wly
>where is the white windmill, wred walter wisely
>where is the white windmill, wly

  setopt extendedglob
  print ${(SI:1:)string##w[^[:space:]]# }
  print ${(SI:1+1:)string##w[^[:space:]]# }
  print ${(SI:1+1+1:)string##w[^[:space:]]# }
  print ${(SI:1+1+1+1:)string##w[^[:space:]]# }
0:${(I:...:)...}
>is the white windmill, whispered walter wisely
>where is the windmill, whispered walter wisely
>where is the white whispered walter wisely
>where is the white windmill, walter wisely

  print ${(MSI:1:)string##w[^[:space:]]# }
0:${(M...)...}
>where 

  print ${(R)string//w[a-z]# #}
0:${(R)...}
>is the , 

  # This (1) doesn't work with // or /
  #      (2) perhaps ought to be 18, to be consistent with normal zsh
  #          substring indexing and with backreferences.
  print ${(BES)string##white}
0:${(BE...)...}
>14 19

  print ${(NS)string##white}
0:${(N)...}
>5

  string='abcdefghijklmnopqrstuvwxyz'
  print ${${string%[aeiou]*}/(#m)?(#e)/${(U)MATCH}}
0:Rule 1:  Nested substitutions
>abcdefghijklmnopqrsT

  array=(et Swann avec cette muflerie intermittente)
  string="qui reparaissait chez lui"
  print ${array[4,5]}
  print ${array[4,5][1]}
  print ${array[4,5][1][2,3]}
  print ${string[4,5]}
  print ${string[4,5][1]}
0:Rule 2: Parameter subscripting
>cette muflerie
>cette
>et
> r
> 

  foo=stringalongamax
  print ${${(P)foo[1,6]}[1,3]}
0:Rule 3: Parameter Name Replacement
>qui

  print "${array[5,6]}"
  print "${(j.:.)array[1,2]}"
0:Rule 4: Double-Quoted Joining
>muflerie intermittente
>et:Swann

  print "${${array}[5,7]}"
  print "${${(@)array}[1,2]}"
0:Rule 5: Nested Subscripting
>wan
>et Swann

  print "${${(@)array}[1,2]#?}"
  print "${(@)${(@)array}[1,2]#?}"
0:Rule 6: Modifiers
>t Swann
>t wann

  array=(she sells z shells by the z shore)
  (IFS='+'; print ${(s.s.)array})
0:Rule 7: Forced Joining, and 8: Forced splitting
>he+ ell +z+ hell +by+the+z+ hore

  setopt shwordsplit
  string='another poxy boring string'
  print -l ${${string}/o/ }
  unsetopt shwordsplit
0:Rule 9: Shell Word Splitting
>an
>ther
>p
>xy
>b
>ring
>string

  setopt nonomatch
  foo='b* e*'
  print ${(e)~foo}
  print ${(e)~=foo}
0:Rule 10: Re-Evaluation
>b* e*
>boringfile evenmoreboringfile

  # ${bar} -> $bar  here would yield "bad substitution".
  bar=confinement
  print ${(el.20..X.)${bar}}
0:Rule 11: Padding
>XXXXXXXXXconfinement

  foo=(bar baz)
  bar=(ax1 bx1)
  print "${(@)${foo}[1]}"
  print "${${(@)foo}[1]}"
  print -l ${(s/x/)bar}
  print -l ${(j/x/s/x/)bar}
  print -l ${(s/x/)bar%%1*}
0:Examples in manual on parameter expansion
>b
>bar
>a
>1 b
>1
>a
>1
>b
>1
>a
> b

  set If "this test fails" "we have broken" the shell again
  print -l ${1+"$@"}
0:Regression test of ${1+"$@"} bug
>If
>this test fails
>we have broken
>the
>shell
>again

  set If "this test fails" "we have broken" the shell again
  print -l "${(A)foo::=$@}"
  print -l ${(t)foo}
  print -l $foo
0:Regression test of "${(A)foo=$@}" bug
>If this test fails we have broken the shell again
>array
>If
>this test fails
>we have broken
>the
>shell
>again

  local sure_that='sure that' varieties_of='varieties of' one=1 two=2
  extra=(5 4 3)
  unset foo
  set Make $sure_that "this test keeps" on 'preserving all' "$varieties_of" quoted whitespace
  print -l ${=1+"$@"}
  print -l ${(A)=foo=Make $sure_that "this test keeps" on 'preserving all' "$varieties_of" quoted whitespace}
  print ${(t)foo}
  print -l ${=1+$one $two}
  print -l ${1+$extra$two$one}
0:Regression test of ${=1+"$@"} bug and some related expansions
>Make
>sure that
>this test keeps
>on
>preserving all
>varieties of
>quoted
>whitespace
>Make
>sure
>that
>this test keeps
>on
>preserving all
>varieties of
>quoted
>whitespace
>array
>1
>2
>5
>4
>321

  splitfn() {
    emulate -L sh
    local HOME="/differs from/bash" foo='1 2' bar='3 4'
    print -l ${1:-~}
    touch has\ space
    print -l ${1:-*[ ]*}
    print -l ${1:-*[\ ]*}
    print -l ${1:-*}
    print -l ${1:-"$foo" $bar}
    print -l ${==1:-$foo $bar}
    rm has\ space
  }
  splitfn
0:More bourne-shell-compatible nested word-splitting with wildcards and ~
>/differs from/bash
>*[
>]*
>has space
>boringfile
>evenmoreboringfile
>has space
>1 2
>3
>4
>1 2 3 4

  splitfn() {
    local IFS=.-
    local foo=1-2.3-4
    #
    print "Called with argument '$1'"
    print "No quotes"
    print -l ${=1:-1-2.3-4} ${=1:-$foo}
    print "With quotes on default argument only"
    print -l ${=1:-"1-2.3-4"} ${=1:-"$foo"}
  }
  print 'Using "="'
  splitfn
  splitfn 5.6-7.8
  #
  splitfn() {
    emulate -L zsh
    setopt shwordsplit
    local IFS=.-
    local foo=1-2.3-4
    #
    print "Called with argument '$1'"
    print "No quotes"
    print -l ${1:-1-2.3-4} ${1:-$foo}
    print "With quotes on default argument only"
    print -l ${1:-"1-2.3-4"} ${1:-"$foo"}
  }
  print Using shwordsplit
  splitfn
  splitfn 5.6-7.8
0:Test of nested word splitting with and without quotes
>Using "="
>Called with argument ''
>No quotes
>1
>2
>3
>4
>1
>2
>3
>4
>With quotes on default argument only
>1-2.3-4
>1-2.3-4
>Called with argument '5.6-7.8'
>No quotes
>5
>6
>7
>8
>5
>6
>7
>8
>With quotes on default argument only
>5
>6
>7
>8
>5
>6
>7
>8
>Using shwordsplit
>Called with argument ''
>No quotes
>1
>2
>3
>4
>1
>2
>3
>4
>With quotes on default argument only
>1-2.3-4
>1-2.3-4
>Called with argument '5.6-7.8'
>No quotes
>5
>6
>7
>8
>5
>6
>7
>8
>With quotes on default argument only
>5
>6
>7
>8
>5
>6
>7
>8

# Tests a long-standing bug with joining on metafied characters in IFS
  (array=(one two three)
  IFS=$'\0'
  foo="$array"
  for (( i = 1; i <= ${#foo}; i++ )); do
    char=${foo[i]}
    print $(( #char ))
  done)
0:Joining with NULL character from IFS
>111
>110
>101
>0
>116
>119
>111
>0
>116
>104
>114
>101
>101

  unset SHLVL
  (( SHLVL++ ))
  print $SHLVL
0:Unsetting and recreation of numerical special parameters
>1

  unset manpath
  print $+MANPATH
  manpath=(/here /there)
  print $MANPATH
  unset MANPATH
  print $+manpath
  MANPATH=/elsewhere:/somewhere
  print $manpath
0:Unsetting and recreation of tied special parameters
>0
>/here:/there
>0
>/elsewhere /somewhere

  local STRING=a:b
  typeset -T STRING string
  print $STRING $string
  unset STRING
  set -A string x y z
  print $STRING $string
  STRING=a:b
  typeset -T STRING string
  print $STRING $string
  unset STRING
  set -A string x y z
  print $STRING $string
  STRING=a:b
  typeset -T STRING string
  print $STRING $string
  unset string
  STRING=x:y:z
  print $STRING $string
  STRING=a:b
  typeset -T STRING string
  print $STRING $string
  unset string
  STRING=x:y:z
  print $STRING $string
0:Unsetting and recreation of tied normal parameters
>a:b a b
>x y z
>a:b a b
>x y z
>a:b a b
>x:y:z
>a:b a b
>x:y:z

  string='look for a match in here'
  if [[ ${string%%(#b)(match)*} = "look for a " ]]; then
    print $match[1] $mbegin[1] $mend[1] $string[$mbegin[1],$mend[1]]
    print $#match $#mbegin $#mend
  else
    print That didn\'t work.
  fi
0:Parameters associated with backreferences
>match 12 16 match
>1 1 1
#' deconfuse emacs

  string='and look for a MATCH in here'
  if [[ ${(S)string%%(#m)M*H} = "and look for a  in here" ]]; then
    print $MATCH $MBEGIN $MEND $string[$MBEGIN,$MEND]
    print $#MATCH
  else
    print Oh, dear.  Back to the drawing board.
  fi
0:Parameters associated with (#m) flag
>MATCH 16 20 MATCH
>5

  string='this is a string'
  print ${string//(#m)s/$MATCH $MBEGIN $MEND}
0:(#m) flag with pure string
>this 4 4 is 7 7 a s 11 11tring

  print ${${~:-*}//(#m)*/$MATCH=$MATCH}
0:(#m) flag with tokenized input
>*=*

  print -l JAMES${(u)${=:-$(echo yes yes)}}JOYCE
  print -l JAMES${(u)${=:-$(echo yes yes she said yes i will yes)}}JOYCE
0:Bug with (u) flag reducing arrays to one element
>JAMESyesJOYCE
>JAMESyes
>she
>said
>i
>willJOYCE

  foo=
  print "${${foo}/?*/replacement}"
0:Quoted zero-length strings are handled properly
>

  file=aleftkept
  print ${file//(#b)(*)left/${match/a/andsome}}
  print ${file//(#b)(*)left/${match//a/andsome}}
0:Substitutions where $match is itself substituted in the replacement
>andsomekept
>andsomekept

  file=/one/two/three/four
  print ${file:fh}
  print ${file:F.1.h}
  print ${file:F+2+h}
  print ${file:F(3)h}
  print ${file:F<4>h}
  print ${file:F{5}h}
0:Modifiers with repetition
>/
>/one/two/three
>/one/two
>/one
>/
>/

  baz=foo/bar
  zab=oof+rab
  print ${baz:s/\//+/}
  print "${baz:s/\//+/}"
  print ${zab:s/+/\//}
  print "${zab:s/+/\//}"
0:Quoting of separator in substitution modifier
>foo+bar
>foo+bar
>oof/rab
>oof/rab

  bsbs='X\\\\Y'
  print -r -- ${bsbs:s/\\/\\/}
  print -r -- "${bsbs:s/\\/\\/}"
  print -r -- ${bsbs:s/\\\\/\\\\/}
  print -r -- "${bsbs:s/\\\\/\\\\/}"
  print -r -- ${bsbs:gs/\\/\\/}
  print -r -- "${bsbs:gs/\\/\\/}"
  print -r -- ${bsbs:gs/\\\\/\\\\/}
  print -r -- "${bsbs:gs/\\\\/\\\\/}"
0:Handling of backslashed backslashes in substitution modifier
>X\\\\Y
>X\\\\Y
>X\\\\Y
>X\\\\Y
>X\\\\Y
>X\\\\Y
>X\\\\Y
>X\\\\Y

  print -r ${${:-one/two}:s,/,X&Y,}
  print -r ${${:-one/two}:s,/,X\&Y,}
  print -r ${${:-one/two}:s,/,X\\&Y,}
  print -r "${${:-one/two}:s,/,X&Y,}"
  print -r "${${:-one/two}:s,/,X\&Y,}"
  print -r "${${:-one/two}:s,/,X\\&Y,}"
0:Quoting of ampersand in substitution modifier RHS
>oneX/Ytwo
>oneX&Ytwo
>oneX\/Ytwo
>oneX/Ytwo
>oneX&Ytwo
>oneX\/Ytwo

  nully=($'a\0c' $'a\0b\0b' $'a\0b\0a' $'a\0b\0' $'a\0b' $'a\0' $'a')
  for string in ${(o)nully}; do
    for (( i = 1; i <= ${#string}; i++ )); do
      foo=$string[i]
      printf "%02x" $(( #foo ))
    done
    print
  done
0:Sorting arrays with embedded nulls
>61
>6100
>610062
>61006200
>6100620061
>6100620062
>610063

  array=(X)
  patterns=("*X*" "spong" "a[b")
  for pat in $patterns; do
    print A${array[(r)$pat]}B C${array[(I)$pat]}D
  done
0:Bad patterns should never match array elements
>AXB C1D
>AB C0D
>AB C0D

  foo=(a6 a117 a17 b6 b117 b17)
  print ${(n)foo}
  print ${(On)foo}
0:Numeric sorting
>a6 a17 a117 b6 b17 b117
>b117 b17 b6 a117 a17 a6

  x=sprodj
  x[-10]=scrumf
  print $x
0:Out of range negative scalar subscripts
>scrumfsprodj

  a=(some sunny day)
  a[-10]=(we\'ll meet again)
  print -l $a
0:Out of range negative array subscripts
>we'll
>meet
>again
>some
>sunny
>day

# ' emacs likes this close quote

  a=(sping spang spong bumble)
  print ${a[(i)spong]}
  print ${a[(i)spung]}
  print ${a[(ib.1.)spong]}
  print ${a[(ib.4.)spong]}
  print ${a[(ib.10.)spong]}
0:In and out of range reverse matched indices without and with b: arrays
>3
>5
>3
>5
>5

  a="thrimblewuddlefrong"
  print ${a[(i)w]}
  print ${a[(i)x]}
  print ${a[(ib.3.)w]}
  print ${a[(ib.10.)w]}
  print ${a[(ib.30.)w]}
0:In and out of range reverse matched indices without and with b: strings
>9
>20
>9
>20
>20

  foo="line:with::missing::fields:in:it"
  print -l ${(s.:.)foo}
0:Removal of empty fields in unquoted splitting
>line
>with
>missing
>fields
>in
>it

  foo="line:with::missing::fields:in:it"
  print -l "${(s.:.)foo}"
0:Hacky removal of empty fields in quoted splitting with no "@"
>line
>with
>missing
>fields
>in
>it

  foo="line:with::missing::fields:in:it"
  print -l "${(@s.:.)foo}"
0:Retention of empty fields in quoted splitting with "@"
>line
>with
>
>missing
>
>fields
>in
>it

  array=('%' '$' 'j' '*' '$foo')
  print ${array[(i)*]} "${array[(i)*]}"
  print ${array[(ie)*]} "${array[(ie)*]}"
  key='$foo'
  print ${array[(ie)$key]} "${array[(ie)$key]}"
  key='*'
  print ${array[(ie)$key]} "${array[(ie)$key]}"
0:Matching array indices with and without quoting
>1 1
>4 4
>5 5
>4 4

# Ordering of associative arrays is arbitrary, so we need to use
# patterns that only match one element.
  typeset -A assoc_r
  assoc_r=(star '*' of '*this*' and '!that!' or '(the|other)')
  print ${(kv)assoc_r[(re)*]}
  print ${(kv)assoc_r[(re)*this*]}
  print ${(kv)assoc_r[(re)!that!]}
  print ${(kv)assoc_r[(re)(the|other)]}
  print ${(kv)assoc_r[(r)*at*]}
  print ${(kv)assoc_r[(r)*(ywis|bliss|kiss|miss|this)*]}
  print ${(kv)assoc_r[(r)(this|that|\(the\|other\))]}
0:Reverse subscripting associative arrays with literal matching
>star *
>of *this*
>and !that!
>or (the|other)
>and !that!
>of *this*
>or (the|other)

  print $ZSH_SUBSHELL
  (print $ZSH_SUBSHELL)
  ( (print $ZSH_SUBSHELL) )
  ( (print $ZSH_SUBSHELL); print $ZSH_SUBSHELL )
  print $(print $ZSH_SUBSHELL)
  cat =(print $ZSH_SUBSHELL)
0:ZSH_SUBSHELL
>0
>1
>2
>2
>1
>1
>1

  foo=("|" "?")
  [[ "|" = ${(j.|.)foo} ]] && print yes || print no
  [[ "|" = ${(j.|.)~foo} ]] && print yes || print no
  [[ "|" = ${(~j.|.)foo} ]] && print yes || print no
  [[ "|" = ${(~~j.|.)foo} ]] && print yes || print no
  [[ "|" = ${(j.|.~)foo} ]] && print yes || print no
  [[ "x" = ${(j.|.)foo} ]] && print yes || print no
  [[ "x" = ${(j.|.)~foo} ]] && print yes || print no
  [[ "x" = ${(~j.|.)foo} ]] && print yes || print no
  [[ "x" = ${(~~j.|.)foo} ]] && print yes || print no
  [[ "x" = ${(j.|.~)foo} ]] && print yes || print no
0:GLOBSUBST only on parameter substitution arguments
>no
>yes
>yes
>no
>no
>no
>yes
>no
>no
>no

  rcexbug() {
    emulate -L zsh
    setopt rcexpandparam
    local -A hash
    local -a full empty
    full=(X x)
    hash=(X x)
    print ORDINARY ARRAYS
    : The following behaves as documented in zshoptions
    print FULL expand=$full
    : Empty arrays remove the adjacent argument
    print EMPTY expand=$empty
    print ASSOCIATIVE ARRAY
    print Subscript flags returning many values
    print FOUND key=$hash[(I)X] val=$hash[(R)x]
    : This should behave like $empty, and does
    print LOST key=$hash[(I)y] val=$hash[(R)Y]
    print Subscript flags returning single values
    : Doc says "substitutes ... empty string"
    : so must not behave like an empty array
    print STRING key=$hash[(i)y] val=$hash[(r)Y]
  }
  rcexbug
0:Lookup failures on elements of arrays with RC_EXPAND_PARAM
>ORDINARY ARRAYS
>FULL expand=X expand=x
>EMPTY
>ASSOCIATIVE ARRAY
>Subscript flags returning many values
>FOUND key=X val=x
>LOST
>Subscript flags returning single values
>STRING key= val=

   print $zsh_eval_context[1]
   [[ $ZSH_EVAL_CONTEXT = ${(j.:.)zsh_eval_context} ]] || print Not equal!
   (( icontext = ${#zsh_eval_context} + 1 ))
   contextfn() { print $(print $zsh_eval_context[icontext,-1]); }
   contextfn
0:$ZSH_EVAL_CONTEXT and $zsh_eval_context
>toplevel
>shfunc cmdsubst

   foo="123456789"
   print ${foo:3}
   print ${foo: 1 + 3}
   print ${foo:$(( 2 + 3))}
   print ${foo:$(echo 3 + 3)}
   print ${foo:3:1}
   print ${foo: 1 + 3:(4-2)/2}
   print ${foo:$(( 2 + 3)):$(( 7 - 6 ))}
   print ${foo:$(echo 3 + 3):`echo 4 - 3`}
   print ${foo: -1}
   print ${foo: -10}
0:Bash-style offsets, scalar
>456789
>56789
>6789
>789
>4
>5
>6
>7
>9
>123456789

   foo=(1 2 3 4 5 6 7 8 9)
   print ${foo:3}
   print ${foo: 1 + 3}
   print ${foo:$(( 2 + 3))}
   print ${foo:$(echo 3 + 3)}
   print ${foo:3:1}
   print ${foo: 1 + 3:(4-2)/2}
   print ${foo:$(( 2 + 3)):$(( 7 - 6 ))}
   print ${foo:$(echo 3 + 3):`echo 4 - 3`}
   print ${foo: -1}
   print ${foo: -10}
0:Bash-style offsets, array
>4 5 6 7 8 9
>5 6 7 8 9
>6 7 8 9
>7 8 9
>4
>5
>6
>7
>9
>1 2 3 4 5 6 7 8 9

   testfn() {
     emulate -L sh
     set -A foo 1 2 3
     set -- 1 2 3
     str=abc
     echo ${foo[*]:0:1}
     echo ${foo[*]:1:1}
     echo ${foo[*]: -1:1}
     :
     echo ${*:0:1}
     echo ${*:1:1}
     echo ${*: -1:1}
     :
     echo ${str:0:1}
     echo ${str:1:1}
     echo ${str: -1:1}
   }
   testfn
0:Bash-style offsets, Bourne-style indexing
>1
>2
>3
>testfn
>1
>3
>a
>b
>c