1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/src/cmd/ksh93/tests/sh_match.sh
Johnothan King dccf6b5ea8 Backport ksh93v- regression tests and fix various regression test bugs (#472)
- tests/*.sh: Backported many additional regression tests and test
  fixes from the alpha and beta releases of ksh93v-.

- tests/alias.sh: Avoid trying to add vi to the hash table, as some
  platforms do not provide a vi(1) implementation installed as part
  of the default system. This fixes a regression test failure I was
  getting in one of my Linux virtual machines.

- tests/builtins.sh: Fixed a bug in one of the regression tests that
  caused an incorrect total error count if any of the tests failed.

- tests/sh_match.sh: Fixed a regression test failure on DragonFly
  BSD caused by the diff command printing an extra 'No differences
  encountered' line.
2022-03-11 21:15:55 +01:00

1078 lines
39 KiB
Bash
Executable file

########################################################################
# #
# This software is part of the ast package #
# Copyright (c) 1982-2012 AT&T Intellectual Property #
# Copyright (c) 2012 Roland Mainz #
# Copyright (c) 2020-2022 Contributors to ksh 93u+m #
# and is licensed under the #
# Eclipse Public License, Version 1.0 #
# by AT&T Intellectual Property #
# #
# A copy of the License is available at #
# http://www.eclipse.org/org/documents/epl-v10.html #
# (with md5 checksum b35adb5213ca9657e911e9befb180842) #
# #
# Information and Software Systems Research #
# AT&T Research #
# Florham Park NJ #
# #
# David Korn <dgkorn@gmail.com> #
# Roland Mainz <roland.mainz@nrubsig.org> #
# #
########################################################################
#
# This test module tests the .sh.match pattern matching facility
#
. "${SHTESTS_COMMON:-${0%/*}/_common}"
# =====
# Start with basic character class matching tests backported from ksh2020. This
# is primarily to verify that the underlying AST regex code is working as
# expected before moving on to more complex tests.
[[ 1 =~ [[:digit:]] ]] || err_exit 'pattern [[:digit:]] broken'
[[ x =~ [[:digit:]] ]] && err_exit 'pattern [[:digit:]] broken'
[[ 5 =~ [[:alpha:]] ]] && err_exit 'pattern [[:alpha:]] broken'
[[ z =~ [[:alpha:]] ]] || err_exit 'pattern [[:alpha:]] broken'
[[ 3 =~ [[:alnum:]] ]] || err_exit 'pattern [[:alnum:]] broken'
[[ y =~ [[:alnum:]] ]] || err_exit 'pattern [[:alnum:]] broken'
[[ / =~ [[:alnum:]] ]] && err_exit 'pattern [[:alnum:]] broken'
[[ 3 =~ [[:lower:]] ]] && err_exit 'pattern [[:lower:]] broken'
[[ y =~ [[:lower:]] ]] || err_exit 'pattern [[:lower:]] broken'
[[ B =~ [[:lower:]] ]] && err_exit 'pattern [[:lower:]] broken'
[[ 3 =~ [[:upper:]] ]] && err_exit 'pattern [[:upper:]] broken'
[[ y =~ [[:upper:]] ]] && err_exit 'pattern [[:upper:]] broken'
[[ B =~ [[:upper:]] ]] || err_exit 'pattern [[:upper:]] broken'
[[ 7 =~ [[:word:]] ]] || err_exit 'pattern [[:word:]] broken'
[[ x =~ [[:word:]] ]] || err_exit 'pattern [[:word:]] broken'
[[ _ =~ [[:word:]] ]] || err_exit 'pattern [[:word:]] broken'
[[ + =~ [[:word:]] ]] && err_exit 'pattern [[:word:]] broken'
[[ . =~ [[:space:]] ]] && err_exit 'pattern [[:space:]] broken'
[[ X =~ [[:space:]] ]] && err_exit 'pattern [[:space:]] broken'
[[ ' ' =~ [[:space:]] ]] || err_exit 'pattern [[:space:]] broken'
[[ $'\t' =~ [[:space:]] ]] || err_exit 'pattern [[:space:]] broken'
[[ $'\v' =~ [[:space:]] ]] || err_exit 'pattern [[:space:]] broken'
[[ $'\f' =~ [[:space:]] ]] || err_exit 'pattern [[:space:]] broken'
[[ $'\n' =~ [[:space:]] ]] || err_exit 'pattern [[:space:]] broken'
[[ . =~ [[:blank:]] ]] && err_exit 'pattern [[:blank:]] broken'
[[ X =~ [[:blank:]] ]] && err_exit 'pattern [[:blank:]] broken'
[[ ' ' =~ [[:blank:]] ]] || err_exit 'pattern [[:blank:]] broken'
[[ $'\t' =~ [[:blank:]] ]] || err_exit 'pattern [[:blank:]] broken'
[[ $'\v' =~ [[:blank:]] ]] && err_exit 'pattern [[:blank:]] broken'
[[ ' ' =~ [[:space:]] ]] || err_exit 'pattern [[:space:]] broken'
[[ $'\t' =~ [[:space:]] ]] || err_exit 'pattern [[:space:]] broken'
[[ $'\v' =~ [[:space:]] ]] || err_exit 'pattern [[:space:]] broken'
[[ $'\f' =~ [[:space:]] ]] || err_exit 'pattern [[:space:]] broken'
[[ $'\n' =~ [[:space:]] ]] || err_exit 'pattern [[:space:]] broken'
[[ . =~ [[:blank:]] ]] && err_exit 'pattern [[:blank:]] broken'
[[ X =~ [[:blank:]] ]] && err_exit 'pattern [[:blank:]] broken'
[[ ' ' =~ [[:blank:]] ]] || err_exit 'pattern [[:blank:]] broken'
[[ $'\t' =~ [[:blank:]] ]] || err_exit 'pattern [[:blank:]] broken'
[[ $'\v' =~ [[:blank:]] ]] && err_exit 'pattern [[:blank:]] broken'
[[ $'\f' =~ [[:blank:]] ]] && err_exit 'pattern [[:blank:]] broken'
[[ $'\n' =~ [[:blank:]] ]] && err_exit 'pattern [[:blank:]] broken'
[[ Z =~ [[:print:]] ]] || err_exit 'pattern [[:print:]] broken'
[[ ' ' =~ [[:print:]] ]] || err_exit 'pattern [[:print:]] broken'
[[ $'\cg' =~ [[:print:]] ]] && err_exit 'pattern [[:print:]] broken'
[[ Z =~ [[:cntrl:]] ]] && err_exit 'pattern [[:cntrl:]] broken'
[[ ' ' =~ [[:cntrl:]] ]] && err_exit 'pattern [[:cntrl:]] broken'
[[ $'\cg' =~ [[:cntrl:]] ]] || err_exit 'pattern [[:cntrl:]] broken'
[[ \$ =~ [[:graph:]] ]] || err_exit 'pattern [[:graph:]] broken'
[[ ' ' =~ [[:graph:]] ]] && err_exit 'pattern [[:graph:]] broken'
[[ \$ =~ [[:punct:]] ]] || err_exit 'pattern [[:punct:]] broken'
[[ / =~ [[:punct:]] ]] || err_exit 'pattern [[:punct:]] broken'
[[ ' ' =~ [[:punct:]] ]] && err_exit 'pattern [[:punct:]] broken'
[[ x =~ [[:punct:]] ]] && err_exit 'pattern [[:punct:]] broken'
[[ ' ' =~ [[:xdigit:]] ]] && err_exit 'pattern [[:xdigit:]] broken'
[[ x =~ [[:xdigit:]] ]] && err_exit 'pattern [[:xdigit:]] broken'
[[ 0 =~ [[:xdigit:]] ]] || err_exit 'pattern [[:xdigit:]] broken'
[[ 9 =~ [[:xdigit:]] ]] || err_exit 'pattern [[:xdigit:]] broken'
[[ A =~ [[:xdigit:]] ]] || err_exit 'pattern [[:xdigit:]] broken'
[[ a =~ [[:xdigit:]] ]] || err_exit 'pattern [[:xdigit:]] broken'
[[ F =~ [[:xdigit:]] ]] || err_exit 'pattern [[:xdigit:]] broken'
[[ f =~ [[:xdigit:]] ]] || err_exit 'pattern [[:xdigit:]] broken'
[[ G =~ [[:xdigit:]] ]] && err_exit 'pattern [[:xdigit:]] broken'
[[ g =~ [[:xdigit:]] ]] && err_exit 'pattern [[:xdigit:]] broken'
[[ 3 =~ \w ]] || err_exit 'pattern \w broken'
[[ y =~ \w ]] || err_exit 'pattern \w broken'
[[ / =~ \w ]] && err_exit 'pattern \w broken'
[[ 3 =~ \W ]] && err_exit 'pattern \w broken'
[[ y =~ \W ]] && err_exit 'pattern \w broken'
[[ / =~ \W ]] || err_exit 'pattern \w broken'
[[ . =~ \s ]] && err_exit 'pattern \s broken'
[[ X =~ \s ]] && err_exit 'pattern \s broken'
[[ ' ' =~ \s ]] || err_exit 'pattern \s broken'
[[ $'\t' =~ \s ]] || err_exit 'pattern \s broken'
[[ $'\v' =~ \s ]] || err_exit 'pattern \s broken'
[[ $'\f' =~ \s ]] || err_exit 'pattern \s broken'
[[ $'\n' =~ \s ]] || err_exit 'pattern \s broken'
[[ x =~ \d ]] && err_exit 'pattern \d broken'
[[ 9 =~ \d ]] || err_exit 'pattern \d broken'
[[ x =~ \D ]] || err_exit 'pattern \D broken'
[[ 9 =~ \D ]] && err_exit 'pattern \D broken'
[[ 7 =~ \b ]] || err_exit 'pattern \b broken'
[[ x =~ \b ]] || err_exit 'pattern \b broken'
[[ _ =~ \b ]] || err_exit 'pattern \b broken'
[[ + =~ \b ]] || err_exit 'pattern \b broken'
[[ 'x y ' =~ .\b.\b ]] || err_exit 'pattern \b broken'
[[ ' xy ' =~ .\b.\b ]] && err_exit 'pattern \b broken'
[[ 7 =~ \B ]] && err_exit 'pattern \B broken'
[[ x =~ \B ]] && err_exit 'pattern \B broken'
[[ _ =~ \B ]] && err_exit 'pattern \B broken'
[[ + =~ \B ]] || err_exit 'pattern \B broken'
# ======
# Tests backported from ksh93v-
function test_xmlfragment1
{
typeset -r testscript='test1_script.sh'
cat >"${testscript}" <<-TEST1SCRIPT
# memory safeguards to prevent out-of-control memory consumption
{
ulimit -M \$(( 1024 * 1024 ))
ulimit -v \$(( 1024 * 1024 ))
ulimit -d \$(( 1024 * 1024 ))
} 2>/dev/null
# input text
xmltext="\$( < "\$1" )"
print -f "%d characters to process...\\n" "\${#xmltext}"
#
# parse the XML data
#
typeset dummy
function parse_xmltext
{
typeset xmltext="\$2"
nameref ar="\$1"
# fixme:
# - We want to enforce standard conformance - does ~(Exp) or ~(Ex-p) do that ?
dummy="\${xmltext//~(Ex-p)(?:
(<!--.*-->)+?| # xml comments
(<[:_[:alnum:]-]+
(?: # attributes
[[:space:]]+
(?: # four different types of name=value syntax
(?:[:_[:alnum:]-]+=[^\\"\\'[:space:]]+?)| #x='foo=bar huz=123'
(?:[:_[:alnum:]-]+=\\"[^\\"]*?\\")| #x='foo="ba=r o" huz=123'
(?:[:_[:alnum:]-]+=\\'[^\\']*?\\')| #x="foox huz=123"
(?:[:_[:alnum:]-]+) #x="foox huz=123"
)
)*
[[:space:]]*
\\/? # start tags which are end tags, too (like <foo\\/>)
>)+?| # xml start tags
(<\\/[:_[:alnum:]-]+>)+?| # xml end tags
([^<]+) # xml text
)/D}"
# copy ".sh.match" to array "ar"
integer i j
for i in "\${!.sh.match[@]}" ; do
for j in "\${!.sh.match[i][@]}" ; do
[[ -v .sh.match[i][j] ]] && ar[i][j]="\${.sh.match[i][j]}"
done
done
return 0
}
function rebuild_xml_and_verify
{
nameref ar="\$1"
typeset xtext="\$2" # xml text
#
# rebuild the original text from "ar" (copy of ".sh.match")
# and compare it to the content of "xtext"
#
tmpfile=rebuild_xml_and_verify.\$\$
{
# rebuild the original text, based on our matches
nameref nodes_all=ar[0] # contains all matches
nameref nodes_comments=ar[1] # contains only XML comment matches
nameref nodes_start_tags=ar[2] # contains only XML start tag matches
nameref nodes_end_tags=ar[3] # contains only XML end tag matches
nameref nodes_text=ar[4] # contains only XML text matches
integer i
for (( i = 0 ; i < \${#nodes_all[@]} ; i++ )) ; do
[[ -v nodes_comments[i] ]] && printf '%s' "\${nodes_comments[i]}"
[[ -v nodes_start_tags[i] ]] && printf '%s' "\${nodes_start_tags[i]}"
[[ -v nodes_end_tags[i] ]] && printf '%s' "\${nodes_end_tags[i]}"
[[ -v nodes_text[i] ]] && printf '%s' "\${nodes_text[i]}"
done
printf '\\n'
} >"\${tmpfile}"
diff -u <( printf '%s\\n' "\${xtext}") "\${tmpfile}" | sed '/No differences encountered/d'
if cmp <( printf '%s\\n' "\${xtext}") "\${tmpfile}" ; then
printf "#input and output OK (%d characters).\\n" "\$(wc -m <"\${tmpfile}")"
else
printf "#difference between input and output found.\\n"
fi
rm -f "\${tmpfile}"
return 0
}
# main
set -o nounset
typeset -a xar
parse_xmltext xar "\$xmltext"
rebuild_xml_and_verify xar "\$xmltext"
TEST1SCRIPT
cat >'testfile1.xml' <<-EOF
<refentry>
<refentryinfo>
<title>&dhtitle;</title>
<productname>&dhpackage;</productname>
<releaseinfo role="version">&dhrelease;</releaseinfo>
<date>&dhdate;</date>
<authorgroup>
<author>
<firstname>XXXX</firstname>
<surname>YYYYYYYYYYYY</surname>
<contrib>Wrote this example manpage for the &quot;SunOS Man Page Howto&quot;, available at <ulink url="http://www.YYYYYYYYYYYY.xxx/foo_batt_12345.abcd"/> or <ulink url="http://www.1234.xxx/info/SunOS-mini/123-4567.hhhh"/>.</contrib>
<address>
<email>mailmail@YYYYYYYYYYYY.xxx</email>
</address>
</author>
<author>
<firstname>&dhfirstname;</firstname>
<surname>&dhsurname;</surname>
<contrib>Rewrote and extended the example manpage in DocBook XML for the Zebras distribution.</contrib>
<address>
<email>&dhemail;</email>
</address>
</author>
</authorgroup>
<copyright>
<year>1995</year>
<year>1996</year>
<year>1997</year>
<year>1998</year>
<year>1999</year>
<year>2000</year>
<year>2001</year>
<year>2002</year>
<year>2003</year>
<holder>XXXX YYYYYYYYYYYY</holder>
</copyright>
<copyright>
<year>2006</year>
<holder>&dhusername;</holder>
</copyright>
<legalnotice>
<para>The Howto containing this example, was offered under the following conditions:</para>
<para>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</para>
<orderedlist>
<listitem>
<para>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</para>
</listitem>
<listitem>
<para>Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.</para>
</listitem>
</orderedlist>
<para>THIS SOFTWARE IS PROVIDED BY THE AUTHOR &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</para>
</legalnotice>
</refentryinfo>
<refmeta>
<refentrytitle>&dhucpackage;</refentrytitle>
<manvolnum>&dhsection;</manvolnum>
</refmeta>
<refnamediv>
<refname>&dhpackage;</refname>
<refpurpose>frobnicate the bar library</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>&dhpackage;</command>
<arg choice="opt"><option>-bar</option></arg>
<group choice="opt">
<arg choice="plain"><option>-b</option></arg>
<arg choice="plain"><option>--busy</option></arg>
</group>
<group choice="opt">
<arg choice="plain"><option>-c <replaceable>config-file</replaceable></option></arg>
<arg choice="plain"><option>--config=<replaceable>config-file</replaceable></option></arg>
</group>
<arg choice="opt">
<group choice="req">
<arg choice="plain"><option>-e</option></arg>
<arg choice="plain"><option>--example</option></arg>
</group>
<replaceable class="option">this</replaceable>
</arg>
<arg choice="opt">
<group choice="req">
<arg choice="plain"><option>-e</option></arg>
<arg choice="plain"><option>--example</option></arg>
</group>
<group choice="req">
<arg choice="plain"><replaceable>this</replaceable></arg>
<arg choice="plain"><replaceable>that</replaceable></arg>
</group>
</arg>
<arg choice="plain" rep="repeat"><replaceable>file(s)</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>&dhpackage;</command>
<!-- Normally the help and version options make the programs stop
right after outputting the requested information. -->
<group choice="opt">
<arg choice="plain">
<group choice="req">
<arg choice="plain"><option>-h</option></arg>
<arg choice="plain"><option>--help</option></arg>
</group>
</arg>
<arg choice="plain">
<group choice="req">
<arg choice="plain"><option>-v</option></arg>
<arg choice="plain"><option>--version</option></arg>
</group>
</arg>
</group>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1 id="description">
<title>DESCRIPTION</title>
<para><command>&dhpackage;</command> frobnicates the <application>bar</application> library by tweaking internal symbol tables. By default it parses all baz segments and rearranges them in reverse order by time for the <citerefentry><refentrytitle>xyzzy</refentrytitle><manvolnum>1</manvolnum></citerefentry> linker to find them. The symdef entry is then compressed using the <abbrev>WBG</abbrev> (Whiz-Bang-Gizmo) algorithm. All files are processed in the order specified.</para>
</refsect1>
<refsect1 id="options">
<title>OPTIONS</title>
<variablelist>
<!-- Use the variablelist.term.separator and the
variablelist.term.break.after parameters to
control the term elements. -->
<varlistentry>
<term><option>-b</option></term>
<term><option>--busy</option></term>
<listitem>
<para>Do not write <quote>busy</quote> to <filename class="devicefile">stdout</filename> while processing.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-c <replaceable class="parameter">config-file</replaceable></option></term>
<term><option>--config=<replaceable class="parameter">config-file</replaceable></option></term>
<listitem>
<para>Use the alternate system wide <replaceable>config-file</replaceable> instead of the <filename>/etc/foo.conf</filename>. This overrides any <envar>FOOCONF</envar> environment variable.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-a</option></term>
<listitem>
<para>In addition to the baz segments, also parse the <citerefentry><refentrytitle>blurfl</refentrytitle><manvolnum>3</manvolnum></citerefentry> headers.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-r</option></term>
<listitem>
<para>Recursive mode. Operates as fast as lightning at the expense of a megabyte of virtual memory.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="files">
<title>FILES</title>
<variablelist>
<varlistentry>
<term><filename>/etc/foo.conf</filename></term>
<listitem>
<para>The system-wide configuration file. See <citerefentry><refentrytitle>foo.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> for further details.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><filename>\${HOME}/.foo.conf</filename></term>
<listitem>
<para>The per-user configuration file. See <citerefentry><refentrytitle>foo.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> for further details.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="environment">
<title>ENVIRONMENT</title>
<variablelist>
<varlistentry>
<term><envar>FOOCONF</envar></term>
<listitem>
<para>The full pathname for an alternate system wide configuration file <citerefentry><refentrytitle>foo.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> (see also <xref linkend="files"/>). Overridden by the <option>-c</option> option.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="diagnostics">
<title>DIAGNOSTICS</title>
<para>The following diagnostics may be issued on <filename class="devicefile">stderr</filename>:</para>
<variablelist>
<varlistentry>
<term><quote><errortext>Bad magic number.</errortext></quote></term>
<listitem>
<para>The input file does not look like an archive file.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><quote><errortext>Old style baz segments.</errortext></quote></term>
<listitem>
<para><command>&dhpackage;</command> can only handle new style baz segments. <acronym>COBOL</acronym> object libraries are not supported in this version.</para>
</listitem>
</varlistentry>
</variablelist>
<para>The following return codes can be used in scripts:</para>
<segmentedlist>
<segtitle>Errorcode</segtitle>
<segtitle>Errortext</segtitle>
<segtitle>Diagnostic</segtitle>
<seglistitem>
<seg><errorcode>0</errorcode></seg>
<seg><errortext>Program exited normally.</errortext></seg>
<seg>No error. Program ran successfully.</seg>
</seglistitem>
<seglistitem>
<seg><errorcode>1</errorcode></seg>
<seg><errortext>Bad magic number.</errortext></seg>
<seg>The input file does not look like an archive file.</seg>
</seglistitem>
<seglistitem>
<seg><errorcode>2</errorcode></seg>
<seg><errortext>Old style baz segments.</errortext></seg>
<seg><command>&dhpackage;</command> can only handle new style baz segments. <acronym>COBOL</acronym> object libraries are not supported in this version.</seg>
</seglistitem>
</segmentedlist>
</refsect1>
<refsect1 id="bugs">
<!-- Or use this section to tell about upstream BTS. -->
<title>BUGS</title>
<para>The command name should have been chosen more carefully to reflect its purpose.</para>
<para>The upstreams <acronym>BTS</acronym> can be found at <ulink url="http://bugzilla.foo.tld"/>.</para>
</refsect1>
<refsect1 id="see_also">
<title>SEE ALSO</title>
<!-- In alphabetical order. -->
<para><citerefentry>
<refentrytitle>bar</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>, <citerefentry>
<refentrytitle>foo</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>, <citerefentry>
<refentrytitle>foo.conf</refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry>, <citerefentry>
<refentrytitle>xyzzy</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry></para>
<para>The programs are documented fully by <citetitle>The Rise and Fall of a Fooish Bar</citetitle> available via the <application>Info</application> system.</para>
</refsect1>
</refentry>
EOF
# Note: Standalone '>' is valid XML text
printf "%s" $'<h1 style=\'nice\' h="bar">> <oook:banana color="<yellow />"><oook:apple-mash color="<green />"><div style="some green"><illegal tag /><br /> a text </div>More [TEXT].<!-- a comment (<disabled>) --></h1>' >'testfile2.xml'
compound -r -a tests=(
(
file='testfile1.xml'
expected_output=$'9764 characters to process...\n#input and output OK (9765 characters).'
)
(
file='testfile2.xml'
expected_output=$'201 characters to process...\n#input and output OK (202 characters).'
)
)
compound out=( typeset stdout stderr ; integer res )
integer i
typeset expected_output
typeset testname
for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do
nameref tst=tests[i]
testname="${0}/${i}/${tst.file}"
expected_output="${tst.expected_output}"
out.stderr="${ { out.stdout="${ ${SHELL} -o nounset "${testscript}" "${tst.file}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
[[ "${out.stdout}" == "${expected_output}" ]] || err_exit "${testname}: Expected stdout==${ printf '%q\n' "${expected_output}" ;}, got ${ printf '%q\n' "${out.stdout}" ; }"
[[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got ${ printf '%q\n' "${out.stderr}" ; }"
(( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}"
done
rm "${testscript}"
rm 'testfile1.xml'
rm 'testfile2.xml'
return 0
}
# test whether the [[ -v .sh.match[x][y] ]] operator works, try1
function test_testop_v1
{
compound out=( typeset stdout stderr ; integer res )
integer i
typeset testname
typeset expected_output
compound -r -a tests=(
(
cmd='s="aaa bbb 333 ccc 555" ; s="${s//~(E)([[:alpha:]]+)|([[:digit:]]+)/NOP}" ; [[ -v .sh.match[2][3] ]] || print "OK"'
expected_output='OK'
)
(
cmd='s="aaa bbb 333 ccc 555" ; s="${s//~(E)([[:alpha:]]+)|([[:digit:]]+)/NOP}" ; integer i=2 j=3 ; [[ -v .sh.match[$i][$j] ]] || print "OK"'
expected_output='OK'
)
(
cmd='s="aaa bbb 333 ccc 555" ; s="${s//~(E)([[:alpha:]]+)|([[:digit:]]+)/NOP}" ; integer i=2 j=3 ; [[ -v .sh.match[i][j] ]] || print "OK"'
expected_output='OK'
)
)
for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do
nameref tst=tests[i]
testname="${0}/${i}/${tst.cmd}"
expected_output="${tst.expected_output}"
out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${tst.cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
[[ "${out.stdout}" == "${expected_output}" ]] || err_exit "${testname}: Expected stdout==${ printf '%q\n' "${expected_output}" ;}, got ${ printf '%q\n' "${out.stdout}" ; }"
[[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got ${ printf '%q\n' "${out.stderr}" ; }"
(( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}"
done
return 0
}
# test whether the [[ -v .sh.match[x][y] ]] operator works, try2
function test_testop_v2
{
compound out=( typeset stdout stderr ; integer res )
integer i
integer j
integer j
typeset testname
typeset cmd
compound -r -a tests=(
(
cmd='s="aaa bbb 333 ccc 555" ; s="${s//~(E)([[:alpha:]]+)|([[:digit:]]+)/NOP}"'
integer y=6
expected_output_1d=$'[0]\n[1]\n[2]'
expected_output_2d=$'[0][0]\n[0][1]\n[0][2]\n[0][3]\n[0][4]\n[1][0]\n[1][1]\n[1][3]\n[2][2]\n[2][4]'
)
# FIXME: Add more hideous horror tests here
)
for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do
nameref tst=tests[i]
#
# test first dimension, by plain number
#
cmd="${tst.cmd}"
for (( j=0 ; j < tst.y ; j++ )) ; do
cmd+="; $( printf "[[ -v .sh.match[%d] ]] && print '[%d]'\n" j j )"
done
cmd+='; true'
testname="${0}/${i}/plain_number_index_1d/${cmd}"
out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
[[ "${out.stdout}" == "${tst.expected_output_1d}" ]] || err_exit "${testname}: Expected stdout==${ printf '%q\n' "${tst.expected_output_1d}" ;}, got ${ printf '%q\n' "${out.stdout}" ; }"
[[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got ${ printf '%q\n' "${out.stderr}" ; }"
(( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}"
#
# test second dimension, by plain number
#
cmd="${tst.cmd}"
for (( j=0 ; j < tst.y ; j++ )) ; do
for (( k=0 ; k < tst.y ; k++ )) ; do
cmd+="; $( printf "[[ -v .sh.match[%d][%d] ]] && print '[%d][%d]'\n" j k j k )"
done
done
cmd+='; true'
testname="${0}/${i}/plain_number_index_2d/${cmd}"
out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
[[ "${out.stdout}" == "${tst.expected_output_2d}" ]] || err_exit "${testname}: Expected stdout==${ printf '%q\n' "${tst.expected_output_2d}" ;}, got ${ printf '%q\n' "${out.stdout}" ; }"
[[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got ${ printf '%q\n' "${out.stderr}" ; }"
(( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}"
#
# test first dimension, by variable index
#
cmd="${tst.cmd} ; integer i"
for (( j=0 ; j < tst.y ; j++ )) ; do
cmd+="; $( printf "(( i=%d )) ; [[ -v .sh.match[i] ]] && print '[%d]'\n" j j )"
done
cmd+='; true'
testname="${0}/${i}/variable_index_1d/${cmd}"
out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
[[ "${out.stdout}" == "${tst.expected_output_1d}" ]] || err_exit "${testname}: Expected stdout==${ printf '%q\n' "${tst.expected_output_1d}" ;}, got ${ printf '%q\n' "${out.stdout}" ; }"
[[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got ${ printf '%q\n' "${out.stderr}" ; }"
(( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}"
#
# test second dimension, by variable index
#
cmd="${tst.cmd} ; integer i j"
for (( j=0 ; j < tst.y ; j++ )) ; do
for (( k=0 ; k < tst.y ; k++ )) ; do
cmd+="; $( printf "(( i=%d , j=%d )) ; [[ -v .sh.match[i][j] ]] && print '[%d][%d]'\n" j k j k )"
done
done
cmd+='; true'
testname="${0}/${i}/variable_index_2d/${cmd}"
out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
[[ "${out.stdout}" == "${tst.expected_output_2d}" ]] || err_exit "${testname}: Expected stdout==${ printf '%q\n' "${tst.expected_output_2d}" ;}, got ${ printf '%q\n' "${out.stdout}" ; }"
[[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got ${ printf '%q\n' "${out.stderr}" ; }"
(( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}"
done
return 0
}
# test whether ${#.sh.match[0][@]} returns the right number of elements
function test_num_elements1
{
compound out=( typeset stdout stderr ; integer res )
integer i
typeset testname
typeset expected_output
compound -r -a tests=(
(
cmd='s="a1a2a3" ; d="${s//~(E)([[:alpha:]])|([[:digit:]])/dummy}" ; printf "num=%d\n" "${#.sh.match[0][@]}"'
expected_output='num=6'
)
(
cmd='s="ababab" ; d="${s//~(E)([[:alpha:]])|([[:digit:]])/dummy}" ; printf "num=%d\n" "${#.sh.match[0][@]}"'
expected_output='num=6'
)
(
cmd='s="123456" ; d="${s//~(E)([[:alpha:]])|([[:digit:]])/dummy}" ; printf "num=%d\n" "${#.sh.match[0][@]}"'
expected_output='num=6'
)
)
for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do
nameref tst=tests[i]
testname="${0}/${i}/${tst.cmd}"
expected_output="${tst.expected_output}"
out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${tst.cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
[[ "${out.stdout}" == "${expected_output}" ]] || err_exit "${testname}: Expected stdout==${ printf '%q\n' "${expected_output}" ; }, got ${ printf '%q\n' "${out.stdout}" ; }"
[[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got ${ printf '%q\n' "${out.stderr}" ; }"
(( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}"
done
return 0
}
# dgk's test which checks whether typeset -m (rename variable) works for .sh.match
function test_shmatch_varmove_dgk1
{
typeset out
# we use an array of $'...\n' here to get correct line numbers
typeset -r -a script=(
$'set -o nounset\n'
$'x=1234\n'
$'compound co\n'
$': "${x//~(X)([012])|([345])/ }"\n'
$'x="$(print -v .sh.match)"\n'
$'typeset -m co.array=.sh.match\n'
$'y="$(print -v co.array)"\n'
$'[[ "$y" == "$x" ]] && print "MATCH"\n'
# fixme: this currently outputs as ${co.array[2][(null)]}, which isn't correct
# # added later by gisburn
# $'printf "%s" "${co.array[2][1]}"'
)
out="$(${SHELL} -c "${script[*]}" 2>&1 ; print -- "$?")"
[[ "${out}" == $'MATCH\n0' ]] || err_exit "${0}: typeset -m of .sh.match to variable not working, expected 'MATCH', got ${ printf '%q\n' "${out}" ; }"
return 0
}
function test_nomatch_dgk1
{
cat >'testscript1.sh' <<'EOF'
integer j k
compound c
compound -a c.attrs
attrdata=$' x=\'1\' y=\'2\' z="3" end="world"'
dummy="${attrdata//~(Ex-p)(?:
[[:space:]]+
( # four different types of name=value syntax
(?:([:_[:alnum:]-]+)=([^\"\'[:space:]]+?))| #x='foo=bar huz=123'
(?:([:_[:alnum:]-]+)=\"([^\"]*?)\")| #x='foo="ba=r o" huz=123'
(?:([:_[:alnum:]-]+)=\'([^\']*?)\')| #x="foox huz=123"
(?:([:_[:alnum:]-]+)) #x="foox huz=123"
)
)/D}"
for (( j=0 ; j < ${#.sh.match[0][@]} ; j++ ))
do
if [[ -v .sh.match[2][j] && -v .sh.match[3][j] ]]
then c.attrs+=( name="${.sh.match[2][j]}" value="${.sh.match[3][j]}" )
fi
if [[ -v .sh.match[4][j] && -v .sh.match[5][j] ]]
then c.attrs+=( name="${.sh.match[4][j]}" value="${.sh.match[5][j]}" )
fi
if [[ -v .sh.match[6][j] && -v .sh.match[7][j] ]] ; then
c.attrs+=( name="${.sh.match[6][j]}" value="${.sh.match[7][j]}" )
fi
done
print -v c
EOF
expect='(
typeset -a attrs=(
[0]=(
name=x
value=1
)
[1]=(
name=y
value=2
)
[2]=(
name=z
value=3
)
[3]=(
name=end
value=world
)
)
)'
compound out=( typeset stdout stderr ; integer res )
typeset testname
# plain
testname="${0}/plain"
out.stderr="${ { out.stdout="${ ${SHELL} -o nounset 'testscript1.sh' ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
[[ "${out.stdout}" == "${expect}" ]] || err_exit "${testname}: Expected stdout==${ printf '%q\n' "${expect}" ; }, got ${ printf '%q\n' "${out.stdout}" ; }"
[[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got ${ printf '%q\n' "${out.stderr}" ; }"
(( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}"
# compiled
testname="${0}/compiled"
out.stderr="${ { out.stdout="${ ${SHCOMP} -n 'testscript1.sh' 'testscript1.shbin' ; ${SHELL} -o nounset 'testscript1.shbin' ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
[[ "${out.stdout}" == "${expect}" ]] || err_exit "${testname}: Expected stdout==${ printf '%q\n' "${expect}" ; }, got ${ printf '%q\n' "${out.stdout}" ; }"
[[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got ${ printf '%q\n' "${out.stderr}" ; }"
(( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}"
rm 'testscript1.sh' 'testscript1.shbin'
return 0
}
function test_sh_match_varmove2
{
cat >'testscript1.sh' <<EOF
function parse_attr
{
typeset move_mode=\$1
typeset attrdata=" \$2" # leading space is intentional to get eregex to work below
integer i
typeset dummy="\${attrdata//~(Ex-p)(?:
[[:space:]]+
( # four different types of name=value syntax
(?:([:_[:alnum:]-]+)=([^\"\'[:space:]]+?))|
(?:([:_[:alnum:]-]+)=\"([^\"]*?)\")|
(?:([:_[:alnum:]-]+)=\'([^\']*?)\')|
(?:([:_[:alnum:]-]+))
)
)/D}"
case \${move_mode} in
'plain')
nameref m=.sh.match
;;
'move')
typeset -m m=.sh.match
;;
'move_to_compound')
compound mc
typeset -m mc.m=.sh.match
nameref m=mc.m
;;
'move_to_nameref_compound')
compound mc
nameref mcn=mc
typeset -m mcn.m=.sh.match
nameref m=mcn.m
;;
*)
print -u2 -f '# wrong move_mode=%q\n' "\${move_mode}"
return 1
;;
esac
for (( i=0 ; i < \${#m[0][@]} ; i++ )) ; do
[[ -v m[2][i] && -v m[3][i] ]] && printf '%q=%q\n' "\${m[2][i]}" "\${m[3][i]}"
[[ -v m[4][i] && -v m[5][i] ]] && printf '%q=%q\n' "\${m[4][i]}" "\${m[5][i]}"
[[ -v m[6][i] && -v m[7][i] ]] && printf '%q=%q\n' "\${m[6][i]}" "\${m[7][i]}"
done
print "Nummatches=\${#m[0][@]}"
return 0
}
set -o nounset
parse_attr "\$1" "\$2"
exit \$?
EOF
compound -r -a tests=(
( attrstr=$'aname="avalue" x="y"' output=$'aname=avalue\nx=y\nNummatches=2' )
( attrstr=$'aname=\'avalue\' x=\'y\'' output=$'aname=avalue\nx=y\nNummatches=2' )
( attrstr=$'aname="avalue" x=\'y\'' output=$'aname=avalue\nx=y\nNummatches=2' )
( attrstr=$'aname=\'avalue\' x="y"' output=$'aname=avalue\nx=y\nNummatches=2' )
( attrstr=$'aname="avalue"' output=$'aname=avalue\nNummatches=1' )
)
compound out=( typeset stdout stderr ; integer res )
typeset testname
typeset mode
integer numtests=0
${SHCOMP} -n 'testscript1.sh' 'testscript1.shbin' || err_exit "${0}: shcomp failed with exit code $?."
for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do
nameref tst=tests[$i] # fixme: this should be tst=tests[i]
for mode in 'plain' 'move' 'move_to_compound' 'move_to_nameref_compound' ; do
# plain
testname="${0}/${i}/${mode}/plain"
out.stderr="${ { out.stdout="${ ${SHELL} 'testscript1.sh' ${mode} "${tst.attrstr}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
[[ "${out.stdout}" == "${tst.output}" ]] || err_exit "${testname}: Expected stdout==${ printf '%q\n' "${tst.output}" ; }, got ${ printf '%q\n' "${out.stdout}" ; }"
[[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got ${ printf '%q\n' "${out.stderr}" ; }"
(( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}"
(( numtests++ ))
# compiled
testname="${0}/${i}/${mode}/compiled"
out.stderr="${ { out.stdout="${ ${SHELL} 'testscript1.shbin' ${mode} "${tst.attrstr}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }"
[[ "${out.stdout}" == "${tst.output}" ]] || err_exit "${testname}: Expected stdout==${ printf '%q\n' "${tst.output}" ; }, got ${ printf '%q\n' "${out.stdout}" ; }"
[[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got ${ printf '%q\n' "${out.stderr}" ; }"
(( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}"
(( numtests++ ))
done
done
rm 'testscript1.sh' 'testscript1.shbin'
# safeguard against malfunctions in the test chain
(( numtests == 40 )) || err_exit "${0}: Internal test script error, expected numtests == 40, got ${numtests}"
return 0
}
# run tests
test_xmlfragment1
test_testop_v1
test_testop_v2
test_num_elements1
test_shmatch_varmove_dgk1
test_sh_match_varmove2
test_nomatch_dgk1
# ======
set +u
x=1234
compound co
: "${x//~(X)([012])|([345])/ }"
x=$(print -v .sh.match)
typeset -m co.array=.sh.match
y=$(print -v co.array)
[[ $y == "$x" ]] || 'typeset -m of .sh.match to variable not working'
# ======
# https://github.com/ksh93/ksh/issues/308
exp='typeset -a .sh.match=((1 2 3 4) (1 2) ([2]=3 [3]=4) )
typeset -a .sh.match[1]=(1 2)
typeset -a .sh.match[2]=([2]=3 [3]=4)
3 2 2
2 3'
got=$("$SHELL" -c '
x=1234
true ${x//~(X)([012])|([345])/ }
typeset -p .sh.match .sh.match[1] .sh.match[2]
echo ${#.sh.match[@]} ${#.sh.match[1][@]} ${#.sh.match[2][@]}
echo ${!.sh.match[2][@]};
')
[[ $exp == "$got" ]] || err_exit "listing .sh.match indexed array results doesn't work correctly" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
# https://marc.info/?l=ast-developers&m=134604855504311&w=2
nummatches=$tmp/nummatches.sh
cat > "$nummatches" << 'EOF'
attrdata=$' aname=avalue '
dummy="${attrdata//~(Ex-p)(?:
[[:space:]]+
( # four different types of name=value syntax
(?:([:_[:alnum:]-]+)=([^\"\'[:space:]]+?))|
(?:([:_[:alnum:]-]+)=\"([^\"]*?)\")|
(?:([:_[:alnum:]-]+)=\'([^\']*?)\')|
(?:([:_[:alnum:]-]+))
)
)/D}"
print -v .sh.match
print "Nummatches=${#.sh.match[0][@]}"
EOF
exp=$'(
(
\' aname=a\'
)
(
aname\\=a
)
(
aname
)
(
a
)
)
Nummatches=1'
got=$("$SHELL" "$nummatches")
[[ $exp == "$got" ]] || err_exit "Nummatches should be one" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
# https://marc.info/?l=ast-developers&m=134490505607093
if ((SHOPT_NAMESPACE)); then
type_nameref=$tmp/ksh93v_typeset_T_nameref_fails001.sh
cat > "$type_nameref" << 'EOF'
namespace xmlfragmentparser
{
typeset -T parser_t=(
typeset -a data # "raw" data from .sh.match
compound -a context # parsed tag data
function build_context
{
typeset dummy
typeset attrdata # data after "<tag" ...
integer i
for (( i=0 ; i < ${#_.data[@]} ; i++ )) ; do
nameref currc=_.context[i] # current context
dummy="${_.data[i]/~(El)<([:_[:alnum:]-]+)(.*)>/X}"
currc.tagname="${.sh.match[1]}"
attrdata="${.sh.match[2]}"
if [[ "${attrdata}" != ~(Elr)[[:space:]]* ]] ; then
dummy="${attrdata//~(Ex-p)(?:
[[:space:]]+
( # four different types of name=value syntax
(?:([:_[:alnum:]-]+)=([^\"\'[:space:]]+?))| #x='foo=bar huz=123'
(?:([:_[:alnum:]-]+)=\"([^\"]*?)\")| #x='foo="ba=r o" huz=123'
(?:([:_[:alnum:]-]+)=\'([^\']*?)\')| #x="foox huz=123"
(?:([:_[:alnum:]-]+)) #x="foox huz=123"
)
)/D}"
integer j k
compound -a currc.attrs
for (( j=0 ; j < ${#.sh.match[0][@]} ; j++ )) ; do
if [[ -v .sh.match[2][j] && -v .sh.match[3][j] ]] ; then
currc.attrs+=( name="${.sh.match[2][j]}" value="${.sh.match[3][j]}" )
fi ; if [[ -v .sh.match[4][j] && -v .sh.match[5][j] ]] ; then
currc.attrs+=( name="${.sh.match[4][j]}" value="${.sh.match[5][j]}" )
fi ; if [[ -v .sh.match[6][j] && -v .sh.match[7][j] ]] ; then
currc.attrs+=( name="${.sh.match[6][j]}" value="${.sh.match[7][j]}" )
fi
done
fi
done
return 0
}
)
}
function main
{
.xmlfragmentparser.parser_t xd # xml document
xd.data=( "<foo x='1' y='2' />" "<bar a='1' b='2' />" )
xd.build_context
print "$xd"
return 0
}
# main
set -o nounset
main
EOF
exp="(
typeset -a data=(
$'<foo x=\\'1\\' y=\\'2\\' />'
$'<bar a=\\'1\\' b=\\'2\\' />'
)
typeset -C -a context=(
[0]=(
typeset -a attrs=(
[0]=(
name=x
value=1
)
[1]=(
name=y
value=2
)
)
tagname=foo
)
[1]=(
typeset -a attrs=(
[0]=(
name=a
value=1
)
[1]=(
name=b
value=2
)
)
tagname=bar
)
)
)"
got=$("$SHELL" "$type_nameref")
[[ $exp == "$got" ]] || err_exit "Compound variable \$context is not printed with 'print -v'." \
$'Diff follows:\n'"$(diff -u <(print -r -- "$exp") <(print -r -- "$got") | sed $'s/^/\t| /')"
fi
# ======
exit $((Errors<125?Errors:125))