Index: build_ksh93_standalone.sh =================================================================== --- build_ksh93_standalone.sh (revision 0) +++ build_ksh93_standalone.sh (revision 1122) @@ -0,0 +1,58 @@ +#!/usr/bin/ksh93 + +function fatal_error +{ + print -u 2 "${progname}: $@" + exit 1 +} + +set -o xtrace +set -o errexit + +typeset progname="$(basename "$0")" + +# assertions +[[ "$SRC" != "" ]] || fatal_error "SRC not set." +[[ -d "$SRC" ]] || fatal_error "SRC is not directory." + +# check whether "make setup" was executed +[[ -x "$CTFCONVERT" ]] || fatal_error "CTFCONVERT seem to be unavailable." + +# build ksh93 +cd "$SRC" + +export CW_NO_SHADOW=1 + +( + cd lib + for i in libast libdll libpp libsum libcmd libshell ; do + ( + cd "$i" + make install + ) + done +) + +( + cd cmd + for i in isaexec ksh shcomp ast nsadmin file ; do + ( + cd "$i" + make install + ) + done +) + +( + cd lib + for i in libast libdll libpp libsum libcmd libshell ; do + ( + cd "$i" + make _msg + ) + done +) +print "#done." + +# EOF. + Index: src/pkgdefs/SUNWhea/prototype_com =================================================================== --- src/pkgdefs/SUNWhea/prototype_com (revision 974) +++ src/pkgdefs/SUNWhea/prototype_com (revision 1122) @@ -17,13 +17,13 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END -# # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)prototype_com 1.480 07/12/28 SMI" +# ident "%Z%%M% %I% %E% SMI" # # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package @@ -81,6 +81,8 @@ f none usr/include/ast/ast_map.h 644 root bin f none usr/include/ast/ast_mmap.h 644 root bin f none usr/include/ast/ast_mode.h 644 root bin +f none usr/include/ast/ast_namval.h 644 root bin +f none usr/include/ast/ast_ndbm.h 644 root bin f none usr/include/ast/ast_nl_types.h 644 root bin f none usr/include/ast/ast_param.h 644 root bin f none usr/include/ast/ast_standards.h 644 root bin @@ -120,6 +122,7 @@ f none usr/include/ast/hashpart.h 644 root bin f none usr/include/ast/history.h 644 root bin f none usr/include/ast/iconv.h 644 root bin +f none usr/include/ast/ip6.h 644 root bin f none usr/include/ast/lc.h 644 root bin f none usr/include/ast/ls.h 644 root bin f none usr/include/ast/magic.h 644 root bin @@ -144,12 +147,14 @@ f none usr/include/ast/sfio.h 644 root bin f none usr/include/ast/sfio_s.h 644 root bin f none usr/include/ast/sfio_t.h 644 root bin +f none usr/include/ast/shcmd.h 644 root bin f none usr/include/ast/shell.h 644 root bin f none usr/include/ast/sig.h 644 root bin f none usr/include/ast/stack.h 644 root bin f none usr/include/ast/stak.h 644 root bin f none usr/include/ast/stdio.h 644 root bin f none usr/include/ast/stk.h 644 root bin +f none usr/include/ast/sum.h 644 root bin f none usr/include/ast/swap.h 644 root bin f none usr/include/ast/tar.h 644 root bin f none usr/include/ast/times.h 644 root bin Index: src/pkgdefs/SUNWloc/prototype_com =================================================================== --- src/pkgdefs/SUNWloc/prototype_com (revision 974) +++ src/pkgdefs/SUNWloc/prototype_com (revision 1122) @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -18,12 +17,13 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END + # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "@(#)prototype_com 1.44 05/06/08 SMI" +# ident "%Z%%M% %I% %E% SMI" # # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package @@ -53,7 +53,6 @@ f none usr/bin/locale 555 root bin f none usr/bin/mkmsgs 555 root root f none usr/bin/msgfmt 555 root bin -f none usr/bin/printf 555 root bin f none usr/bin/srchtxt 555 root bin f none usr/bin/xgettext 555 root bin d none usr/lib 755 root bin Index: src/pkgdefs/SUNWcsl/prototype_com =================================================================== --- src/pkgdefs/SUNWcsl/prototype_com (revision 974) +++ src/pkgdefs/SUNWcsl/prototype_com (revision 1122) @@ -18,13 +18,12 @@ # # CDDL HEADER END - # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)prototype_com 1.115 08/01/22 SMI" +# ident "%Z%%M% %I% %E% SMI" # # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package @@ -256,6 +255,7 @@ f none usr/lib/libsmbios.so.1 755 root bin s none usr/lib/libsocket.so=../../lib/libsocket.so.1 s none usr/lib/libsocket.so.1=../../lib/libsocket.so.1 +f none usr/lib/libsum.so.1 755 root bin s none usr/lib/libsys.so=./libsys.so.1 f none usr/lib/libsys.so.1 755 root bin s none usr/lib/libsysevent.so=../../lib/libsysevent.so.1 Index: src/pkgdefs/SUNWcsl/prototype_sparc =================================================================== --- src/pkgdefs/SUNWcsl/prototype_sparc (revision 974) +++ src/pkgdefs/SUNWcsl/prototype_sparc (revision 1122) @@ -18,13 +18,12 @@ # # CDDL HEADER END - # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)prototype_sparc 1.40 08/01/22 SMI" +# ident "%Z%%M% %I% %E% SMI" # # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package @@ -309,6 +308,7 @@ s none usr/lib/sparcv9/libsmbios.so=libsmbios.so.1 s none usr/lib/sparcv9/libsocket.so.1=../../../lib/sparcv9/libsocket.so.1 s none usr/lib/sparcv9/libsocket.so=../../../lib/sparcv9/libsocket.so.1 +f none usr/lib/sparcv9/libsum.so.1 755 root bin s none usr/lib/sparcv9/libsysevent.so.1=../../../lib/sparcv9/libsysevent.so.1 s none usr/lib/sparcv9/libsysevent.so=../../../lib/sparcv9/libsysevent.so.1 s none usr/lib/sparcv9/libtermcap.so=../../../lib/sparcv9/libcurses.so.1 Index: src/pkgdefs/SUNWcsl/prototype_i386 =================================================================== --- src/pkgdefs/SUNWcsl/prototype_i386 (revision 974) +++ src/pkgdefs/SUNWcsl/prototype_i386 (revision 1122) @@ -23,7 +23,7 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)prototype_i386 1.39 08/01/22 SMI" +# ident "%Z%%M% %I% %E% SMI" # # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package @@ -322,6 +322,7 @@ f none usr/lib/amd64/libsmbios.so.1 755 root bin s none usr/lib/amd64/libsocket.so.1=../../../lib/amd64/libsocket.so.1 s none usr/lib/amd64/libsocket.so=../../../lib/amd64/libsocket.so.1 +f none usr/lib/amd64/libsum.so.1 755 root bin s none usr/lib/amd64/libsysevent.so=../../../lib/amd64/libsysevent.so.1 s none usr/lib/amd64/libsysevent.so.1=../../../lib/amd64/libsysevent.so.1 s none usr/lib/amd64/libtermcap.so=../../../lib/amd64/libcurses.so.1 Index: src/pkgdefs/SUNWcsu/prototype_com =================================================================== --- src/pkgdefs/SUNWcsu/prototype_com (revision 974) +++ src/pkgdefs/SUNWcsu/prototype_com (revision 1122) @@ -17,12 +17,13 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END + # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)prototype_com 1.567 08/02/13 SMI" +# ident "%Z%%M% %I% %E% SMI" # # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package @@ -220,6 +221,7 @@ f none usr/bin/pktool 555 root bin f none usr/bin/pr 555 root bin l none usr/bin/prctl=../../usr/lib/isaexec +l none usr/bin/printf=../../usr/bin/alias f none usr/bin/priocntl 555 root bin f none usr/bin/profiles 555 root bin f none usr/bin/projects 555 root bin @@ -232,6 +234,7 @@ l none usr/bin/read=../../usr/bin/alias l none usr/bin/red=../../usr/bin/ed f none usr/bin/renice 555 root bin +l none usr/bin/rev=../../usr/bin/alias l none usr/bin/rksh=../../usr/bin/ksh l none usr/bin/rksh93=../../usr/lib/isaexec f none usr/bin/rm 555 root bin @@ -248,7 +251,8 @@ f none usr/bin/settime 555 root bin l none usr/bin/setuname=../../usr/lib/isaexec s none usr/bin/sh=../../sbin/sh -f none usr/bin/sleep 555 root bin +f none usr/bin/shcomp 555 root bin +l none usr/bin/sleep=../../usr/bin/alias l none usr/bin/sparc=../../usr/bin/i286 f none usr/bin/strchg 555 root root s none usr/bin/strclean=../sbin/strclean @@ -256,6 +260,7 @@ s none usr/bin/strerr=../sbin/strerr f none usr/bin/stty 555 root bin f none usr/bin/su 4555 root sys +l none usr/bin/sum=../../usr/bin/alias l none usr/bin/sun2=../../usr/bin/i286 l none usr/bin/sun3=../../usr/bin/i286 l none usr/bin/sun3x=../../usr/bin/i286 Index: src/pkgdefs/etc/exception_list_sparc =================================================================== --- src/pkgdefs/etc/exception_list_sparc (revision 974) +++ src/pkgdefs/etc/exception_list_sparc (revision 1122) @@ -17,12 +17,13 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END + # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)exception_list_sparc 1.276 08/02/13 SMI" +# ident "%Z%%M% %I% %E% SMI" # # Exception List for protocmp # @@ -913,6 +914,12 @@ usr/lib/llib-lshell.ln sparc usr/lib/sparcv9/libshell.so sparc usr/lib/sparcv9/llib-lshell.ln sparc +# libsum +usr/lib/libsum.so sparc +usr/lib/llib-lsum sparc +usr/lib/llib-lsum.ln sparc +usr/lib/sparcv9/libsum.so sparc +usr/lib/sparcv9/llib-lsum.ln sparc # # bmc (IPMI) interfaces shared within ON. # Index: src/pkgdefs/etc/exception_list_i386 =================================================================== --- src/pkgdefs/etc/exception_list_i386 (revision 974) +++ src/pkgdefs/etc/exception_list_i386 (revision 1122) @@ -17,12 +17,13 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END + # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)exception_list_i386 1.252 08/02/13 SMI" +# ident "%Z%%M% %I% %E% SMI" # # Exception List for protocmp # @@ -840,6 +841,12 @@ usr/lib/llib-lshell.ln i386 usr/lib/amd64/libshell.so i386 usr/lib/amd64/llib-lshell.ln i386 +# libsum +usr/lib/libsum.so i386 +usr/lib/llib-lsum i386 +usr/lib/llib-lsum.ln i386 +usr/lib/amd64/libsum.so i386 +usr/lib/amd64/llib-lsum.ln i386 # # bmc (IPMI) interfaces shared within ON. # Index: src/pkgdefs/SUNW0on/prototype_com =================================================================== --- src/pkgdefs/SUNW0on/prototype_com (revision 974) +++ src/pkgdefs/SUNW0on/prototype_com (revision 1122) @@ -17,12 +17,13 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END + # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "@(#)prototype_com 1.79 08/02/13 SMI" +# ident "%Z%%M% %I% %E% SMI" # # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package @@ -85,6 +86,7 @@ f none usr/lib/locale/C/LC_MESSAGES/libcmd 644 root sys f none usr/lib/locale/C/LC_MESSAGES/libdll 644 root sys f none usr/lib/locale/C/LC_MESSAGES/libshell 644 root sys +f none usr/lib/locale/C/LC_MESSAGES/libsum 644 root sys # # Java locale directories # Index: src/pkgdefs/SUNWesu/prototype_com =================================================================== --- src/pkgdefs/SUNWesu/prototype_com (revision 974) +++ src/pkgdefs/SUNWesu/prototype_com (revision 1122) @@ -17,12 +17,13 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END + # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "@(#)prototype_com 1.49 06/10/10 SMI" +# ident "%Z%%M% %I% %E% SMI" # # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package @@ -107,7 +108,6 @@ f none usr/bin/spline 555 root bin f none usr/bin/split 555 root bin s none usr/bin/strace=../sbin/strace -f none usr/bin/sum 555 root bin f none usr/bin/tcopy 555 root bin l none usr/bin/uncompress=../../usr/bin/compress f none usr/bin/unexpand 555 root bin Index: src/pkgdefs/SUNWckr/prototype_sparc =================================================================== --- src/pkgdefs/SUNWckr/prototype_sparc (revision 974) +++ src/pkgdefs/SUNWckr/prototype_sparc (revision 1122) @@ -23,7 +23,7 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)prototype_sparc 1.57 08/02/14 SMI" +# ident "%Z%%M% %I% %E% SMI" # # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package @@ -144,6 +144,7 @@ f none kernel/exec/sparcv9/aoutexec 755 root sys f none kernel/exec/sparcv9/elfexec 755 root sys f none kernel/exec/sparcv9/intpexec 755 root sys +f none kernel/exec/sparcv9/shbinexec 755 root sys d none kernel/fs/sparcv9 755 root sys f none kernel/fs/sparcv9/autofs 755 root sys f none kernel/fs/sparcv9/cachefs 755 root sys Index: src/pkgdefs/SUNWckr/prototype_i386 =================================================================== --- src/pkgdefs/SUNWckr/prototype_i386 (revision 974) +++ src/pkgdefs/SUNWckr/prototype_i386 (revision 1122) @@ -23,7 +23,7 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)prototype_i386 1.59 08/02/15 SMI" +# ident "%Z%%M% %I% %E% SMI" # # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package @@ -150,6 +150,7 @@ f none kernel/drv/wc 755 root sys f none kernel/exec/elfexec 755 root sys f none kernel/exec/intpexec 755 root sys +f none kernel/exec/shbinexec 755 root sys f none kernel/fs/autofs 755 root sys f none kernel/fs/cachefs 755 root sys f none kernel/fs/ctfs 755 root sys @@ -352,6 +353,7 @@ d none kernel/exec/amd64 755 root sys f none kernel/exec/amd64/elfexec 755 root sys f none kernel/exec/amd64/intpexec 755 root sys +f none kernel/exec/amd64/shbinexec 755 root sys d none kernel/fs/amd64 755 root sys f none kernel/fs/amd64/autofs 755 root sys f none kernel/fs/amd64/cachefs 755 root sys Index: src/pkgdefs/SUNWosdem/prototype_com =================================================================== --- src/pkgdefs/SUNWosdem/prototype_com (revision 974) +++ src/pkgdefs/SUNWosdem/prototype_com (revision 1122) @@ -19,10 +19,10 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "@(#)prototype_com 1.14 07/07/24 SMI" +# ident "%Z%%M% %I% %E% SMI" # # This required package information file contains a list of package contents. # The 'pkgmk' command uses this file to identify the contents of a package @@ -54,20 +54,62 @@ f none usr/demo/ELF/dcom.c 644 root bin f none usr/demo/ELF/tpcom.c 644 root bin d none usr/demo/ksh 755 root bin +d none usr/demo/ksh/bin 755 root bin +f none usr/demo/ksh/bin/crawlsrccomments 755 root bin +f none usr/demo/ksh/bin/filemutexdemo1 755 root bin +f none usr/demo/ksh/bin/gnaw 755 root bin +f none usr/demo/ksh/bin/mandelbrotset1 755 root bin +f none usr/demo/ksh/bin/multifollow 755 root bin +f none usr/demo/ksh/bin/primenumbers1 755 root bin +f none usr/demo/ksh/bin/rssread 755 root bin +f none usr/demo/ksh/bin/shman 755 root bin +f none usr/demo/ksh/bin/shnote 755 root bin +f none usr/demo/ksh/bin/shpiano 755 root bin +f none usr/demo/ksh/bin/shtinyurl 755 root bin +f none usr/demo/ksh/bin/shtwitter 755 root bin +f none usr/demo/ksh/bin/svcproptree1 755 root bin +f none usr/demo/ksh/bin/termclock 755 root bin +f none usr/demo/ksh/bin/test_net_sctp 755 root bin +f none usr/demo/ksh/bin/xmldocumenttree1 755 root bin +d none usr/demo/ksh/doc 755 root bin +d none usr/demo/ksh/doc/images 755 root bin +f none usr/demo/ksh/doc/images/tag_bourne.png 644 root bin +f none usr/demo/ksh/doc/images/tag_i18n.png 644 root bin +f none usr/demo/ksh/doc/images/tag_ksh.png 644 root bin +f none usr/demo/ksh/doc/images/tag_ksh88.png 644 root bin +f none usr/demo/ksh/doc/images/tag_ksh93.png 644 root bin +f none usr/demo/ksh/doc/images/tag_l10n.png 644 root bin +f none usr/demo/ksh/doc/images/tag_perf.png 644 root bin +d none usr/demo/ksh/doc/images/callouts 755 root bin +f none usr/demo/ksh/doc/images/callouts/1.png 644 root bin +f none usr/demo/ksh/doc/images/callouts/2.png 644 root bin +f none usr/demo/ksh/doc/images/callouts/3.png 644 root bin +f none usr/demo/ksh/doc/images/callouts/4.png 644 root bin +f none usr/demo/ksh/doc/images/callouts/5.png 644 root bin +f none usr/demo/ksh/doc/images/callouts/6.png 644 root bin +f none usr/demo/ksh/doc/images/callouts/7.png 644 root bin +f none usr/demo/ksh/doc/images/callouts/8.png 644 root bin +f none usr/demo/ksh/doc/images/callouts/9.png 644 root bin +f none usr/demo/ksh/doc/images/callouts/10.png 644 root bin +f none usr/demo/ksh/doc/COMPATIBILITY 644 root bin +f none usr/demo/ksh/doc/DESIGN 644 root bin +f none usr/demo/ksh/doc/OBSOLETE 644 root bin +f none usr/demo/ksh/doc/README 644 root bin +f none usr/demo/ksh/doc/RELEASE 644 root bin +f none usr/demo/ksh/doc/TYPES 644 root bin +f none usr/demo/ksh/doc/shell_styleguide.docbook 644 root bin +f none usr/demo/ksh/doc/shell_styleguide.html 644 root bin d none usr/demo/ksh/fun 755 root bin -f none usr/demo/ksh/fun/dirs 644 root bin -f none usr/demo/ksh/fun/mandelbrotset1 644 root bin -f none usr/demo/ksh/fun/gnaw 644 root bin -f none usr/demo/ksh/fun/rssread 644 root bin -f none usr/demo/ksh/fun/popd 644 root bin -f none usr/demo/ksh/fun/pushd 644 root bin -f none usr/demo/ksh/fun/termclock 644 root bin -f none usr/demo/ksh/fun/title 644 root bin +f none usr/demo/ksh/fun/dirs 755 root bin +f none usr/demo/ksh/fun/popd 755 root bin +f none usr/demo/ksh/fun/pushd 755 root bin +f none usr/demo/ksh/fun/title 755 root bin d none usr/demo/ksh/tests 755 root bin f none usr/demo/ksh/tests/alias.sh 644 root bin f none usr/demo/ksh/tests/append.sh 644 root bin f none usr/demo/ksh/tests/arith.sh 644 root bin f none usr/demo/ksh/tests/arrays.sh 644 root bin +f none usr/demo/ksh/tests/arrays2.sh 644 root bin f none usr/demo/ksh/tests/attributes.sh 644 root bin f none usr/demo/ksh/tests/basic.sh 644 root bin f none usr/demo/ksh/tests/bracket.sh 644 root bin @@ -75,6 +117,8 @@ f none usr/demo/ksh/tests/case.sh 644 root bin f none usr/demo/ksh/tests/comvar.sh 644 root bin f none usr/demo/ksh/tests/coprocess.sh 644 root bin +f none usr/demo/ksh/tests/cubetype.sh 644 root bin +f none usr/demo/ksh/tests/enum.sh 644 root bin f none usr/demo/ksh/tests/exit.sh 644 root bin f none usr/demo/ksh/tests/expand.sh 644 root bin f none usr/demo/ksh/tests/functions.sh 644 root bin @@ -85,15 +129,31 @@ f none usr/demo/ksh/tests/nameref.sh 644 root bin f none usr/demo/ksh/tests/options.sh 644 root bin f none usr/demo/ksh/tests/path.sh 644 root bin +f none usr/demo/ksh/tests/pointtype.sh 644 root bin f none usr/demo/ksh/tests/quoting.sh 644 root bin f none usr/demo/ksh/tests/quoting2.sh 644 root bin +f none usr/demo/ksh/tests/recttype.sh 644 root bin +f none usr/demo/ksh/tests/restricted.sh 644 root bin f none usr/demo/ksh/tests/return.sh 644 root bin f none usr/demo/ksh/tests/select.sh 644 root bin -f none usr/demo/ksh/tests/shtests 644 root bin +f none usr/demo/ksh/tests/shtests 755 root bin +f none usr/demo/ksh/tests/signal.sh 644 root bin +f none usr/demo/ksh/tests/statics.sh 644 root bin f none usr/demo/ksh/tests/substring.sh 644 root bin +f none usr/demo/ksh/tests/subshell.sh 644 root bin +f none usr/demo/ksh/tests/sun_solaris_builtin_sum.sh 644 root bin +f none usr/demo/ksh/tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh 644 root bin f none usr/demo/ksh/tests/sun_solaris_getconf.sh 644 root bin +f none usr/demo/ksh/tests/sun_solaris_local_compound_nameref001.sh 644 root bin +f none usr/demo/ksh/tests/sun_solaris_staticvariables.sh 644 root bin +f none usr/demo/ksh/tests/sun_solaris_vartree001.sh 644 root bin +f none usr/demo/ksh/tests/sun_solaris_vartree002.sh 644 root bin +f none usr/demo/ksh/tests/sun_solaris_vartree003.sh 644 root bin f none usr/demo/ksh/tests/tilde.sh 644 root bin +f none usr/demo/ksh/tests/timetype.sh 644 root bin f none usr/demo/ksh/tests/variables.sh 644 root bin +f none usr/demo/ksh/tests/vartree1.sh 644 root bin +f none usr/demo/ksh/tests/vartree2.sh 644 root bin d none usr/demo/libexacct 755 root bin f none usr/demo/libexacct/README 644 root bin f none usr/demo/libexacct/Makefile 644 root bin Index: src/tools/findunref/exception_list =================================================================== --- src/tools/findunref/exception_list (revision 974) +++ src/tools/findunref/exception_list (revision 1122) @@ -17,13 +17,13 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END -# # +# # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)exception_list 1.92 08/02/13 SMI" +# ident "%Z%%M% %I% %E% SMI" # # Exception list for the findunref tool. Files in this list are by definition # intentionally never used during a standard nightly build. Since very few @@ -96,6 +96,7 @@ ./src/lib/libshell/common/features/* ./src/lib/libshell/misc/buildksh93.ksh ./src/lib/libshell/misc/buildksh93.readme +./src/lib/libshell/misc/opensolaris_shell_styleguide.docbook # # Ignore ksh93/ast-related test programs. @@ -107,16 +108,11 @@ # Ignore ksh93/ast-related source components that are not currently # used but may be useful later. # -./src/lib/libcmd/common/cksum.c -./src/lib/libcmd/common/md5sum.c -./src/lib/libcmd/common/sum.c ./src/lib/libshell/common/bltins/mkservice.c -./src/lib/libshell/common/bltins/shopen.c ./src/lib/libshell/common/data/bash_pre_rc.sh ./src/lib/libshell/common/include/env.h ./src/lib/libshell/common/sh/bash.c ./src/lib/libshell/common/sh/env.c -./src/lib/libshell/common/sh/shcomp.c ./src/lib/libshell/common/sh/suid_exec.c # Index: src/cmd/ksh/Makefile.testshell =================================================================== --- src/cmd/ksh/Makefile.testshell (revision 974) +++ src/cmd/ksh/Makefile.testshell (revision 1122) @@ -19,15 +19,17 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile.testshell 1.1 07/08/10 SMI" +# ident "%Z%%M% %I% %E% SMI" # # -# run the ksh93 minimum set of tests +# Run the ksh93 minimum set of tests # + +# # Notes: # - "builtins.sh" may fail in some locales like this: # -- snip -- @@ -43,22 +45,8 @@ # This may be simply a different sort order or a bug in the test suite. # Currently under investigation. # -# - "io.sh" may fail due a subtle bug in ksh93 or the test suite which -# only happens when ksh93 is NOT called "ksh"; to work around the -# problem the test sequence currently uses $(SRC)/cmd/ksh/$(CMDTRANSMACH)/ksh -# instead of $(SRC)/cmd/ksh/$(CMDTRANSMACH)/$(PROG) until we+upstream figure -# out what exactly is going wrong in this case. -# -- snip -- -# ./close0[2]: ./close1: cannot execute [Exec format error] -# io.sh[81]: picked up file descriptor zero for opening script file -# -- snip -- -# # - These tests need a working system clock, otherwise they'll bite you. # -# - The test frontend in this Makefile should be rewritten in ksh93 -# instead of the current /usr/bin/ksh (=ksh88i). This would be far less -# complicated. -# # - More locales should be tested here (via ON_KSH_TEST_LOCALES below). # Locales like "ru_RU.KOI8-R","de_DE.UTF-8", "is_IS.ISO8859-1", # "is_IS.UTF-8" and "nl_BE.ISO8859-15" are on our wishlist - but @@ -74,19 +62,21 @@ # be run on a quiet system with no other activity. # -TESTSRC= $(LIBSHELLSRC)/../tests +TESTSRC= $(LIBSHELLBASE)/common/tests # ON_KSH_TEST_LOCALES can be overridden via # $ export ON_KSH_TEST_LOCALES= # before $ make install # ON_KSH_TEST_LOCALES = \ C \ - en_US en_US.UTF-8 \ + en_US en_US.ISO8859-15@euro en_US.UTF-8 \ he_IL.UTF-8 \ hi_IN.UTF-8 \ - ja_JP.PCK ja_JP.UTF-8 ja_JP.eucJP \ - ko_KR.EUC \ + ja ja_JP.PCK ja_JP.UTF-8 ja_JP.eucJP \ + ko_KR.UTF-8 ko_KR.EUC \ th_TH.TIS620 \ - zh_CN.EUC zh_CN.GBK zh_CN.GB18030 zh_CN.UTF-8 \ + zh_CN.EUC zh_CN.GBK \ + zh_CN.GB18030 zh_CN.GB18030@pinyin zh_CN.GB18030@radical zh_CN.GB18030@stroke \ + zh_CN.UTF-8 zh_CN.UTF-8@pinyin zh_CN.UTF-8@radical zh_CN.UTF-8@stroke \ zh_HK.BIG5HK \ zh_TW.BIG5 zh_TW.EUC zh_TW.UTF-8 @@ -103,61 +93,66 @@ # test failures). testshell: $(PROG) @ \ + builtin basename ; \ print '# NOTE: Make sure your binaries in ROOT match your kernel!' ; \ ( \ set +o errexit ; \ - export PATH="$(SRC)/cmd/ksh/$(CMDTRANSMACH):/bin:/usr/bin" ; \ + export PATH="$(SRC)/cmd/ksh/$(LIBSHELLMACH):/bin:/usr/bin" ; \ printf "# which ksh='%s', ksh93='%s'\n" \ "$$(which ksh)" "$$(which ksh93)" ; \ ) ; \ - if [[ "$$(isalist | fgrep "$(CMDTRANSMACH)")" = "" ]] ; then \ + if [[ "$$(isalist)" != ~(E)$(LIBSHELLMACH) ]] ; then \ printf \ "# ISA='%s' not available on this system, skipping tests...\n" \ - "$(CMDTRANSMACH)" ; \ + "$(LIBSHELLMACH)" ; \ exit 0 ; \ fi ; \ exec 2>&1 ; \ (supported_locales="$$(/usr/bin/locale -a)" ; \ for test_lang in $(ON_KSH_TEST_LOCALES) ; do \ - if [[ "$$(print "$${supported_locales}" | \ - egrep "^$${test_lang}\$$")" = "" ]] ; then \ + if [[ "$$(print -r -- "$${supported_locales}" | \ + egrep "^$${test_lang}\$$")" == "" ]] ; then \ printf \ "# Locale '%s' not supported, skipping tests...\n" \ "$${test_lang}" ; \ continue ; \ fi ; \ (for test_item in $(ON_KSH_TEST_LIST) ; do \ - [[ "$${test_item}" = "$(TESTSRC)/builtins.sh" || \ - "$${test_item}" = "$(TESTSRC)/options.sh" ]] || \ + [[ "$${test_item}" == "$(TESTSRC)/builtins.sh" || \ + "$${test_item}" == "$(TESTSRC)/options.sh" ]] || \ $(ON_KSH_TEST_IGNORE_TESTFAILURE) && \ set +o errexit ; \ - printf \ - "## Running %s test: LANG='%s' script='%s'\n" \ - "$(CMDTRANSMACH)/ksh" \ - "$${test_lang}" \ - "$$(basename "$${test_item}")"; \ - ( \ - test_output="$$( ( \ - export \ - SHELL="$(SRC)/cmd/ksh/$(CMDTRANSMACH)/ksh" \ - LD_LIBRARY_PATH_64="$(ROOTLIB64)/" \ - LD_LIBRARY_PATH_32="$(ROOTLIB)/" ; \ - LD_LIBRARY_PATH="$(ROOTLIB64)/:$(ROOTLIB)/" ; \ - "$${SHELL}" "$(TESTSRC)/shtests" -t \ - LD_LIBRARY_PATH_64="$${LD_LIBRARY_PATH_64}" \ - LD_LIBRARY_PATH_32="$${LD_LIBRARY_PATH_32}" \ - LD_LIBRARY_PATH="$${LD_LIBRARY_PATH}" \ - SHELL="$${SHELL}" \ - LANG="$${test_lang}" \ - LC_ALL="$${test_lang}" \ - "$${test_item}" \ - ) 2>&1 | while read ; do \ - printf "#\t%s\n" "$${REPLY}" ; \ - done | tee /dev/stderr)" ; \ - [[ "$$(print "$${test_output}" | \ - egrep 'passed \[ .* tests 0 errors \]')" != "" ]] || \ - (print "##> test failed" ; exit 1) \ - ) ; \ - set -o errexit ; \ + for mode in 'plain_script:-s' 'compiled_script:-c' ; do \ + printf \ + "## Running %s test: LANG='%s' script='%s', mode='%s'\n" \ + "$(LIBSHELLMACH)/ksh" \ + "$${test_lang}" \ + "$$(basename "$${test_item}")" \ + "$${mode%:*}"; \ + ( \ + test_output="$$( ( \ + export \ + SHELL="$(SRC)/cmd/ksh/$(LIBSHELLMACH)/ksh" \ + LD_LIBRARY_PATH_64="$(ROOTLIB64)/" \ + LD_LIBRARY_PATH_32="$(ROOTLIB)/" ; \ + LD_LIBRARY_PATH="$(ROOTLIB64)/:$(ROOTLIB)/" ; \ + "$${SHELL}" "$(TESTSRC)/shtests" -t "$${mode#*:}" \ + LD_LIBRARY_PATH_64="$${LD_LIBRARY_PATH_64}" \ + LD_LIBRARY_PATH_32="$${LD_LIBRARY_PATH_32}" \ + LD_LIBRARY_PATH="$${LD_LIBRARY_PATH}" \ + SHELL="$${SHELL}" \ + LANG="$${test_lang}" \ + LC_ALL="$${test_lang}" \ + VMDEBUG=a \ + SHCOMP="$(ROOTBIN)/shcomp" \ + "$${test_item}" \ + ) 2>&1 | while read ; do \ + printf "#\t%s\n" "$${REPLY}" ; \ + done | tee /dev/stderr)" ; \ + [[ "$${test_output}" == ~(E)test.*passed\ \[\ [[:digit:]]*\ test.*\ 0\ errors\ \] ]] || \ + (print "##--------> test failed" ; exit 1) \ + ) ; \ + done ; \ + set -o errexit ; \ done) ; \ done) Index: src/cmd/ksh/sparcv9/Makefile =================================================================== --- src/cmd/ksh/sparcv9/Makefile (revision 974) +++ src/cmd/ksh/sparcv9/Makefile (revision 1122) @@ -19,14 +19,14 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile 1.1 07/07/16 SMI" +# ident "%Z%%M% %I% %E% SMI" # # Specify the MACH we currently use to build and test ksh -CMDTRANSMACH= $(MACH64) +LIBSHELLMACH= $(MACH64) include ../../Makefile.cmd include ../../Makefile.cmd.64 Index: src/cmd/ksh/sparc/Makefile =================================================================== --- src/cmd/ksh/sparc/Makefile (revision 974) +++ src/cmd/ksh/sparc/Makefile (revision 1122) @@ -19,14 +19,14 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile 1.1 07/07/17 SMI" +# ident "%Z%%M% %I% %E% SMI" # # Specify the MACH we currently use to build and test ksh -CMDTRANSMACH= $(MACH) +LIBSHELLMACH= $(MACH) include ../../Makefile.cmd Index: src/cmd/ksh/builtins/alias.sh =================================================================== --- src/cmd/ksh/builtins/alias.sh (revision 0) +++ src/cmd/ksh/builtins/alias.sh (revision 1122) @@ -0,0 +1,48 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Get name of builtin +builtin basename +typeset cmd="$(basename "$0")" + +# If the requested command is not an alias load it explicitly +# to make sure it is not bound to a path (those built-ins which +# are mapped via shell aliases point to commands which are +# "special shell built-ins" which cannot be bound to a specific +# PATH element) - otherwise we may execute the wrong command +# if an executable with the same name sits in a PATH element +# before /usr/bin (e.g. /usr/xpg4/bin/ls would be executed +# before /usr/bin/ls if would look like +# PATH=/usr/xpg4/bin:/usr/bin). +if ! alias "${cmd}" >/dev/null 2>&1; then + builtin ${cmd} +fi + +${cmd} "$@" Index: src/cmd/ksh/builtins/Makefile =================================================================== --- src/cmd/ksh/builtins/Makefile (revision 0) +++ src/cmd/ksh/builtins/Makefile (revision 1122) @@ -0,0 +1,81 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SHELL=/usr/bin/ksh93 + +PROG= alias +ALIASPROG= \ + bg \ + cd \ + command \ + fc \ + fg \ + getopts \ + hash \ + jobs \ + kill \ + printf \ + read \ + rev \ + sleep \ + sum \ + test \ + type \ + ulimit \ + umask \ + unalias \ + wait + +include ../../Makefile.cmd + +ROOTALIASPROG= $(ALIASPROG:%=$(ROOTBIN)/%) + +FILEMODE= 555 +OWNER= root +GROUP= bin + +.KEEP_STATE: + +all: $(PROG) + +$(ROOTBIN)/%: $(ROOTBIN)/alias + builtin rm ; \ + builtin ln ; \ + rm -f "$@" ; \ + ln "$(ROOTBIN)/alias" "$@" + +# In the future we should replace the "cat" with a call to +# "shcomp" to compile the script (for better performance). +$(PROG): alias.sh + cat "alias.sh" >"$@" + +install: all $(ROOTALIASPROG) + +clean clobber: + rm -f $(PROG) + +lint: Index: src/cmd/ksh/i386/Makefile =================================================================== --- src/cmd/ksh/i386/Makefile (revision 974) +++ src/cmd/ksh/i386/Makefile (revision 1122) @@ -19,14 +19,14 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile 1.1 07/07/17 SMI" +# ident "%Z%%M% %I% %E% SMI" # # Specify the MACH we currently use to build and test ksh -CMDTRANSMACH= $(MACH) +LIBSHELLMACH= $(MACH) include ../../Makefile.cmd Index: src/cmd/ksh/Makefile.com =================================================================== --- src/cmd/ksh/Makefile.com (revision 974) +++ src/cmd/ksh/Makefile.com (revision 1122) @@ -19,13 +19,13 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile.com 1.1 07/07/17 SMI" +# ident "%Z%%M% %I% %E% SMI" # -SHELL=/usr/bin/ksh +SHELL=/usr/bin/ksh93 include ../../../Makefile.ksh93switch @@ -38,7 +38,8 @@ OBJECTS= \ pmain.o -LIBSHELLSRC=../../../lib/libshell/common/sh +LIBSHELLBASE=../../../lib/libshell +LIBSHELLSRC=$(LIBSHELLBASE)/common/sh SRCS= $(OBJECTS:%.o=$(LIBSHELLSRC)/%.c) @@ -63,6 +64,8 @@ $(CCVERBOSE) \ -xstrconst +pmain.o := CERRWARN += -erroff=E_NO_IMPLICIT_DECL_ALLOWED + # Set common AST build flags (e.g., needed to support the math stuff). include ../../../Makefile.ast Index: src/cmd/ksh/amd64/Makefile =================================================================== --- src/cmd/ksh/amd64/Makefile (revision 974) +++ src/cmd/ksh/amd64/Makefile (revision 1122) @@ -19,14 +19,14 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile 1.1 07/07/16 SMI" +# ident "%Z%%M% %I% %E% SMI" # # Specify the MACH we currently use to build and test ksh -CMDTRANSMACH= $(MACH64) +LIBSHELLMACH= $(MACH64) include ../../Makefile.cmd include ../../Makefile.cmd.64 Index: src/cmd/ksh/Makefile =================================================================== --- src/cmd/ksh/Makefile (revision 974) +++ src/cmd/ksh/Makefile (revision 1122) @@ -19,13 +19,13 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile 1.1 07/07/10 SMI" +# ident "%Z%%M% %I% %E% SMI" # -SHELL=/usr/bin/ksh +SHELL=/usr/bin/ksh93 include ../../Makefile.ksh93switch @@ -40,6 +40,8 @@ SUBDIRS= $(MACH) $(BUILD64)SUBDIRS += $(MACH64) +SUBDIRS += builtins + # Serialise the build to avoid that we run the test suite for 32bit # and 64bit in parallel .NO_PARALLEL: $(SUBDIRS) @@ -63,13 +65,15 @@ touch $(PROG).po install: $(ISAEXEC) $(SUBDIRS) - $(RM) $(ROOTPROG) - $(LN) $(ISAEXEC) $(ROOTPROG) @(set -o xtrace ; \ + builtin ln ; \ + builtin rm ; \ + rm -f $(ROOTPROG) ; \ + ln $(ISAEXEC) $(ROOTPROG) ; \ for i in $(USRKSH_ALIAS_LIST) ; do \ [[ "$$i" = "$(PROG)" ]] && continue ; \ - $(RM) "$(ROOTBIN)/$$i" ; \ - $(LN) "$(ROOTBIN)/$(PROG)" "$(ROOTBIN)/$$i" ; \ + rm -f "$(ROOTBIN)/$$i" ; \ + ln "$(ROOTBIN)/$(PROG)" "$(ROOTBIN)/$$i" ; \ done \ ) Index: src/cmd/Makefile =================================================================== --- src/cmd/Makefile (revision 974) +++ src/cmd/Makefile (revision 1122) @@ -18,13 +18,12 @@ # # CDDL HEADER END - # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile 1.382 08/01/22 SMI" +# ident "%Z%%M% %I% %E% SMI" include ../Makefile.master include ../Makefile.ksh93switch @@ -348,7 +347,7 @@ setuname \ sgs \ sh \ - sleep \ + shcomp \ smbios \ smbsrv \ smserverd \ @@ -366,7 +365,6 @@ strings \ su \ sulogin \ - sum \ sunpc \ svc \ swap \ @@ -457,7 +455,6 @@ $(CLOSED)/cmd/patch \ $(CLOSED)/cmd/pax \ $(CLOSED)/cmd/pcitool \ - $(CLOSED)/cmd/printf \ $(CLOSED)/cmd/sed \ $(CLOSED)/cmd/sed_xpg4 \ $(CLOSED)/cmd/smartcard \ @@ -657,7 +654,7 @@ sdpadm \ sgs \ sh \ - sleep \ + shcomp \ sort \ split \ ssh \ @@ -665,7 +662,6 @@ stmsboot \ strings \ su \ - sum \ svc \ swap \ syseventadm \ @@ -724,7 +720,6 @@ $(CLOSED)/cmd/od \ $(CLOSED)/cmd/patch \ $(CLOSED)/cmd/pax \ - $(CLOSED)/cmd/printf \ $(CLOSED)/cmd/sed \ $(CLOSED)/cmd/sed_xpg4 \ $(CLOSED)/cmd/tail \ @@ -917,7 +912,8 @@ # # Dependencies # -fs.d: fstyp +fs.d: fstyp +ksh: shcomp isaexec $(FIRST_SUBDIRS) $(BWOSDIRS) $(SUBDIRS) $(BSMSUBDIRS) $(MANIFEST_SUBDIRS): FRC @if [ -f $@/Makefile ]; then \ Index: src/cmd/shcomp/Makefile =================================================================== --- src/cmd/shcomp/Makefile (revision 0) +++ src/cmd/shcomp/Makefile (revision 1122) @@ -0,0 +1,98 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SHELL=/usr/bin/ksh93 + +include ../Makefile.cmd + +.KEEP_STATE: + +# Set common AST build flags (e.g., needed to support the math stuff). +include ../../Makefile.ast + +CFLAGS += \ + $(CCVERBOSE) \ + -xstrconst + +OBJECTS= \ + shcomp.o + +LIBSHELLMACH=$(MACH) +LIBSHELLBASE=../../lib/libshell +LIBSHELLSRC=$(LIBSHELLBASE)/common/sh + +SRCS= $(OBJECTS:%.o=$(LIBSHELLSRC)/%.c) + +GROUP= bin +LDLIBS += -lshell -last + +# 1. Make sure that the -D/-U defines in CFLAGS below are in sync +# with usr/src/lib/libshell/Makefile.com +# 2. We use "=" here since using $(CPPFLAGS.master) is very tricky in our +# case - it MUST come as the last element but future changes in -D options +# may then cause silent breakage in the AST sources because the last -D +# option specified overrides previous -D options so we prefer the current +# way to explicitly list each single flag. +CPPFLAGS = \ + $(DTEXTDOM) $(DTS_ERRNO) \ + $(LIBSHELLCPPFLAGS) + +CFLAGS += \ + $(CCVERBOSE) \ + -xstrconst +CFLAGS64 += \ + $(CCVERBOSE) \ + -xstrconst + +ROOTCMDDIR=$(ROOT)/usr/bin + +PROG= shcomp + +%.o: $(LIBSHELLSRC)/%.c + $(COMPILE.c) -c -o $@ $< + $(POST_PROCESS_O) + +all: $(PROG) + +# dummy file since AST/ksh/shcomp doesn't use *.po files +# (and "shcomp" is just a frontend which calls directly into libshell, +# e.g. there are no l10n strings here) +$(PROG).po: + $(RM) $(PROG).po + $(TOUCH) $(PROG).po + + +install: all $(ROOTCMD) + +$(PROG): $(OBJECTS) + $(RM) shcomp + $(LINK.c) $(OBJECTS) -o $@ $(LDLIBS) + $(POST_PROCESS) + +clean lint: + +include ../Makefile.targ Index: src/cmd/file/magic =================================================================== --- src/cmd/file/magic (revision 974) +++ src/cmd/file/magic (revision 1122) @@ -1,7 +1,4 @@ # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# # CDDL HEADER START # # The contents of this file are subject to the terms of the @@ -20,9 +17,14 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END + # -#ident "@(#)magic 1.58 07/03/13 SMI" # +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# # This file contains the dictionary of file format identifiers (magic strings) # used by file(1). The fields of this file are as follows: # @@ -523,6 +525,7 @@ 0 string LZ DOS built-in 0 byte 0xe9 DOS executable (COM) 0 byte 0xeb DOS executable (COM) +0 string \013\023\010\000 ksh compiled shell script executable 24 long 60012 ufsdump archive file 0 string TZif zoneinfo timezone data file 0 string BZh bzip2 compressed data Index: src/cmd/nsadmin/ksh.kshrc =================================================================== --- src/cmd/nsadmin/ksh.kshrc (revision 974) +++ src/cmd/nsadmin/ksh.kshrc (revision 1122) @@ -20,23 +20,58 @@ # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)ksh.kshrc 1.1 07/06/27 SMI" +# ident "%Z%%M% %I% %E% SMI" # # # This file is sourced by interactive ksh93 shells before ${HOME}/.kshrc # -# Enable "gmacs" editor mode if the user did not set an input mode yet -# (for example via ${EDITOR}, ${VISUAL} or any "set -o" flag) +# Enable "gmacs"+"multiline" editor mode if the user did not set an +# input mode yet (for example via ${EDITOR}, ${VISUAL} or any +# "set -o" flag) if [[ "$(set +o)" != ~(E)--(gmacs|emacs|vi)( |$) ]] ; then - set -o gmacs + set -o gmacs + # enable multiline input mode + #set -o multiline fi - -# enable multiline input mode -#set -o multiline - +# Set a default prompt (@:<"($|#) ">) if +# then variable does not exist in the environment. +# +# Algorithm: +# 1. Define ellisis, either Unicode #2026 for unicode locales +# and "..." otherwise +# ([[ "${LC_ALL}/${LANG}" = ~(Elr)(.*UTF-8/.*|/.*UTF-8) ]] +# ensures that the pattern matches the leftmost sequence +# containing *.UTF-8, allowing to match either LC_ALL or +# LANG when LC_ALL is not set) +# 2. If PWD is within HOME replace value of HOME with '~' +# If the PWD is longer than 20 charatcers shorten it to 20 chars +# print '#' for user "root" and '$' for normal users +# Notes: +# - printf "%*s\r%s" COLUMNS "") # is used at the beginning to +# work around a bug in the "multiline" handling code which +# causes the shell to override it's own prompt when the edit +# line overflows (this happens if the terminal cursor +# position is not 0 when PS1 is printed). +# - PS1 will initially be empty until either... +# a) ... someone sets the variable +# or +# b) ... the prompt is displayed for the first time (default is +# '$ ' for normal users and '# ' for user "root") +if [[ "$(set)" != ~(E)PS1= && "${PS1}" == '' ]] ; then + PS1='$(printf "%*s\r%s" COLUMNS "")${LOGNAME}@$(hostname):$( + ellip="$( + [[ "${LC_ALL}/${LANG}" == ~(Elr)(.*UTF-8/.*|/.*UTF-8) ]] && + printf "\u[2026]\n" || print "..." )" + p="${PWD/~(El)${HOME}/\~}" + (( ${#p} > 20 )) && + print -r -n -- "${ellip}${p:${#p}-20:20}" || + print -r -n -- "${p}" + [[ "${LOGNAME}" == "root" ]] && print -n "# " || print -n "\$ " + )' +fi Index: src/cmd/ast/msgcc/Makefile =================================================================== --- src/cmd/ast/msgcc/Makefile (revision 974) +++ src/cmd/ast/msgcc/Makefile (revision 1122) @@ -19,13 +19,13 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile 1.1 07/07/10 SMI" +# ident "%Z%%M% %I% %E% SMI" # -SHELL=/usr/bin/ksh +SHELL=/usr/bin/ksh93 include ../../Makefile.cmd Index: src/cmd/ast/Makefile =================================================================== --- src/cmd/ast/Makefile (revision 974) +++ src/cmd/ast/Makefile (revision 1122) @@ -19,13 +19,13 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile 1.1 07/06/27 SMI" +# ident "%Z%%M% %I% %E% SMI" # -SHELL=/usr/bin/ksh +SHELL=/usr/bin/ksh93 include ../Makefile.cmd Index: src/Makefile.ast =================================================================== --- src/Makefile.ast (revision 974) +++ src/Makefile.ast (revision 1122) @@ -19,10 +19,10 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile.ast 1.1 07/07/13 SMI" +# ident "%Z%%M% %I% %E% SMI" # # Override this top level flag so the compiler builds in its native @@ -34,8 +34,10 @@ # ... about |#pragma prototyped| ... CERRWARN += -erroff=E_UNRECOGNIZED_PRAGMA_IGNORED -# common CPP flags for libshell consumers (ksh etc.) +# common CPP flags for libshell consumers (ksh, shcomp etc.) LIBSHELLCPPFLAGS = \ + -I$(LIBSHELLBASE)/$(LIBSHELLMACH)/src/cmd/ksh93 \ + -I$(LIBSHELLBASE)/common/include \ -I$(ROOT)/usr/include/ast \ -DKSHELL \ -DSHOPT_BRACEPAT \ @@ -54,14 +56,18 @@ -DSHOPT_RAWONLY \ -DSHOPT_SUID_EXEC \ -DSHOPT_SYSRC \ + -DSHOPT_TYPEDEF \ -DSHOPT_VSH \ -D_BLD_shell \ -D_PACKAGE_ast \ + '-DERROR_CATALOG="libshell"' \ -DERROR_CONTEXT_T=Error_context_t \ '-DUSAGE_LICENSE=\ "[-author?David Korn ]"\ - "[-copyright?Copyright (c) 1982-2007 AT&T Knowledge Ventures]"\ + "[-copyright?Copyright (c) 1982-2008 AT&T Intellectual Property]"\ "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"\ "[--catalog?libshell]"' +# We need this for C99/VLA support +DEBUGFORMAT=-xdebugformat=dwarf Index: src/lib/libshell/Makefile.demo =================================================================== --- src/lib/libshell/Makefile.demo (revision 974) +++ src/lib/libshell/Makefile.demo (revision 1122) @@ -19,28 +19,66 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile.demo 1.1 07/07/10 SMI" +# ident "%Z%%M% %I% %E% SMI" # ROOTDEMODIRBASE= $(ROOT)/usr/demo/ksh DEMOFILES= \ + doc/RELEASE \ + doc/README \ + doc/TYPES \ + doc/DESIGN \ + doc/COMPATIBILITY \ + doc/OBSOLETE \ + doc/shell_styleguide.docbook \ + doc/shell_styleguide.html \ + doc/images/tag_bourne.png \ + doc/images/tag_i18n.png \ + doc/images/tag_ksh88.png \ + doc/images/tag_ksh93.png \ + doc/images/tag_ksh.png \ + doc/images/tag_l10n.png \ + doc/images/tag_perf.png \ + doc/images/callouts/1.png \ + doc/images/callouts/2.png \ + doc/images/callouts/3.png \ + doc/images/callouts/4.png \ + doc/images/callouts/5.png \ + doc/images/callouts/6.png \ + doc/images/callouts/7.png \ + doc/images/callouts/8.png \ + doc/images/callouts/9.png \ + doc/images/callouts/10.png \ + bin/crawlsrccomments \ + bin/filemutexdemo1 \ + bin/gnaw \ + bin/mandelbrotset1 \ + bin/multifollow \ + bin/primenumbers1 \ + bin/rssread \ + bin/shman \ + bin/shnote \ + bin/shpiano \ + bin/shtinyurl \ + bin/shtwitter \ + bin/svcproptree1 \ + bin/termclock \ + bin/test_net_sctp \ + bin/xmldocumenttree1 \ fun/dirs \ - fun/gnaw \ - fun/mandelbrotset1 \ - fun/rssread \ fun/popd \ fun/pushd \ - fun/termclock \ fun/title \ tests/shtests \ tests/alias.sh \ tests/append.sh \ tests/arith.sh \ tests/arrays.sh \ + tests/arrays2.sh \ tests/attributes.sh \ tests/basic.sh \ tests/bracket.sh \ @@ -48,6 +86,8 @@ tests/case.sh \ tests/comvar.sh \ tests/coprocess.sh \ + tests/cubetype.sh \ + tests/enum.sh \ tests/exit.sh \ tests/expand.sh \ tests/functions.sh \ @@ -58,16 +98,70 @@ tests/nameref.sh \ tests/options.sh \ tests/path.sh \ + tests/pointtype.sh \ tests/quoting.sh \ tests/quoting2.sh \ + tests/recttype.sh \ + tests/restricted.sh \ tests/return.sh \ tests/select.sh \ + tests/signal.sh \ + tests/statics.sh \ + tests/sun_solaris_builtin_sum.sh \ + tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh \ + tests/sun_solaris_getconf.sh \ + tests/sun_solaris_local_compound_nameref001.sh \ + tests/sun_solaris_staticvariables.sh \ + tests/sun_solaris_vartree001.sh \ + tests/sun_solaris_vartree002.sh \ + tests/sun_solaris_vartree003.sh \ tests/substring.sh \ - tests/sun_solaris_getconf.sh \ + tests/subshell.sh \ tests/tilde.sh \ - tests/variables.sh + tests/timetype.sh \ + tests/variables.sh \ + tests/vartree1.sh \ + tests/vartree2.sh +# Rules for executables +$(ROOTDEMODIRBASE)/tests/shtests := FILEMODE= 755 +$(ROOTDEMODIRBASE)/fun/% := FILEMODE= 755 +$(ROOTDEMODIRBASE)/bin/% := FILEMODE= 755 + +# ToDO: We should replace the "cat $<" below with$ shcomp $< # once the build +# machines start to ship /usr/bi/shcomp to compile the scripts +# in bin/ and use $ shcomp -n $< # to do minimum lint-style checks before +# installation. +$(ROOTDEMODIRBASE)/bin/%: common/scripts/%.sh + cat "$<" >"$(@F)" + $(INS) -s -m $(FILEMODE) -f $(@D) "$(@F)" + $(RM) "$(@F)" + +# Documentation rules +$(ROOTDEMODIRBASE)/doc/%: common/% + $(INS.file) + +$(ROOTDEMODIRBASE)/doc/%: misc/% + $(INS.file) + +$(ROOTDEMODIRBASE)/doc/%.html: misc/%.docbook + /usr/bin/xsltproc \ + --nonet \ + --stringparam generate.section.toc.level 0 \ + --stringparam toc.max.depth 3 \ + --stringparam toc.section.depth 12 \ + --xinclude \ + -o "$(@F)" \ + /usr/share/sgml/docbook/xsl-stylesheets/html/docbook.xsl \ + "$<" + $(INS) -s -m $(FILEMODE) -f "$(@D)" "$(@F)" + $(RM) "$(@F)" + ROOTDEMODIRS= $(ROOTDEMODIRBASE) .WAIT \ + $(ROOTDEMODIRBASE)/bin \ + $(ROOTDEMODIRBASE)/doc .WAIT \ + $(ROOTDEMODIRBASE)/doc/images .WAIT \ + $(ROOTDEMODIRBASE)/doc/images/callouts \ $(ROOTDEMODIRBASE)/fun \ $(ROOTDEMODIRBASE)/tests Index: src/lib/libshell/sparcv9/include/ast/shcmd.h =================================================================== --- src/lib/libshell/sparcv9/include/ast/shcmd.h (revision 0) +++ src/lib/libshell/sparcv9/include/ast/shcmd.h (revision 1122) @@ -0,0 +1,89 @@ + +/* : : generated by proto : : */ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1992-2008 AT&T Intellectual Property * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler * +* David Korn * +* * +***********************************************************************/ + + +/* + * ksh builtin command api + */ + +#ifndef _SHCMD_H +#if !defined(__PROTO__) +#include +#endif +#if !defined(__LINKAGE__) +#define __LINKAGE__ /* 2004-08-11 transition */ +#endif + +#define _SHCMD_H 1 + +#ifndef SH_VERSION +# define Shell_t void +#endif +#ifndef NV_DEFAULT +# define Namval_t void +#endif +#ifndef ERROR_NOTIFY +# define ERROR_NOTIFY 1 +#endif + +typedef int (*Shbltin_f) __PROTO__((int, char**, __V_*)); + +#undef Shbltin_t +typedef struct Shbltin_s +{ + Shell_t *shp; + __V_ *ptr; + int version; + int (*shrun) __PROTO__((int, char**)); + int (*shtrap) __PROTO__((const char*, int)); + void (*shexit) __PROTO__((int)); + Namval_t *(*shbltin) __PROTO__((const char*, Shbltin_f, __V_*)); + unsigned char notify; + unsigned char sigset; + unsigned char nosfio; + Namval_t *bnode; + Namval_t *vnode; + char *data; + int flags; +} Shbltin_t; + +#if defined(SH_VERSION) || defined(_SH_PRIVATE) +# undef Shell_t +# undef Namval_t +#else +# define sh_run(c, ac, av) ((c)?(*((Shbltin_t*)(c))->shrun)(ac,av):-1) +# define sh_system(c,str) ((c)?(*((Shbltin_t*)(c))->shtrap)(str,0):system(str)) +# define sh_exit(c,n) ((c)?(*((Shbltin_t*)(c))->shexit)(n):exit(n)) +# define sh_checksig(c) ((c) && ((Shbltin_t*)(c))->sigset) +# if defined(SFIO_VERSION) || defined(_AST_H) +# define LIB_INIT(c) +# else +# define LIB_INIT(c) ((c) && (((Shbltin_t*)(c))->nosfio = 1)) +# endif +# ifndef _CMD_H +# define cmdinit(ac,av,c,cat,flg) do { if((ac)<=0) return(0); \ + (((Shbltin_t*)(c))->notify = ((flg)&ERROR_NOTIFY)?1:0);} while(0) +# endif +#endif + +#endif Index: src/lib/libshell/sparcv9/include/ast/nval.h =================================================================== --- src/lib/libshell/sparcv9/include/ast/nval.h (revision 974) +++ src/lib/libshell/sparcv9/include/ast/nval.h (revision 1122) @@ -3,10 +3,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -40,6 +40,7 @@ #include #include +#include /* for compatibility with old hash library */ #define Hashtab_t Dt_t @@ -53,8 +54,7 @@ typedef struct Namdisc Namdisc_t; typedef struct Nambfun Nambfun_t; typedef struct Namarray Namarr_t; -typedef struct Nambltin Nambltin_t; -typedef struct Namtype Namtype_t; +typedef struct Namdecl Namdecl_t; /* * This defines the template for nodes that have their own assignment @@ -73,13 +73,14 @@ Namval_t *(*nextf) __PROTO__((Namval_t*, Dt_t*, Namfun_t*)); Namval_t *(*typef) __PROTO__((Namval_t*, Namfun_t*)); int (*readf) __PROTO__((Namval_t*, Sfio_t*, int, Namfun_t*)); + int (*writef) __PROTO__((Namval_t*, Sfio_t*, int, Namfun_t*)); }; struct Namfun { const Namdisc_t *disc; char nofree; - char funs; + unsigned char subshell; unsigned short dsize; Namfun_t *next; char *last; @@ -101,22 +102,14 @@ long nelem; /* number of elements */ __V_ *(*fun) __PROTO__((Namval_t*,const char*,int)); /* associative arrays */ Namval_t *parent; /* for multi-dimensional */ + Dt_t *table; /* for subscripts */ + __V_ *scope; /* non-zerp when scoped */ }; -/* Passed as third argument to a builtin when NV_BLTINOPT is set on node */ -struct Nambltin +/* The context pointer for declaration command */ +struct Namdecl { - __V_ *shp; - Namval_t *np; - __V_ *ptr; - __V_ *data; - int flags; -}; - -struct Namtype -{ - __V_ *shp; - Namval_t *np; + Namval_t *tp; /* point to type */ const char *optstring; __V_ *optinfof; }; @@ -141,6 +134,7 @@ }; #define NV_CLASS ".sh.type" +#define NV_DATA "_" /* special class or instance variable */ #define NV_MINSZ (sizeof(struct Namval)-sizeof(Dtlink_t)-sizeof(char*)) #define nv_namptr(p,n) ((Namval_t*)((char*)(p)+(n)*NV_MINSZ-sizeof(Dtlink_t))) @@ -172,8 +166,9 @@ #define NV_SHORT (NV_RJUST) /* when integers are not long */ #define NV_LONG (NV_UTOL) /* for long long and long double */ #define NV_UNSIGN (NV_LTOU) /* for unsigned quantities */ -#define NV_DOUBLE (NV_ZFILL) /* for floating point */ +#define NV_DOUBLE (NV_INTEGER|NV_ZFILL) /* for floating point */ #define NV_EXPNOTE (NV_LJUST) /* for scientific notation */ +#define NV_HEXFLOAT (NV_LTOU) /* for C99 base16 float notation */ /* options for nv_open */ @@ -194,19 +189,21 @@ #define NV_NODISC NV_IDENT /* ignore disciplines */ #define NV_FUNCT NV_IDENT /* option for nv_create */ -#define NV_BLTINOPT NV_ZFILL /* save state for optimization*/ +#define NV_BLTINOPT NV_ZFILL /* mark builtins in libcmd */ #define NV_PUBLIC (~(NV_NOSCOPE|NV_ASSIGN|NV_IDENT|NV_VARNAME|NV_NOADD)) /* numeric types */ +#define NV_INT16P (NV_LJUST|NV_SHORT|NV_INTEGER) #define NV_INT16 (NV_SHORT|NV_INTEGER) #define NV_UINT16 (NV_UNSIGN|NV_SHORT|NV_INTEGER) +#define NV_UINT16P (NV_LJUSTNV_UNSIGN|NV_SHORT|NV_INTEGER) #define NV_INT32 (NV_INTEGER) #define NV_UNT32 (NV_UNSIGN|NV_INTEGER) #define NV_INT64 (NV_LONG|NV_INTEGER) #define NV_UINT64 (NV_UNSIGN|NV_LONG|NV_INTEGER) -#define NV_FLOAT (NV_SHORT|NV_DOUBLE|NV_INTEGER) -#define NV_LDOUBLE (NV_LONG|NV_DOUBLE|NV_INTEGER) +#define NV_FLOAT (NV_SHORT|NV_DOUBLE) +#define NV_LDOUBLE (NV_LONG|NV_DOUBLE) /* name-value pair macros */ #define nv_isattr(np,f) ((np)->nvflag & (f)) @@ -222,6 +219,7 @@ #define NV_ADELETE 5 /* delete current subscript */ #define NV_AADD 6 /* add subscript if not found */ #define NV_ACURRENT 7 /* return current subscript Namval_t* */ +#define NV_ASETSUB 8 /* set current subscript */ /* The following are for nv_disc */ #define NV_FIRST 1 @@ -250,7 +248,9 @@ # endif /* _BLD_shell */ #endif /* _DLL */ /* prototype for array interface*/ +extern __MANGLE__ Namarr_t *nv_arrayptr __PROTO__((Namval_t*)); extern __MANGLE__ Namarr_t *nv_setarray __PROTO__((Namval_t*,__V_*(*)(Namval_t*,const char*,int))); +extern __MANGLE__ int nv_arraynsub __PROTO__((Namarr_t*)); extern __MANGLE__ __V_ *nv_associative __PROTO__((Namval_t*,const char*,int)); extern __MANGLE__ int nv_aindex __PROTO__((Namval_t*)); extern __MANGLE__ int nv_nextsub __PROTO__((Namval_t*)); @@ -272,12 +272,12 @@ extern __MANGLE__ Namfun_t *nv_hasdisc __PROTO__((Namval_t*, const Namdisc_t*)); extern __MANGLE__ int nv_isnull __PROTO__((Namval_t*)); extern __MANGLE__ Namval_t *nv_lastdict __PROTO__((void)); +extern __MANGLE__ Namval_t *nv_mkinttype __PROTO__((char*, size_t, int, const char*, Namdisc_t*)); extern __MANGLE__ void nv_newattr __PROTO__((Namval_t*,unsigned,int)); extern __MANGLE__ Namval_t *nv_open __PROTO__((const char*,Dt_t*,int)); extern __MANGLE__ void nv_putval __PROTO__((Namval_t*,const char*,int)); extern __MANGLE__ void nv_putv __PROTO__((Namval_t*,const char*,int,Namfun_t*)); extern __MANGLE__ int nv_scan __PROTO__((Dt_t*,void(*)(Namval_t*,__V_*),__V_*,int,int)); -extern __MANGLE__ Namval_t *nv_scoped __PROTO__((Namval_t*)); extern __MANGLE__ char *nv_setdisc __PROTO__((Namval_t*,const char*,Namval_t*,Namfun_t*)); extern __MANGLE__ void nv_setref __PROTO__((Namval_t*, Dt_t*,int)); extern __MANGLE__ int nv_settype __PROTO__((Namval_t*, Namval_t*, int)); @@ -287,9 +287,9 @@ extern __MANGLE__ Namfun_t *nv_disc __PROTO__((Namval_t*,Namfun_t*,int)); extern __MANGLE__ void nv_unset __PROTO__((Namval_t*)); extern __MANGLE__ Namval_t *nv_search __PROTO__((const char *, Dt_t*, int)); -extern __MANGLE__ void nv_unscope __PROTO__((void)); extern __MANGLE__ char *nv_name __PROTO__((Namval_t*)); extern __MANGLE__ Namval_t *nv_type __PROTO__((Namval_t*)); +extern __MANGLE__ void nv_addtype __PROTO__((Namval_t*,const char*, Optdisc_t*, size_t)); extern __MANGLE__ const Namdisc_t *nv_discfun __PROTO__((int)); #ifdef _DLL Index: src/lib/libshell/sparcv9/include/ast/history.h =================================================================== --- src/lib/libshell/sparcv9/include/ast/history.h (revision 974) +++ src/lib/libshell/sparcv9/include/ast/history.h (revision 1122) @@ -3,10 +3,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -65,7 +65,7 @@ #define hist_min(hp) ((_Hist=((int)((hp)->histind-(hp)->histsize)))>=0?_Hist:0) #define hist_max(hp) ((int)((hp)->histind)) /* these are the history interface routines */ -extern __MANGLE__ int sh_histinit __PROTO__((void)); +extern __MANGLE__ int sh_histinit __PROTO__((__V_ *)); extern __MANGLE__ void hist_cancel __PROTO__((History_t*)); extern __MANGLE__ void hist_close __PROTO__((History_t*)); extern __MANGLE__ int hist_copy __PROTO__((char*, int, int, int)); Index: src/lib/libshell/sparcv9/include/ast/shell.h =================================================================== --- src/lib/libshell/sparcv9/include/ast/shell.h (revision 974) +++ src/lib/libshell/sparcv9/include/ast/shell.h (revision 1122) @@ -3,10 +3,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -36,7 +36,7 @@ * */ -#include +#include #include #ifdef _SH_PRIVATE # include "name.h" @@ -44,7 +44,7 @@ # include #endif /* _SH_PRIVATE */ -#define SH_VERSION 20060510 +#define SH_VERSION 20071012 #undef NOT_USED #define NOT_USED(x) (&x,1) @@ -57,7 +57,6 @@ Shopt_t; typedef void (*Shinit_f) __PROTO__((int)); -typedef int (*Shbltin_f) __PROTO__((int, char*[], __V_*)); typedef int (*Shwait_f) __PROTO__((int, long, int)); union Shnode_u; @@ -145,6 +144,7 @@ int exitval; /* most recent exit value */ unsigned char trapnote; /* set when trap/signal is pending */ char subshell; /* set for virtual subshell */ + char shcomp; /* set when runing shcomp */ #ifdef _SH_PRIVATE _SH_PRIVATE #endif /* _SH_PRIVATE */ @@ -158,6 +158,8 @@ #define SH_IOCOPROCESS (-2) #define SH_IOHISTFILE (-3) +#include + /* symbolic value for sh_fdnotify */ #define SH_FDCLOSE (-1) @@ -180,6 +182,7 @@ extern __MANGLE__ int sh_funscope __PROTO__((int,char*[],int(*)(__V_*),__V_*,int)); extern __MANGLE__ Sfio_t *sh_iogetiop __PROTO__((int,int)); extern __MANGLE__ int sh_main __PROTO__((int, char*[], void(*)(int))); +extern __MANGLE__ int sh_run __PROTO__((int, char*[])); extern __MANGLE__ void sh_menu __PROTO__((Sfio_t*, int, char*[])); extern __MANGLE__ Namval_t *sh_addbuiltin __PROTO__((const char*, int(*)(int, char*[],__V_*), __V_*)); extern __MANGLE__ char *sh_fmtq __PROTO__((const char*)); Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/locale =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/locale (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/locale (revision 1122) @@ -1,11 +1,12 @@ -/* : : generated from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/features/locale by iffe version 2007-04-04 : : */ +/* : : generated from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/features/locale by iffe version 2008-01-31 : : */ #ifndef _def_locale_ksh93 #define _def_locale_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #define _hdr_locale 1 /* #include ok */ #define _hdr_wchar 1 /* #include ok */ Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/execargs =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/execargs (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/execargs (revision 1122) @@ -1,10 +1,11 @@ -/* : : generated by iffe version 2007-04-04 : : */ +/* : : generated by iffe version 2008-01-31 : : */ #ifndef _def_execargs_ksh93 #define _def_execargs_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #endif Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/sigfeatures =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/sigfeatures (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/sigfeatures (revision 1122) @@ -1,11 +1,12 @@ -/* : : generated from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/features/sigfeatures by iffe version 2007-04-04 : : */ +/* : : generated from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/features/sigfeatures by iffe version 2008-01-31 : : */ #ifndef _def_sigfeatures_ksh93 #define _def_sigfeatures_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #define _lib_sigrelse 1 /* sigrelse() in default lib(s) */ #define _lib_sigprocmask 1 /* sigprocmask() in default lib(s) */ @@ -22,8 +23,8 @@ #endif #ifdef _lib_sigprocmask # define sh_sigaction(s,action) do { sigset_t ss;\ - sigemptyset(&ss);\ - sigaddset(&ss,(s));\ + sigemptyset(&ss); \ + if(s) sigaddset(&ss,(s)); \ sigprocmask(action,&ss,0); \ }while(0) # define sigrelease(s) sh_sigaction(s,SIG_UNBLOCK) Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/setjmp =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/setjmp (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/setjmp (revision 1122) @@ -1,11 +1,12 @@ -/* : : generated from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/features/setjmp by iffe version 2007-04-04 : : */ +/* : : generated from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/features/setjmp by iffe version 2008-01-31 : : */ #ifndef _def_setjmp_ksh93 #define _def_setjmp_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #define _lib_sigsetjmp 1 /* sigsetjmp() in default lib(s) */ #define _lib__setjmp 1 /* _setjmp() in default lib(s) */ Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/rlimits =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/rlimits (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/rlimits (revision 1122) @@ -1,11 +1,12 @@ -/* : : generated from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/features/rlimits by iffe version 2007-04-04 : : */ +/* : : generated from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/features/rlimits by iffe version 2008-01-31 : : */ #ifndef _def_rlimits_ksh93 #define _def_rlimits_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #define _sys_resource 1 /* #include ok */ #define _lib_getrlimit 1 /* getrlimit() in default lib(s) */ Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/ttys =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/ttys (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/ttys (revision 1122) @@ -1,11 +1,12 @@ -/* : : generated from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/features/ttys by iffe version 2007-04-04 : : */ +/* : : generated from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/features/ttys by iffe version 2008-01-31 : : */ #ifndef _def_ttys_ksh93 #define _def_ttys_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #define _hdr_termios 1 /* #include ok */ #define _hdr_termio 1 /* #include ok */ Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/dynamic =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/dynamic (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/dynamic (revision 1122) @@ -1,11 +1,12 @@ -/* : : generated from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/features/dynamic by iffe version 2007-04-04 : : */ +/* : : generated from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/features/dynamic by iffe version 2008-01-31 : : */ #ifndef _def_dynamic_ksh93 #define _def_dynamic_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #define _hdr_dlfcn 1 /* #include ok */ #define _sys_dl 1 /* #include ok */ Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/cmds =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/cmds (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/cmds (revision 1122) @@ -1,11 +1,12 @@ -/* : : generated from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/features/cmds by iffe version 2007-04-04 : : */ +/* : : generated from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/features/cmds by iffe version 2008-01-31 : : */ #ifndef _def_cmds_ksh93 #define _def_cmds_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #define _cmd_newgrp 1 /* newgrp in ?(/usr)/(bin|etc|ucb) */ #define _bin_newgrp 1 /* /bin/newgrp found */ Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/poll =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/poll (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/poll (revision 1122) @@ -1,6 +1,6 @@ /* : : generated by proto : : */ -/* : : generated from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/features/poll by iffe version 2007-04-04 : : */ +/* : : generated from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/features/poll by iffe version 2008-01-31 : : */ #ifndef _def_poll_ksh93 #if !defined(__PROTO__) # if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus) @@ -62,10 +62,11 @@ #define _def_poll_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #define _hdr_poll 1 /* #include ok */ #define _hdr_netinet_in 1 /* #include ok */ Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/externs =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/externs (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/externs (revision 1122) @@ -1,6 +1,6 @@ /* : : generated by proto : : */ -/* : : generated from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/features/externs by iffe version 2007-04-04 : : */ +/* : : generated from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/features/externs by iffe version 2008-01-31 : : */ #ifndef _def_externs_ksh93 #if !defined(__PROTO__) @@ -63,10 +63,11 @@ #define _def_externs_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #define _hdr_exec_attr 1 /* #include ok */ #define _hdr_math 1 /* #include ok */ @@ -78,4 +79,6 @@ #define _lib_fork 1 /* fork() in default lib(s) */ #define _lib_spawnveg 1 /* spawnveg() in default lib(s) */ #define _lib_fchdir 1 /* fchdir() in default lib(s) */ +#define _sys_mman 1 /* #include ok */ +#define _lib_memcntl 1 /* memcntl() in default lib(s) */ #endif Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/math =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/math (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/math (revision 1122) @@ -1,6 +1,6 @@ /* : : generated by proto : : */ -/* : : generated from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/features/math.sh by iffe version 2007-04-04 : : */ +/* : : generated from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/features/math.sh by iffe version 2008-01-31 : : */ #ifndef _def_math_ksh93 #if !defined(__PROTO__) # if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus) @@ -62,14 +62,15 @@ #define _def_math_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ -/* : : generated by iffe from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/data/math.tab : : */ +/* : : generated by iffe from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/data/math.tab : : */ typedef Sfdouble_t (*Math_f) __PROTO__((Sfdouble_t,...)); @@ -104,6 +105,7 @@ "\002atan2", (Math_f)atan2l, "\001atanh", (Math_f)atanhl, "\001cbrt", (Math_f)cbrtl, + "\001ceil", (Math_f)ceill, "\002copysign", (Math_f)copysignl, "\001cos", (Math_f)cosl, "\001cosh", (Math_f)coshl, Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/acct =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/acct (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/acct (revision 1122) @@ -1,11 +1,12 @@ -/* : : generated by iffe version 2007-04-04 : : */ +/* : : generated by iffe version 2008-01-31 : : */ #ifndef _def_acct_ksh93 #define _def_acct_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #define _lib_acct 1 /* acct() in default lib(s) */ #define _sys_acct 1 /* #include ok */ Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/options =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/options (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/options (revision 1122) @@ -1,11 +1,12 @@ -/* : : generated from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/features/options by iffe version 2007-04-04 : : */ +/* : : generated from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/features/options by iffe version 2008-01-31 : : */ #ifndef _def_options_ksh93 #define _def_options_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #define SHELLMAGIC 1 #ifndef SHOPT_DEVFD Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/pstat =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/pstat (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/pstat (revision 1122) @@ -1,10 +1,11 @@ -/* : : generated by iffe version 2007-04-04 : : */ +/* : : generated by iffe version 2008-01-31 : : */ #ifndef _def_pstat_ksh93 #define _def_pstat_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #endif Index: src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/time =================================================================== --- src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/time (revision 974) +++ src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/time (revision 1122) @@ -1,11 +1,12 @@ -/* : : generated from /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/src/cmd/ksh93/features/time by iffe version 2007-04-04 : : */ +/* : : generated from /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/src/cmd/ksh93/features/time by iffe version 2008-01-31 : : */ #ifndef _def_time_ksh93 #define _def_time_ksh93 1 #define _sys_types 1 /* #include ok */ -#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ -#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ +#define _LIB_dll 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libdll.a is a library */ +#define _LIB_ast 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libast.a is a library */ #define _LIB_m 1 /* -lm is a library */ -#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20070418/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_cmd 1 /* /home/gisburn/ksh93/ast_ksh_20080614/build_sparc_64bit/arch/sol11.sun4/lib/libcmd.a is a library */ +#define _LIB_md 1 /* -lmd is a library */ #define _LIB_nsl 1 /* -lnsl is a library */ #define _hdr_utime 1 /* #include ok */ #define _lib_gettimeofday 1 /* gettimeofday() in default lib(s) */ Index: src/lib/libshell/sparcv9/Makefile =================================================================== --- src/lib/libshell/sparcv9/Makefile (revision 974) +++ src/lib/libshell/sparcv9/Makefile (revision 1122) @@ -19,13 +19,17 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)Makefile 1.1 07/07/10 SMI" +# ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../Makefile.lib.64 +# Use -KPIC since libshell is too big for -Kpic on 64bit +# (and on 32bit it is close to the barrier) +sparcv9_C_PICFLAGS = $(C_BIGPICFLAGS) + install: all $(ROOTLIBS64) $(ROOTLINKS64) Index: src/lib/libshell/common/RELEASE =================================================================== --- src/lib/libshell/common/RELEASE (revision 974) +++ src/lib/libshell/common/RELEASE (revision 1122) @@ -1,4 +1,314 @@ -07-04-18 --- Release ksh93s+ --- +08-06-14 --- Release ksh93t- --- +08-06-14 A bug that could effect the drawing of the screen from multiline + emacs or gmacs mode when walking up the history file has been fixed. +08-06-13 A bug in which a compound variable defined in a subshell could + have side effects into the parent shell has been fixed. +08-06-13 A number of bugs related to using .sh.level to set the stack from + for DEBUG traps have been fixed. +08-06-13 The .sh.lineno variable has been added. When .sh.level is changed + inside a DEBUG trap, the .sh.lineno contains the calling line number + for the specified stack frame. +08-06-13 The .sh.level variable has been documented and now works. +08-06-11 The -C option has been added to read for reading compound command + definitions from a file. +08-06-11 The . command is now permitted inside a compound command definition. + The dot script can contain declaration commands and dot commands. +08-06-09 Add -C option to typeset so that typeset -C foo, is equivalent + to foo=(). +08-06-09 Added -n warning message for typeset option orderings that are valid + with ksh88 but not valid with ksh93, for example Lx5. +08-06-09 A bug in which the return value for an assignment command containing + a command substitution with that failed was zero when the assignment + contained redirections has been fixed. +08-06-09 A bug in the quoting of $ inside a ERE pattern ~(E)(pattern) + has been fixed. +08-06-06 A bug when processing `` command substitution with the character + sequence \$' has been fixed. +08-06-02 When defining a type, the typeset -r attribute causes this field + to be required to be specified for each instance of the type and + does not allow a default value. +08-06-02 Several bugs in which compound variables were modified by + subshells have been fixed. +08-05-22 The ceil function has been added to the math functions. +08-05-21 A bug in which a name reference defined in a function and passed + as an argument to another function could cause an incorrect binding. +08-05-21 A bug in freeing compound variables that are local to functions + has been fixed. +08-05-19 The array expansions ${array[sub1..sub2]} and ${!array[sub1..sub2]} + to expand to the value (or subscripts) for array between sub1 and + sub2 inclusive. For associative arrays, the range is based on + location in the POSIX locale. The .. must be explicit and cannot + result from an expansion. +08-05-15 The trap on SIGCLD is no longer triggered by the completion of + the foreground job as with ksh88. +08-05-14 A bug in the implementation of the editing feature added on + 07-09-19 in emacs mode has been fixed. +08-05-12 A bug in processing the test built-in with parenthesis has been + fixed. +08-05-12 The unset built-in now returns non-zero when deleting an array + subscript that is not set. +08-05-08 Changing the value of HISTFILE or HISTSIZE will cause the old + history file to be close and reopened with the new name or size. +08-05-08 When FPATH is changed functions that were found via a path search + will be searched for again. +08-05-08 A parser bug in which reserved words and labels were recognized + inside compound indexed array assignment after a new-line has + been fixed. +08-05-07 A bug in getopts when handling numerical option arguments has + been fixed. +08-05-07 The typeset -S option was added for variables outside type + definitions to provide a storage class similar to C static + inside a function defined with function name. When outside + type definitions and outside a function, the -S option cause + the specified variable so be unset before the assignment and + before the remaining attributes are supplied. +08-05-07 A bug that affected the cursor movement in multiline mode when + a character was deleted from near the beginning of the any + line other than the first. +08-05-01 In multiline edit mode, the refresh operation will now clear + the remaining portion of the last line. +08-05-01 A bug in computing prompt widths for the edit modes for prompts + with multibyte characters has been fixed. +08-05-01 A bug in the multiline edit mode which could cause the current + line to be displayed incorrectly when moving backwards from third + or higher line to the previous line has been fixed. +08-05-01 A bug in which options set in functions declared with the function + name syntax were carried across into functions invoked by these + functions has been fixed. +08-04-30 A bug which could cause a coprocess to hang when the read end + is a builtin command has been fixed. +08-04-30 The emacs and vi editors have been modified to handle window + change commands as soon as they happen rather than waiting for + the next command. +08-04-28 A bug in which ${!x} did not expand to x when x was unset has been + fixed. +08-04-27 A bug in which the assignment x=(typeset -a foo=([0]=abc)) created + x.foo as an associative array has been fixed. +08-04-25 A bug in which $# did not report correctly when there were more + than 32K positional parameters has been fixed. +08-04-04 Choose the name _ as the sub-variable that holds type or instance + specific data used by discipline functions. +08-03-27 A bug in which the terminal group was not given back to the parent + shell when the last part of a pipeline was handled by the parent shell + and the other parts of the pipeline complete has been fixed. + The symtom was that the pipeline became uninterruptable. +08-03-25 A bug in restricted mode introduced in ksh93s that caused scripts + that did not use #! to executed in restriected mode has been fixed. +08-03-25 A bug in which the pipefail option did not work for a pipeline + within a pipeline has been fixed. +08-03-24 A bug in which OPTIND was not set correctly in subshells has + been fixed. +08-03-24 A bug which could cause a memory exception when a compound variable + containing an indexed array with only element 0 defined was expanded. +08-03-20 A bug in which ${!var[sub].*} was treated as an error has been fixed. +08-03-20 Associative array assignments of the form ([name]=value ...) + now allow ; as well as space tab and new line to separate elements. +08-03-18 A buffering problem in which standard error was sometimes + not flushed before sleep has been fixed. +08-03-17 A bug in which a signal sent to $$ while in a subshell would be + sent to the subshell rather than the parent has been fixed. +08-03-17 --default option added to set(1) to handle set +o POSIX semantics. + set --state added as a long name alias for set +o. +08-03-14 A bug in which using monitor mode from within a script could + cause the terminal group to change has been fixed. +08-03-10 The new ${...} command substitution will treat the trailing } + as a reserved word even if it is not at the beginning of a command, + for example, ${ date }. +08-03-10 If the name of the ENV begins with /./ or ././ then the + /etc/ksh.kshrc file will not be executed on systems that support + this interactive initialization file. +08-03-07 A bug in which ksh -i did not run the ENV file has been fixed. +08-03-07 A bug in which ulimit did not always produce the same output as + ulimit -fS has been fixed. +08-03-04 A bug in multiline mode in emacs and vi mode which could cause the + cursor to be on the wrong line when interrupt was hit has been fixed. +08-03-03 The change made in ksh93s+ on 07-06-18 in which braces became + optional for ${a[i]} inside [[...]] was restored in the case + where the argument can be a pattern. +08-03-03 A bug in which creating a name reference to an associative array + instance would fail when the subscript contained characters [ or + ] has been fixed. +08-02-29 The redirection operator >; has been added which for non-special + files, generates the output in a temporary file and writes the + specified file only of the command has completed successfully. +08-02-15 A bug in ${var/pattern/string} for patterns of the form ?(*) and +(*) + has bee fixed. +08-02-07 A bug in which test \( ! -e \) produced an error has been fixed. +08-02-14 The typeset -a option can now optionally be followed by the name + of an enumerication type which allows subscripts to be enumerations. +08-02-14 The enum builtin which creates enumeration types has been added. +08-02-12 The backoff logic when there are no more processes has been fixed. +08-02-07 The -X option has been added to typeset. The -X option creates + a double precision number that gets displayed using the C99 %a + format. It can be used along with -l for long double. +08-01-31 The -T option to typeset has been added for creating typed + variables. Also the -h and -S options have been added to + typeset that are only applicable when defining a type. +08-01-31 The prefix expansion operator @ has been added. ${@name} + expandes to the type of name or yields the attributes. +07-11-15 A bug in the macro expander for multibyte characters in which + part of the character contains a file pattern byte has been fixed. +07-10-03 A bug in which : was not allowed as part of an alias name has been + fixed. +07-09-26 A bug in which appending a compound variable to a compound variable + or to an index array didn't work has been fixed. +07-09-19 In both emacs and vi edit mode, the escape sequence \E[A (usually + cursor up, when the cursor is at the end of the line will fetch + the most recent line starting with the current line. +07-09-18 The value of ${!var} was correct when var was a reference to an + array instance. +07-09-18 The value of ${!var[sub]} was not expanding to var[sub] and this + was fixed. It also fixed ${name} where name is a name reference + to var[sub]. +07-09-18 It is now legal to create a name reference without an initialization. + It will be bound to a variable on the first assignment. +07-08-30 A discipline function can be invoked as ${x.foo} and is equivalent + to ${ x.foo;} and can be invoked as x.foo inside ((...)). +07-07-09 A bug in which typeset -a did not list indexed arrays has been + fixed. +07-07-03 The command substitution ${ command;} has been added. It behaves + like $(command) except that command is executed in the current + shell environment. The ${ must be followed by a blank or an + operator. + +08-04-17 --- Release ksh93s+ --- +08-04-17 A bug in which umask was not being restored correctly after a + subshell has been fixed. +08-04-15 A bug in which sending a STOP signal to a job control shell started + from within a shell function caused cause the invoking shell to + terminate has been fixed. +08-04-11 A bug which caused $(exec > /dev/null) to go into an infinite loop + has been fixed. +08-03-27 A bug in which typeset -LZ was being treated as -RZ has been fixed. +08-03-06 A bug with ksh -P on systems that support the the profile shell, + in which it would exit after running a non-builtin has been fixed. +08-01-31 A bug in which command substitution inside ((...)) could cause + syntax errors or lead to core dumps has been fixed. +08-01-17 A bug in which discipline functions could be deleted when invoked + from a subshell has been fixed. +08-01-17 A bug in which a command substitution consisting only of + assignments was treated as a noop has been fixed. +08-01-17 A bug in which discipline functions invoked from withing a + compound assignment could fail has been fixed. +08-01-16 Incomplete arithmetic assigments, for example ((x += )), now + generate an error message. +08-01-16 A bug in which a set discipline defined for a variable before + an array assignment could cause a core dump has been fixed. +08-01-03 A bug in on some systems in which exit status 0 is incorrectly + returned by a process that catches the SIGCONT signal is stopped + and then continued. +07-12-13 A race condition in which a program that has been stopped and then + continued could loose the exit status has been fixed. +07-12-12 Code to check for file system out of space write errors for all + writes has been added. +07-12-11 A bug in the macro expander for multibyte characters in which + part of the character contains a file pattern byte has been fixed. +07-12-06 A bug in the emacs edit mode when multiline was set that output + a backspace before the newline to the screen has been fixed. +07-12-04 A bug in which using TAB after a variable name listing expansion + in the edit modes would cause the $ to disappear has been fixed. +07-11-28 A bug in which setting IFS to readonly could cause a subsequent + command substitution to fail has been fixed. +07-11-27 A work around for a gcc 4.* C99 "feature" that could cause a job + control shell to go into an infinite loop by adding the volatile + attribute to some auto vars in functions that call setjmp(). +07-11-27 A bug in which the shell could read ahead on a pipe causing the + standard input to be incorrectly positioned has been fixed. +07-11-27 A bug in which compound variable UTF-8 multibyte values were not + expanded or traced properly has been fixed. +07-11-21 A bug where an unbalanced '[' in a command argument was not treated + properly has been fixed. +07-11-15 A bug in which compatibility mode (no long option names) getopts(1) + incorrectly set the value of OPTARG for flag options has been fixed. +07-11-15 A bug in which "hash -- name" treated "--" as an invalid name operand + has been fixed. +07-11-15 typeset now handles "-t -- [-r] [--]" for s5r4 hash(1) compatibility. +07-11-15 A bug in which the umask builtin mis-handled symbolic mode operands + has been fixed. +07-11-15 Bugs in which shell arithmetic and the printf builtin mis-handled the + signs of { -NaN -Inf -0.0 } have been fixed. +07-11-15 The full { SIGRTMIN SIGRTMIN+1 ... SIGRTMAX-1 SIGRTMAX } range + of signals, determined at runtime, are now supported. +07-11-15 A bug in which creating an index array with only subscript 0 created + only a simple variable has been fixed. +07-11-14 A bug in which appending to an indexed array using the form + name+=([sub]=value) could cause the array to become an associative + array has been fixed. +07-11-14 A bug in which typeset without arguments could coredump if a + variable is declared as in indexed array and has no elements has + been fixed. +07-11-14 A bug in which creating a local SECONDS variable with typeset in + a function could corrupt memory has been fixed. +07-11-14 A bug which could cause a core dump when a script invoked by name + from a function used compound variables has been fixed. +07-11-05 A bug in which printf %d "'AB" did not diagnose unconverted characters + has been fixed. +07-11-05 printf %g "'A" support added for all floating point formats. +07-11-01 A bug in which typeset -f fun did not display the function definition + when invoked in a subshell has been fixed. +07-10-29 The sleep builtin was fixed so that all floating point constants + are valid operands. +07-10-10 A bug in which the locale was not being restored after + LANG=value command has been fixed. +07-09-20 A bug in which a nameref to a compound variable that was local + to the calling function would not expand correctly when displaying + is value has been fixed. +07-09-19 A bug which cause cause a core dump if .sh.edchar returned + 80 characters or more from a keyboard trap has been fixed. +07-09-14 A bug in which could cause a core dump when more than 8 file + descriptors were in use has been fixed. +07-09-10 A bug in which creating a name reference to an instance of + an array when the array name is itself a reference has been fixed. +07-09-10 The file completion code has been modified so that after an = in + any word, each : will be considered a path delimiter. +07-09-06 A bug in which subprocess cleanup could corrupt the malloc() heap + has been fixed. +07-08-26 A bug in which a name reference to an associatve array instance + could cause the subscript to be evaluated as an arithmetic expression + has been fixed. +07-08-22 A bug in which the value of an array instance was of a compound + variable was not expanded correctly has been fixed. +07-08-14 A bug which could cause a core dump when a compound assignment was + made to a compound variable element with a typeset -a attribute + has been fixed. +07-08-08 A bug in which a trap ignored in a subshell caused it to be + ignored by the parent has been fixed. +07-08-07 A bug in which the set command would generated erroneous output + for a variable with the -RZ attribute if the variable name had been + passed to a function has been fixed. +07-08-02 A bug in which read x[1] could core dump has been fixed. +07-08-02 A second bug in which after read x[sub] into an associative array + of an element that hasn't been assigned could lead to a core dump + has been fixed. +07-07-31 A bug in which a pipeline that completed correctly could have + an exit status of 127 when pipefail was enabled has been fixed. +07-07-09 The SHOPT_AUDIT compile option has been added for keyboard logging. +07-06-25 In vi insert mode, ksh no longer emits a backspace character + before the carraige return when the newline is entered. +07-06-25 A bug in which pipefail would cause a command to return 0 + when the pipeline was the last command and the failure happened + on a component other than the last has been fixed. +07-06-25 A bug in the expansion of ${var/pattern/rep} when pattern or rep + contained a left parenthesis in single quotes has been fixed. +07-06-18 The braces for a subscripted variable with ${var[sub]} are now + optional when inside [[...]], ((...)) or as a subscript. +07-05-28 A bug in brace expansion in which single and double quotes did + not treat the comma as a literal character has been fixed. +07-05-24 The -p option of whence now disables -v. +07-05-23 Several bug fixes in compound variables and arrays of arrays + have been made. +07-05-15 A bug in which the %B format of printf was affected by the + locale has been fixed. +07-05-14 A bug in which \ was not removed in the replacement pattern with + ${var/pattern/rep} when it was not followed by \ or a digit has + been fixed. +07-05-10 A bug in which ksh -R file core dumped if no script was specified + has been fixed. it not displays an error message. +07-05-07 Added additional Solaris signals to signal table. +07-04-30 A bug in which a pipeline with command substitution inside a + function could cause a pipeline that invokes this function to + hang when the pipefail option is on has been fixed. +07-04-30 Added -q to whence. 07-04-18 A small memory leak with each redirection of a non-builtin has been fixed. 07-03-08 A bug in which set +o output command line options has been fixed. Index: src/lib/libshell/common/include/builtins.h =================================================================== --- src/lib/libshell/common/include/builtins.h (revision 974) +++ src/lib/libshell/common/include/builtins.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -39,8 +39,9 @@ #define SYSBRACKET (sh.bltin_cmds+11) #define SYSLET (sh.bltin_cmds+12) #define SYSEXPORT (sh.bltin_cmds+13) +#define SYSDOT (sh.bltin_cmds+14) #if SHOPT_BASH -# define SYSLOCAL (sh.bltin_cmds+14) +# define SYSLOCAL (sh.bltin_cmds+15) #else # define SYSLOCAL 0 #endif @@ -54,6 +55,7 @@ extern int b_alias(int, char*[],void*); extern int b_break(int, char*[],void*); extern int b_dot_cmd(int, char*[],void*); +extern int b_enum(int, char*[],void*); extern int b_exec(int, char*[],void*); extern int b_eval(int, char*[],void*); extern int b_return(int, char*[],void*); @@ -123,7 +125,6 @@ extern const char e_eneedsarg[]; extern const char e_toodeep[]; extern const char e_badname[]; -extern const char e_badwrite[]; extern const char e_badsyntax[]; #ifdef _cmd_universe extern const char e_nouniverse[]; @@ -131,7 +132,6 @@ extern const char e_histopen[]; extern const char e_condition[]; extern const char e_badrange[]; -extern const char e_numeric[]; extern const char e_trap[]; extern const char e_direct[]; extern const char e_defedit[]; Index: src/lib/libshell/common/include/path.h =================================================================== --- src/lib/libshell/common/include/path.h (revision 974) +++ src/lib/libshell/common/include/path.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -90,7 +90,7 @@ #undef extern extern char *path_pwd(int); extern Pathcomp_t *path_nextcomp(Pathcomp_t*,const char*,Pathcomp_t*); -extern int path_search(const char*,Pathcomp_t*,int); +extern int path_search(const char*,Pathcomp_t**,int); extern char *path_relative(const char*); extern int path_complete(const char*, const char*,struct argnod**); #if SHOPT_BRACEPAT Index: src/lib/libshell/common/include/jobs.h =================================================================== --- src/lib/libshell/common/include/jobs.h (revision 974) +++ src/lib/libshell/common/include/jobs.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -64,6 +64,7 @@ pid_t p_fgrp; /* process group when stopped */ short p_job; /* job number of process */ unsigned short p_exit; /* exit value or signal number */ + unsigned short p_exitmin; /* minimum exit value for xargs */ unsigned short p_flag; /* flags - see below */ int p_env; /* subshell environment number */ #ifdef JOBS @@ -105,8 +106,19 @@ #ifdef JOBS +#if !_std_malloc +#include +#if VMALLOC_VERSION >= 20070911L +#define vmbusy() (vmstat(0,0)!=0) +#endif +#endif +#ifndef vmbusy +#define vmbusy() 0 +#endif + + #define job_lock() (job.in_critical++) -#define job_unlock() do{if(!--job.in_critical&&job.savesig)job_reap(job.savesig);}while(0) +#define job_unlock() do{if(!--job.in_critical&&job.savesig&&!vmbusy())job_reap(job.savesig);}while(0) extern const char e_jobusage[]; extern const char e_done[]; @@ -137,21 +149,21 @@ extern void job_bwait(char**); extern int job_walk(Sfio_t*,int(*)(struct process*,int),int,char*[]); extern int job_kill(struct process*,int); -extern void job_wait(pid_t); +extern int job_wait(pid_t); extern int job_post(pid_t,pid_t); extern void *job_subsave(void); extern void job_subrestore(void*); #ifdef JOBS - extern void job_init(int); - extern int job_close(void); + extern void job_init(Shell_t*,int); + extern int job_close(Shell_t*); extern int job_list(struct process*,int); extern int job_terminate(struct process*,int); extern int job_switch(struct process*,int); extern void job_fork(pid_t); extern int job_reap(int); #else -# define job_init(flag) -# define job_close() (0) +# define job_init(s,flag) +# define job_close(s) (0) # define job_fork(p) #endif /* JOBS */ Index: src/lib/libshell/common/include/nval.h =================================================================== --- src/lib/libshell/common/include/nval.h (revision 974) +++ src/lib/libshell/common/include/nval.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -31,6 +31,7 @@ #include #include +#include /* for compatibility with old hash library */ #define Hashtab_t Dt_t @@ -44,8 +45,7 @@ typedef struct Namdisc Namdisc_t; typedef struct Nambfun Nambfun_t; typedef struct Namarray Namarr_t; -typedef struct Nambltin Nambltin_t; -typedef struct Namtype Namtype_t; +typedef struct Namdecl Namdecl_t; /* * This defines the template for nodes that have their own assignment @@ -64,13 +64,14 @@ Namval_t *(*nextf)(Namval_t*, Dt_t*, Namfun_t*); Namval_t *(*typef)(Namval_t*, Namfun_t*); int (*readf)(Namval_t*, Sfio_t*, int, Namfun_t*); + int (*writef)(Namval_t*, Sfio_t*, int, Namfun_t*); }; struct Namfun { const Namdisc_t *disc; char nofree; - char funs; + unsigned char subshell; unsigned short dsize; Namfun_t *next; char *last; @@ -92,22 +93,14 @@ long nelem; /* number of elements */ void *(*fun)(Namval_t*,const char*,int); /* associative arrays */ Namval_t *parent; /* for multi-dimensional */ + Dt_t *table; /* for subscripts */ + void *scope; /* non-zerp when scoped */ }; -/* Passed as third argument to a builtin when NV_BLTINOPT is set on node */ -struct Nambltin +/* The context pointer for declaration command */ +struct Namdecl { - void *shp; - Namval_t *np; - void *ptr; - void *data; - int flags; -}; - -struct Namtype -{ - void *shp; - Namval_t *np; + Namval_t *tp; /* point to type */ const char *optstring; void *optinfof; }; @@ -132,6 +125,7 @@ }; #define NV_CLASS ".sh.type" +#define NV_DATA "_" /* special class or instance variable */ #define NV_MINSZ (sizeof(struct Namval)-sizeof(Dtlink_t)-sizeof(char*)) #define nv_namptr(p,n) ((Namval_t*)((char*)(p)+(n)*NV_MINSZ-sizeof(Dtlink_t))) @@ -163,8 +157,9 @@ #define NV_SHORT (NV_RJUST) /* when integers are not long */ #define NV_LONG (NV_UTOL) /* for long long and long double */ #define NV_UNSIGN (NV_LTOU) /* for unsigned quantities */ -#define NV_DOUBLE (NV_ZFILL) /* for floating point */ +#define NV_DOUBLE (NV_INTEGER|NV_ZFILL) /* for floating point */ #define NV_EXPNOTE (NV_LJUST) /* for scientific notation */ +#define NV_HEXFLOAT (NV_LTOU) /* for C99 base16 float notation */ /* options for nv_open */ @@ -185,19 +180,21 @@ #define NV_NODISC NV_IDENT /* ignore disciplines */ #define NV_FUNCT NV_IDENT /* option for nv_create */ -#define NV_BLTINOPT NV_ZFILL /* save state for optimization*/ +#define NV_BLTINOPT NV_ZFILL /* mark builtins in libcmd */ #define NV_PUBLIC (~(NV_NOSCOPE|NV_ASSIGN|NV_IDENT|NV_VARNAME|NV_NOADD)) /* numeric types */ +#define NV_INT16P (NV_LJUST|NV_SHORT|NV_INTEGER) #define NV_INT16 (NV_SHORT|NV_INTEGER) #define NV_UINT16 (NV_UNSIGN|NV_SHORT|NV_INTEGER) +#define NV_UINT16P (NV_LJUSTNV_UNSIGN|NV_SHORT|NV_INTEGER) #define NV_INT32 (NV_INTEGER) #define NV_UNT32 (NV_UNSIGN|NV_INTEGER) #define NV_INT64 (NV_LONG|NV_INTEGER) #define NV_UINT64 (NV_UNSIGN|NV_LONG|NV_INTEGER) -#define NV_FLOAT (NV_SHORT|NV_DOUBLE|NV_INTEGER) -#define NV_LDOUBLE (NV_LONG|NV_DOUBLE|NV_INTEGER) +#define NV_FLOAT (NV_SHORT|NV_DOUBLE) +#define NV_LDOUBLE (NV_LONG|NV_DOUBLE) /* name-value pair macros */ #define nv_isattr(np,f) ((np)->nvflag & (f)) @@ -213,6 +210,7 @@ #define NV_ADELETE 5 /* delete current subscript */ #define NV_AADD 6 /* add subscript if not found */ #define NV_ACURRENT 7 /* return current subscript Namval_t* */ +#define NV_ASETSUB 8 /* set current subscript */ /* The following are for nv_disc */ #define NV_FIRST 1 @@ -239,7 +237,9 @@ # endif /* _BLD_shell */ #endif /* _DLL */ /* prototype for array interface*/ +extern Namarr_t *nv_arrayptr(Namval_t*); extern Namarr_t *nv_setarray(Namval_t*,void*(*)(Namval_t*,const char*,int)); +extern int nv_arraynsub(Namarr_t*); extern void *nv_associative(Namval_t*,const char*,int); extern int nv_aindex(Namval_t*); extern int nv_nextsub(Namval_t*); @@ -261,12 +261,12 @@ extern Namfun_t *nv_hasdisc(Namval_t*, const Namdisc_t*); extern int nv_isnull(Namval_t*); extern Namval_t *nv_lastdict(void); +extern Namval_t *nv_mkinttype(char*, size_t, int, const char*, Namdisc_t*); extern void nv_newattr(Namval_t*,unsigned,int); extern Namval_t *nv_open(const char*,Dt_t*,int); extern void nv_putval(Namval_t*,const char*,int); extern void nv_putv(Namval_t*,const char*,int,Namfun_t*); extern int nv_scan(Dt_t*,void(*)(Namval_t*,void*),void*,int,int); -extern Namval_t *nv_scoped(Namval_t*); extern char *nv_setdisc(Namval_t*,const char*,Namval_t*,Namfun_t*); extern void nv_setref(Namval_t*, Dt_t*,int); extern int nv_settype(Namval_t*, Namval_t*, int); @@ -276,9 +276,9 @@ extern Namfun_t *nv_disc(Namval_t*,Namfun_t*,int); extern void nv_unset(Namval_t*); extern Namval_t *nv_search(const char *, Dt_t*, int); -extern void nv_unscope(void); extern char *nv_name(Namval_t*); extern Namval_t *nv_type(Namval_t*); +extern void nv_addtype(Namval_t*,const char*, Optdisc_t*, size_t); extern const Namdisc_t *nv_discfun(int); #ifdef _DLL Index: src/lib/libshell/common/include/history.h =================================================================== --- src/lib/libshell/common/include/history.h (revision 974) +++ src/lib/libshell/common/include/history.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -56,7 +56,7 @@ #define hist_min(hp) ((_Hist=((int)((hp)->histind-(hp)->histsize)))>=0?_Hist:0) #define hist_max(hp) ((int)((hp)->histind)) /* these are the history interface routines */ -extern int sh_histinit(void); +extern int sh_histinit(void *); extern void hist_cancel(History_t*); extern void hist_close(History_t*); extern int hist_copy(char*, int, int, int); Index: src/lib/libshell/common/include/shnodes.h =================================================================== --- src/lib/libshell/common/include/shnodes.h (revision 974) +++ src/lib/libshell/common/include/shnodes.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -40,6 +40,7 @@ #define FSHOWME (0400< redirection operator */ -#define IOAPP 0x80 /* >> redirection operator */ -#define IODOC 0x100 /* << redirection operator */ -#define IOMOV 0x200 /* <& or >& operators */ -#define IOCLOB 0x400 /* noclobber bit */ -#define IORDW 0x800 /* <> redirection operator */ -#define IORAW 0x1000 /* no expansion needed for filename */ -#define IOSTRG 0x2000 /* here-document stored as incore string */ -#define IOSTRIP 0x4000 /* strip leading tabs for here-document */ -#define IOQUOTE 0x8000 /* here-document delimiter was quoted */ -#define IOVNM 0x10000 /* iovname field is non-zero */ -#define IOLSEEK 0x20000 /* seek operators <# or ># */ -#define IOARITH 0x40000 /* arithmetic seek <# ((expr)) */ -#define IOCOPY IOCLOB /* copy skipped lines onto standard output */ +#define IOUFD 0x3f /* file descriptor number mask */ +#define IOPUT 0x40 /* > redirection operator */ +#define IOAPP 0x80 /* >> redirection operator */ +#define IODOC 0x100 /* << redirection operator */ +#define IOMOV 0x200 /* <& or >& operators */ +#define IOCLOB 0x400 /* noclobber bit */ +#define IORDW 0x800 /* <> redirection operator */ +#define IORAW 0x1000 /* no expansion needed for filename */ +#define IOSTRG 0x2000 /* here-document stored as incore string */ +#define IOSTRIP 0x4000 /* strip leading tabs for here-document */ +#define IOQUOTE 0x8000 /* here-document delimiter was quoted */ +#define IOVNM 0x10000 /* iovname field is non-zero */ +#define IOLSEEK 0x20000 /* seek operators <# or ># */ +#define IOARITH 0x40000 /* arithmetic seek <# ((expr)) */ +#define IOREWRITE 0x80000 /* arithmetic seek <# ((expr)) */ +#define IOCOPY IOCLOB /* copy skipped lines onto standard output */ union Shnode_u { @@ -205,18 +207,13 @@ struct arithnod ar; }; -extern void sh_freeup(void); +extern void sh_freeup(Shell_t*); extern void sh_funstaks(struct slnod*,int); extern Sfio_t *sh_subshell(Shnode_t*, int, int); #if defined(__EXPORT__) && defined(_BLD_DLL) && defined(_BLD_shell) __EXPORT__ #endif extern int sh_tdump(Sfio_t*, const Shnode_t*); -extern Shnode_t *sh_dolparen(void); -extern Shnode_t *sh_trestore(Sfio_t*); -#if SHOPT_KIA - extern int kiaclose(void); - extern unsigned long kiaentity(const char*,int,int,int,int,unsigned long,int,int,const char*); -#endif /* SHOPT_KIA */ +extern Shnode_t *sh_trestore(Shell_t*, Sfio_t*); #endif /* _SHNODES_H */ Index: src/lib/libshell/common/include/ulimit.h =================================================================== --- src/lib/libshell/common/include/ulimit.h (revision 974) +++ src/lib/libshell/common/include/ulimit.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/include/national.h =================================================================== --- src/lib/libshell/common/include/national.h (revision 974) +++ src/lib/libshell/common/include/national.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/include/shell.h =================================================================== --- src/lib/libshell/common/include/shell.h (revision 974) +++ src/lib/libshell/common/include/shell.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -27,7 +27,7 @@ * */ -#include +#include #include #ifdef _SH_PRIVATE # include "name.h" @@ -35,7 +35,7 @@ # include #endif /* _SH_PRIVATE */ -#define SH_VERSION 20060510 +#define SH_VERSION 20071012 #undef NOT_USED #define NOT_USED(x) (&x,1) @@ -48,7 +48,6 @@ Shopt_t; typedef void (*Shinit_f)(int); -typedef int (*Shbltin_f)(int, char*[], void*); typedef int (*Shwait_f)(int, long, int); union Shnode_u; @@ -136,6 +135,7 @@ int exitval; /* most recent exit value */ unsigned char trapnote; /* set when trap/signal is pending */ char subshell; /* set for virtual subshell */ + char shcomp; /* set when runing shcomp */ #ifdef _SH_PRIVATE _SH_PRIVATE #endif /* _SH_PRIVATE */ @@ -149,6 +149,8 @@ #define SH_IOCOPROCESS (-2) #define SH_IOHISTFILE (-3) +#include + /* symbolic value for sh_fdnotify */ #define SH_FDCLOSE (-1) @@ -170,6 +172,7 @@ extern int sh_funscope(int,char*[],int(*)(void*),void*,int); extern Sfio_t *sh_iogetiop(int,int); extern int sh_main(int, char*[], void(*)(int)); +extern int sh_run(int, char*[]); extern void sh_menu(Sfio_t*, int, char*[]); extern Namval_t *sh_addbuiltin(const char*, int(*)(int, char*[],void*), void*); extern char *sh_fmtq(const char*); Index: src/lib/libshell/common/include/io.h =================================================================== --- src/lib/libshell/common/include/io.h (revision 974) +++ src/lib/libshell/common/include/io.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -65,19 +65,19 @@ #define sh_inuse(f2) (sh.fdptrs[f2]) -extern int sh_iocheckfd(int); -extern void sh_ioinit(void); +extern int sh_iocheckfd(Shell_t*,int); +extern void sh_ioinit(Shell_t*); extern int sh_iomovefd(int); -extern int sh_iorenumber(int,int); +extern int sh_iorenumber(Shell_t*,int,int); extern void sh_pclose(int[]); -extern void sh_iorestore(int,int); +extern void sh_iorestore(Shell_t*,int,int); #if defined(__EXPORT__) && defined(_BLD_DLL) && defined(_BLD_shell) __EXPORT__ #endif -extern Sfio_t *sh_iostream(int); -extern int sh_redirect(struct ionod*,int); -extern void sh_iosave(int,int); -extern void sh_iounsave(void); +extern Sfio_t *sh_iostream(Shell_t*,int); +extern int sh_redirect(Shell_t*,struct ionod*,int); +extern void sh_iosave(Shell_t *, int,int,char*); +extern void sh_iounsave(Shell_t*); extern int sh_chkopen(const char*); extern int sh_ioaccess(int,int); extern int sh_devtofd(const char*); @@ -98,6 +98,7 @@ extern const char e_notseek[]; extern const char e_noread[]; extern const char e_badseek[]; +extern const char e_badwrite[]; extern const char e_badpattern[]; extern const char e_toomany[]; extern const char e_pipe[]; Index: src/lib/libshell/common/include/variables.h =================================================================== --- src/lib/libshell/common/include/variables.h (revision 974) +++ src/lib/libshell/common/include/variables.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -84,21 +84,22 @@ #define SH_FUNNAMENOD (sh.bltin_nodes+54) #define SH_SUBSHELLNOD (sh.bltin_nodes+55) #define SH_LEVELNOD (sh.bltin_nodes+56) +#define SH_LINENO (sh.bltin_nodes+57) #if SHOPT_FS_3D -# define VPATHNOD (sh.bltin_nodes+57) +# define VPATHNOD (sh.bltin_nodes+58) # define NFS_3D 1 #else # define NFS_3D 0 #endif /* SHOPT_FS_3D */ #if SHOPT_VPIX -# define DOSPATHNOD (sh.bltin_nodes+57+NFS_3D) -# define VPIXNOD (sh.bltin_nodes+58+NFS_3D) +# define DOSPATHNOD (sh.bltin_nodes+58+NFS_3D) +# define VPIXNOD (sh.bltin_nodes+59+NFS_3D) # define NVPIX (NFS_3D+2) #else # define NVPIX NFS_3D #endif /* SHOPT_VPIX */ #ifdef apollo -# define SYSTYPENOD (sh.bltin_nodes+57+NVPIX) +# define SYSTYPENOD (sh.bltin_nodes+58+NVPIX) #endif /* apollo */ #endif /* SH_VALNOD */ Index: src/lib/libshell/common/include/argnod.h =================================================================== --- src/lib/libshell/common/include/argnod.h (revision 974) +++ src/lib/libshell/common/include/argnod.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -69,10 +69,10 @@ struct dolnod { - short dolrefcnt; /* reference count */ - short dolmax; /* size of dolval array */ - short dolnum; /* number of elements */ - short dolbot; /* current first element */ + int dolrefcnt; /* reference count */ + int dolmax; /* size of dolval array */ + int dolnum; /* number of elements */ + int dolbot; /* current first element */ struct dolnod *dolnxt; /* used when list are chained */ char *dolval[1]; /* array of value pointers */ }; @@ -123,17 +123,13 @@ #define ARG_OPTIMIZE 0x200 /* try to optimize */ #define ARG_NOGLOB 0x400 /* no file name expansion */ #define ARG_LET 0x800 /* processing let command arguments */ +#define ARG_ARRAYOK 0x1000 /* $x[sub] ==> ${x[sub]} */ -extern char **sh_argbuild(int*,const struct comnod*,int); extern struct dolnod *sh_argcreate(char*[]); -extern char *sh_argdolminus(void); -extern struct dolnod *sh_argfree(struct dolnod*,int); -extern struct dolnod *sh_argnew(char*[],struct dolnod**); -extern int sh_argopts(int,char*[]); -extern void sh_argreset(struct dolnod*,struct dolnod*); -extern void sh_argset(char*[]); -extern struct dolnod *sh_arguse(void); +extern char *sh_argdolminus(void*); +extern int sh_argopts(int,char*[],void*); + extern const char e_heading[]; extern const char e_off[]; extern const char e_on[]; Index: src/lib/libshell/common/include/fault.h =================================================================== --- src/lib/libshell/common/include/fault.h (revision 974) +++ src/lib/libshell/common/include/fault.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -33,6 +33,7 @@ #include "FEATURE/setjmp" #include "FEATURE/sigfeatures" + #ifndef SIGWINCH # ifdef SIGWIND # define SIGWINCH SIGWIND @@ -63,7 +64,11 @@ #define SH_SIGTSTP 0200 /* tstp signal received */ #define SH_SIGALRM 0200 /* timer alarm received */ #define SH_SIGTERM SH_SIGOFF /* term signal received */ +#define SH_SIGRUNTIME 0400 /* runtime value */ +#define SH_SIGRTMIN 0 /* sh.sigruntime[] index */ +#define SH_SIGRTMAX 1 /* sh.sigruntime[] index */ + /* * These are longjmp values */ @@ -108,11 +113,11 @@ #define sh_popcontext(bp) (sh.jmplist=(bp)->prev, errorpop(&((bp)->err))) extern void sh_fault(int); -extern void sh_done(int); +extern void sh_done(void*,int); extern void sh_chktrap(void); extern void sh_sigclear(int); extern void sh_sigdone(void); -extern void sh_siginit(void); +extern void sh_siginit(void*); extern void sh_sigtrap(int); extern void sh_sigreset(int); extern void sh_timetraps(void); Index: src/lib/libshell/common/include/terminal.h =================================================================== --- src/lib/libshell/common/include/terminal.h (revision 974) +++ src/lib/libshell/common/include/terminal.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/include/lexstates.h =================================================================== --- src/lib/libshell/common/include/lexstates.h (revision 974) +++ src/lib/libshell/common/include/lexstates.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -148,4 +148,5 @@ extern const char e_lexfuture[]; extern const char e_lexzerobyte[]; extern const char e_lexemptyfor[]; +extern const char e_lextypeset[]; #endif Index: src/lib/libshell/common/include/fcin.h =================================================================== --- src/lib/libshell/common/include/fcin.h (revision 974) +++ src/lib/libshell/common/include/fcin.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -36,7 +36,8 @@ unsigned char *fclast; /* pointer to end of input buffer */ unsigned char *fcptr; /* pointer to next input char */ unsigned char fcchar; /* saved character */ - void (*fcfun)(Sfio_t*,const char*,int); /* advance function */ + void (*fcfun)(Sfio_t*,const char*,int,void*); /* advance function */ + void *context; /* context pointer */ int fcleft; /* for multibyte boundary */ Sfoff_t fcoff; /* offset for last read */ } Fcin_t; @@ -54,7 +55,7 @@ extern int fcfill(void); extern int fcfopen(Sfio_t*); extern int fcclose(void); -void fcnotify(void(*)(Sfio_t*,const char*,int)); +void fcnotify(void(*)(Sfio_t*,const char*,int,void*),void*); extern int fcmbstate(const char*,int*,int*); extern Fcin_t _Fcin; /* used by macros */ Index: src/lib/libshell/common/include/test.h =================================================================== --- src/lib/libshell/common/include/test.h (revision 974) +++ src/lib/libshell/common/include/test.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/include/name.h =================================================================== --- src/lib/libshell/common/include/name.h (revision 974) +++ src/lib/libshell/common/include/name.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -43,6 +43,7 @@ int32_t *lp; Sflong_t *llp; /* for long long arithmetic */ int16_t s; + int16_t *sp; double *dp; /* for floating point arithmetic */ Sfdouble_t *ldp; /* for long floating point arithmetic */ struct Namarray *array; /* for array node */ @@ -67,6 +68,7 @@ #define ARRAY_NOCLONE (16L< 255 */ #define BLT_DCL (NV_TAGGED) /* declaration command */ -#define nv_isref(n) (nv_isattr((n),NV_REF)==NV_REF) -#define nv_istable(n) (nv_isattr((n),NV_TABLE|NV_LJUST|NV_RJUST)==NV_TABLE) -#define is_abuiltin(n) (nv_isattr(n,NV_BLTIN)==NV_BLTIN) -#define is_afunction(n) (nv_isattr(n,NV_FUNCTION)==NV_FUNCTION) +#define BLT_NOSFIO (NV_IMPORT) /* doesn't use sfio */ +#define NV_OPTGET (NV_BINARY) /* function calls getopts */ +#define nv_isref(n) (nv_isattr((n),NV_REF|NV_TAGGED|NV_FUNCT)==NV_REF) +#define nv_istable(n) (nv_isattr((n),NV_TABLE|NV_LJUST|NV_RJUST|NV_INTEGER)==NV_TABLE) +#define is_abuiltin(n) (nv_isattr(n,NV_BLTIN|NV_INTEGER)==NV_BLTIN) +#define is_afunction(n) (nv_isattr(n,NV_FUNCTION|NV_REF)==NV_FUNCTION) #define nv_funtree(n) ((n)->nvalue.rp->ptree) #define funptr(n) ((n)->nvalue.bfp) @@ -138,16 +147,13 @@ #define nv_reftree(n) ((n)->nvalue.nrp->root) #define nv_reftable(n) ((n)->nvalue.nrp->table) #define nv_refsub(n) ((n)->nvalue.nrp->sub) -#if SHOPT_OO -# define nv_class(np) (nv_isattr(np,NV_REF|NV_IMPORT)?0:(Namval_t*)((np)->nvenv)) -#endif /* SHOPT_OO */ /* ... etc */ #define nv_setsize(n,s) ((n)->nvsize = (s)) #undef nv_size #define nv_size(np) ((np)->nvsize) -#define nv_isnull(np) (!(np)->nvalue.cp && !(np)->nvfun && !nv_isattr(np,NV_SHORT)) +#define nv_isnull(np) (!(np)->nvalue.cp && !((np)->nvfun && (np)->nvfun->disc) && nv_isattr(np,NV_SHORT|NV_INTEGER)!=(NV_SHORT|NV_INTEGER)) /* ... for arrays */ @@ -158,16 +164,21 @@ extern char *nv_endsubscript(Namval_t*, char*, int); extern Namfun_t *nv_cover(Namval_t*); extern Namarr_t *nv_arrayptr(Namval_t*); +extern int nv_arraysettype(Namval_t*, Namval_t*,const char*,int); +extern int nv_aimax(Namval_t*); +extern int nv_atypeindex(Namval_t*, const char*); extern int nv_setnotify(Namval_t*,char **); extern int nv_unsetnotify(Namval_t*,char **); extern void nv_setlist(struct argnod*, int); +extern struct argnod* nv_onlist(struct argnod*, const char*); extern void nv_optimize(Namval_t*); extern void nv_outname(Sfio_t*,char*, int); -extern void nv_scope(struct argnod*); extern void nv_unref(Namval_t*); extern void _nv_unset(Namval_t*,int); extern int nv_clone(Namval_t*, Namval_t*, int); -extern void *nv_diropen(const char*); +void clone_all_disc(Namval_t*, Namval_t*, int); +extern Namfun_t *nv_clone_disc(Namfun_t*, int); +extern void *nv_diropen(Namval_t*, const char*); extern char *nv_dirnext(void*); extern void nv_dirclose(void*); extern char *nv_getvtree(Namval_t*, Namfun_t*); @@ -175,16 +186,18 @@ extern Namval_t *nv_bfsearch(const char*, Dt_t*, Namval_t**, char**); extern Namval_t *nv_mkclone(Namval_t*); extern Namval_t *nv_mktype(Namval_t**, int); -extern void nv_addnode(Namval_t*, int); +extern Namval_t *nv_addnode(Namval_t*, int); extern Namval_t *nv_parent(Namval_t*); extern char *nv_getbuf(size_t); extern Namval_t *nv_mount(Namval_t*, const char *name, Dt_t*); extern Namval_t *nv_arraychild(Namval_t*, Namval_t*, int); extern int nv_compare(Dt_t*, Void_t*, Void_t*, Dtdisc_t*); +extern Namfun_t *nv_isvtree(Namval_t*); extern const Namdisc_t RESTRICTED_disc; extern char nv_local; extern Dtdisc_t _Nvdisc; +extern const char *nv_discnames[]; extern const char e_subscript[]; extern const char e_nullset[]; extern const char e_notset[]; @@ -205,4 +218,5 @@ extern const char e_badlocale[]; extern const char e_loop[]; extern const char e_redef[]; +extern const char e_badappend[]; #endif /* _NV_PRIVATE */ Index: src/lib/libshell/common/include/streval.h =================================================================== --- src/lib/libshell/common/include/streval.h (revision 974) +++ src/lib/libshell/common/include/streval.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/include/defs.h =================================================================== --- src/lib/libshell/common/include/defs.h (revision 974) +++ src/lib/libshell/common/include/defs.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -25,6 +25,8 @@ * Shell interface private definitions * */ +#ifndef defs_h_defined +#define defs_h_defined #include #include @@ -34,11 +36,17 @@ #include #include "fault.h" #include "argnod.h" +#include "name.h" +#define _SH_PRIVATE +#include +#undef _SH_PRIVATE #ifndef pointerof #define pointerof(x) ((void*)((char*)0+(x))) #endif +#define Empty ((char*)(e_sptbnl+3)) + #define env_change() (++ast.env_serial) #if SHOPT_ENV # include @@ -52,6 +60,8 @@ * note that the first few fields have to be the same as for * Shscoped_t in */ + + struct sh_scoped { struct sh_scoped *prevst; /* pointer to previous state */ @@ -80,6 +90,7 @@ char **trapcom; char **otrapcom; void *timetrap; + struct Ufunction *real_fun; /* current 'function name' function */ }; struct limits @@ -97,6 +108,7 @@ #define _SH_PRIVATE \ struct sh_scoped st; /* scoped information */ \ struct limits lim; /* run time limits */ \ + Stk_t *stk; /* stack poiter */ \ Sfio_t *heredocs; /* current here-doc temp file */ \ Sfio_t *funlog; /* for logging function definitions */ \ int **fdptrs; /* pointer to file numbers */ \ @@ -105,7 +117,6 @@ char *lastpath; /* last alsolute path found */ \ int path_err; /* last error on path search */ \ Dt_t *track_tree; /* for tracked aliases*/ \ - Namval_t *bltin_nodes; /* pointer to built-in variables */ \ Dt_t *var_base; /* global level variables */ \ Namval_t *namespace; /* current active namespace*/ \ Namval_t *last_table; /* last table used in last nv_open */ \ @@ -113,10 +124,12 @@ long timeout; /* read timeout */ \ short curenv; /* current subshell number */ \ short jobenv; /* subshell number for jobs */ \ + int infd; /* input file descriptor */ \ int nextprompt; /* next prompt is PS */ \ + int bltin_nnodes; /* number of bltins nodes */ \ + Namval_t *bltin_nodes; /* pointer to built-in variables */ \ Namval_t *bltin_cmds; /* pointer to built-in commands */ \ Namval_t *posix_fun; /* points to last name() function */ \ - int infd; /* input file descriptor */ \ char *outbuff; /* pointer to output buffer */ \ char *errbuff; /* pointer to stderr buffer */ \ char *prompt; /* pointer to prompt string */ \ @@ -144,7 +157,11 @@ char forked; \ char binscript; \ char deftype; \ + char funload; \ char used_pos; /* used postional parameter */\ + char universe; \ + char winch; \ + char indebug; /* set when in debug trap */ \ unsigned char lastsig; /* last signal received */ \ char *readscript; /* set before reading a script */ \ int *inpipe; /* input pipe pointer */ \ @@ -179,22 +196,27 @@ struct checkpt checkbase; \ Shinit_f userinit; \ Shbltin_f bltinfun; \ + Shbltin_t bltindata; \ Shwait_f waitevent; \ char *cur_line; \ char *rcfile; \ char **login_files; \ - short offsets[10]; \ + int offsets[10]; \ Sfio_t **sftable; \ unsigned char *fdstatus; \ const char *pwd; \ History_t *hist_ptr; \ - char universe; \ void *jmpbuffer; \ void *mktype; \ Sfio_t *strbuf; \ Dt_t *last_root; \ + Dt_t *fpathdict; \ char ifstable[256]; \ - Shopt_t offoptions; + unsigned char sigruntime[2]; \ + unsigned long test; \ + Shopt_t offoptions; \ + Shopt_t glob_options; \ + Namfun_t nvfun; #include @@ -302,13 +324,22 @@ #define MATCH_MAX 64 +#define SH_READEVAL 0x4000 /* for sh_eval */ + +extern Shell_t *nv_shell(Namval_t*); extern int sh_addlib(void*); +extern void sh_applyopts(Shell_t*,Shopt_t); +extern char **sh_argbuild(Shell_t*,int*,const struct comnod*,int); +extern struct dolnod *sh_argfree(Shell_t *, struct dolnod*,int); +extern struct dolnod *sh_argnew(Shell_t*,char*[],struct dolnod**); extern void *sh_argopen(Shell_t*); +extern void sh_argreset(Shell_t*,struct dolnod*,struct dolnod*); extern Namval_t *sh_assignok(Namval_t*,int); +extern struct dolnod *sh_arguse(Shell_t*); extern char *sh_checkid(char*,char*); -extern int sh_debug(const char*,const char*,const char*,char *const[],int); +extern int sh_debug(Shell_t *shp,const char*,const char*,const char*,char *const[],int); extern int sh_echolist(Sfio_t*, int, char**); -extern struct argnod *sh_endword(int); +extern struct argnod *sh_endword(Shell_t*,int); extern char **sh_envgen(void); #if SHOPT_ENV extern void sh_envput(Env_t*, Namval_t*); @@ -318,17 +349,20 @@ extern void *sh_arithcomp(char*); extern pid_t sh_fork(int,int*); extern pid_t _sh_fork(pid_t, int ,int*); -extern char *sh_mactrim(char*,int); -extern int sh_macexpand(struct argnod*,struct argnod**,int); -extern void sh_machere(Sfio_t*, Sfio_t*, char*); +extern char *sh_mactrim(Shell_t*,char*,int); +extern int sh_macexpand(Shell_t*,struct argnod*,struct argnod**,int); +extern int sh_macfun(Shell_t*,const char*,int); +extern void sh_machere(Shell_t*,Sfio_t*, Sfio_t*, char*); extern void *sh_macopen(Shell_t*); -extern char *sh_macpat(struct argnod*,int); -extern char *sh_mactry(char*); +extern char *sh_macpat(Shell_t*,struct argnod*,int); +extern char *sh_mactry(Shell_t*,char*); extern void sh_printopts(Shopt_t,int,Shopt_t*); extern int sh_readline(Shell_t*,char**,int,int,long); extern Sfio_t *sh_sfeval(char*[]); extern void sh_setmatch(const char*,int,int,int[]); extern Dt_t *sh_subaliastree(int); +extern void sh_scope(Shell_t*, struct argnod*, int); +extern Namval_t *sh_scoped(Shell_t*, Namval_t*); extern Dt_t *sh_subfuntree(int); extern int sh_subsavefd(int); extern void sh_subtmpfile(void); @@ -337,6 +371,7 @@ extern int sh_trace(char*[],int); extern void sh_trim(char*); extern int sh_type(const char*); +extern void sh_unscope(Shell_t*); extern void sh_utol(const char*, char*); extern int sh_whence(char**,int); @@ -371,7 +406,9 @@ /* sh_printopts() mode flags -- set --[no]option by default */ #define PRINT_VERBOSE 0x01 /* option on|off list */ -#define PRINT_ALL 0x02 /* list unset iptions too */ +#define PRINT_ALL 0x02 /* list unset options too */ #define PRINT_NO_HEADER 0x04 /* omit listing header */ #define PRINT_SHOPT 0x08 /* shopt -s|-u */ #define PRINT_TABLE 0x10 /* table of all options */ + +#endif Index: src/lib/libshell/common/include/shtable.h =================================================================== --- src/lib/libshell/common/include/shtable.h (revision 974) +++ src/lib/libshell/common/include/shtable.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -33,20 +33,20 @@ typedef struct shtable1 { const char *sh_name; - unsigned sh_number; + const unsigned sh_number; } Shtable_t; struct shtable2 { const char *sh_name; - unsigned sh_number; + const unsigned sh_number; const char *sh_value; }; struct shtable3 { const char *sh_name; - unsigned sh_number; + const unsigned sh_number; int (*sh_value)(int, char*[], void*); }; Index: src/lib/libshell/common/include/shlex.h =================================================================== --- src/lib/libshell/common/include/shlex.h (revision 974) +++ src/lib/libshell/common/include/shlex.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -31,7 +31,8 @@ #include "shtable.h" #include "lexstates.h" -struct shlex_t + +typedef struct _shlex_ { Shell_t *sh; /* pointer to the interpreter */ struct argnod *arg; /* current word */ @@ -42,9 +43,12 @@ int digits; /* numerical value with word token */ char aliasok; /* on when alias is legal */ char assignok; /* on when name=value is legal */ + char inexec; /* on when processing exec */ + char intypeset; /* on when processing typeset */ + char comp_assign; /* in compound assignment */ + char comsub; /* parsing command substitution */ int inlineno; /* saved value of sh.inlineno */ int firstline; /* saved value of sh.st.firstline */ - int comsub; /* parsing command substitution */ #if SHOPT_KIA Sfio_t *kiafile; /* kia output file */ Sfio_t *kiatmp; /* kia reference file */ @@ -56,7 +60,10 @@ char *scriptname; /* name of script file */ Dt_t *entity_tree; /* for entity ids */ #endif /* SHOPT_KIA */ -}; +#ifdef _SHLEX_PRIVATE + _SHLEX_PRIVATE +#endif +} Lex_t; /* symbols for parsing */ #define NL '\n' @@ -122,6 +129,7 @@ #define SH_COMPASSIGN 010 /* allow compound assignments only */ +#if 0 typedef struct _shlex_ { struct shlex_t _shlex; @@ -131,6 +139,7 @@ } Lex_t; #define shlex (((Lex_t*)(sh.lex_context))->_shlex) +#endif extern const char e_unexpected[]; extern const char e_unmatched[]; extern const char e_endoffile[]; @@ -144,9 +153,15 @@ #define LBRACT '[' #define RBRACT ']' -extern int sh_lex(); +extern int sh_lex(Lex_t*); +extern Shnode_t *sh_dolparen(Lex_t*); extern Lex_t *sh_lexopen(Lex_t*, Shell_t*, int); -extern void sh_lexskip(int,int,int); -extern void sh_syntax(void); +extern void sh_lexskip(Lex_t*,int,int,int); +extern void sh_syntax(Lex_t*); +#if SHOPT_KIA + extern int kiaclose(Lex_t *); + extern unsigned long kiaentity(Lex_t*, const char*,int,int,int,int,unsigned long,int,int,const char*); +#endif /* SHOPT_KIA */ + #endif /* !NOTSYM */ Index: src/lib/libshell/common/include/edit.h =================================================================== --- src/lib/libshell/common/include/edit.h (revision 974) +++ src/lib/libshell/common/include/edit.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/include/version.h =================================================================== --- src/lib/libshell/common/include/version.h (revision 974) +++ src/lib/libshell/common/include/version.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -17,4 +17,4 @@ * David Korn * * * ***********************************************************************/ -#define SH_RELEASE "1993-12-28 s+" +#define SH_RELEASE "93t- 2008-06-14" Index: src/lib/libshell/common/include/timeout.h =================================================================== --- src/lib/libshell/common/include/timeout.h (revision 974) +++ src/lib/libshell/common/include/timeout.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/include/env.h =================================================================== --- src/lib/libshell/common/include/env.h (revision 974) +++ src/lib/libshell/common/include/env.h (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/edit/vi.c =================================================================== --- src/lib/libshell/common/edit/vi.c (revision 974) +++ src/lib/libshell/common/edit/vi.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -556,6 +556,11 @@ i = sigsetjmp(editb.e_env,0); if( i != 0 ) { + if(vp->ed->e_multiline) + { + cur_virt = last_virt; + sync_cursor(vp); + } virtual[0] = '\0'; tty_cooked(ERRIO); @@ -1472,6 +1477,7 @@ if( mode != SEARCH ) save_last(vp); refresh(vp,INPUT); + last_phys++; return; case '\t': /** command completion **/ @@ -1557,7 +1563,21 @@ switch(motion=getcount(vp,ed_getchar(vp->ed,-1))) { case 'A': - ed_ungetchar(vp->ed,'k'); + if(cur_virt>=0 && cur_virt<(SEARCHSIZE-2) && cur_virt == last_virt) + { + virtual[last_virt + 1] = '\0'; + gencpy(&((genchar*)lsearch)[1], virtual); +#if SHOPT_MULTIBYTE + ed_external(&((genchar*)lsearch)[1],lsearch+1); +#endif /* SHOPT_MULTIBYTE */ + *lsearch = '^'; + vp->direction = -2; + ed_ungetchar(vp->ed,'n'); + } + else if(cur_virt==0 && vp->direction == -2) + ed_ungetchar(vp->ed,'n'); + else + ed_ungetchar(vp->ed,'k'); return(1); case 'B': ed_ungetchar(vp->ed,'j'); @@ -1927,6 +1947,8 @@ vp->long_line = vp->long_char; } + if(vp->ed->e_multiline && vp->ofirst_wind==INVALID) + ed_setcursor(vp->ed, physical, last_phys+1, last_phys+1, -1); vp->ocur_phys = ncur_phys; vp->ocur_virt = cur_virt; vp->ofirst_wind = first_w; @@ -2103,6 +2125,8 @@ register int i; Histloc_t location; + if( vp->direction == -2 && mode != 'n') + vp->direction = -1; if( mode == '/' || mode == '?') { /*** new search expression ***/ Index: src/lib/libshell/common/edit/history.c =================================================================== --- src/lib/libshell/common/edit/history.c (revision 974) +++ src/lib/libshell/common/edit/history.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -49,13 +49,23 @@ #define HIST_BSIZE 4096 /* size of history file buffer */ #define HIST_DFLT 512 /* default size of history list */ +#if SHOPT_AUDIT +# define _HIST_AUDIT Sfio_t *auditfp; \ + char *tty; \ + int auditmask; +#else +# define _HIST_AUDIT +#endif + #define _HIST_PRIVATE \ + void *histshell; \ off_t histcnt; /* offset into history file */\ off_t histmarker; /* offset of last command marker */ \ int histflush; /* set if flushed outside of hflush() */\ int histmask; /* power of two mask for histcnt */ \ char histbuff[HIST_BSIZE+1]; /* history file buffer */ \ int histwfail; \ + _HIST_AUDIT \ off_t histcmds[2]; /* offset for recent commands, must be last */ #define hist_ind(hp,c) ((int)((c)&(hp)->histmask)) @@ -119,10 +129,10 @@ static char *logname; # include - int acctinit(void) + static int acctinit(History_t *hp) { register char *cp, *acctfile; - Namval_t *np = nv_search("ACCTFILE",sh.var_tree,0); + Namval_t *np = nv_search("ACCTFILE",((Shell_t*)hp->histshell)->var_tree,0); if(!np || !(acctfile=nv_getval(np))) return(0); @@ -135,7 +145,6 @@ cp = "unknown"; } logname = strdup(cp); - if((acctfd=sh_open(acctfile, O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IRUSR|S_IWUSR))>=0 && (unsigned)acctfd < 10) @@ -164,6 +173,42 @@ } #endif /* SHOPT_ACCTFILE */ +#if SHOPT_AUDIT +static int sh_checkaudit(History_t *hp, const char *name, char *logbuf, size_t len) +{ + Shell_t *shp = (Shell_t*)hp->histshell; + char *buff, *cp, *last; + int id1, id2, r=0, n, fd; + if((fd=open(name, O_RDONLY)) < 0) + return(0); + if((n = read(fd, logbuf,len-1)) < 0) + goto done; + while(logbuf[n-1]=='\n') + n--; + logbuf[n] = 0; + if(!(cp=strchr(logbuf,';')) && !(cp=strchr(logbuf,' '))) + goto done; + *cp = 0; + do + { + cp++; + id1 = id2 = strtol(cp,&last,10); + if(*last=='-') + id1 = strtol(last+1,&last,10); + if(shp->euserid >=id1 && shp->euserid <= id2) + r |= 1; + if(shp->userid >=id1 && shp->userid <= id2) + r |= 2; + cp = last; + } + while(*cp==';' || *cp==' '); +done: + close(fd); + return(r); + +} +#endif /*SHOPT_AUDIT*/ + static const unsigned char hist_stamp[2] = { HIST_UNDO, HIST_VERSION }; static const Sfdisc_t hist_disc = { NULL, hist_write, NULL, hist_exceptf, NULL}; @@ -179,8 +224,9 @@ * cleaned up. * hist_open() returns 1, if history file is open */ -int sh_histinit(void) +int sh_histinit(void *sh_context) { + Shell_t *shp = (Shell_t*)sh_context; register int fd; register History_t *hp; register char *histname; @@ -189,7 +235,7 @@ register char *cp; register off_t hsize = 0; - if(sh.hist_ptr=hist_ptr) + if(shp->hist_ptr=hist_ptr) return(1); if(!(histname = nv_getval(HISTFILE))) { @@ -206,7 +252,7 @@ { /* reuse history file if same name */ wasopen = 0; - sh.hist_ptr = hist_ptr = hp; + shp->hist_ptr = hist_ptr = hp; if(strcmp(histname,hp->histname)==0) return(1); else @@ -243,7 +289,7 @@ { #if KSHELL /* don't allow root a history_file in /tmp */ - if(sh.userid) + if(shp->userid) #endif /* KSHELL */ { if(!(fname = pathtmp(NIL(char*),0,0,NIL(int*)))) @@ -265,7 +311,8 @@ close(fd); return(0); } - sh.hist_ptr = hist_ptr = hp; + shp->hist_ptr = hist_ptr = hp; + hp->histshell = (void*)shp; hp->histsize = maxlines; hp->histmask = histmask; hp->histfp= sfnew(NIL(Sfio_t*),hp->histbuff,HIST_BSIZE,fd,SF_READ|SF_WRITE|SF_APPENDWR|SF_SHARE); @@ -327,8 +374,31 @@ sh_timeradd(1000L*(HIST_RECENT-30), 1, hist_touch, (void*)hp->histname); #if SHOPT_ACCTFILE if(sh_isstate(SH_INTERACTIVE)) - acctinit(); + acctinit(hp); #endif /* SHOPT_ACCTFILE */ +#if SHOPT_AUDIT + { + char buff[SF_BUFSIZE]; + hp->auditfp = 0; + if(sh_isstate(SH_INTERACTIVE) && (hp->auditmask=sh_checkaudit(hp,SHOPT_AUDITFILE, buff, sizeof(buff)))) + { + if((fd=sh_open(buff,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IRUSR|S_IWUSR))>=0 && fd < 10) + { + int n; + if((n = sh_fcntl(fd,F_DUPFD, 10)) >= 0) + { + sh_close(fd); + fd = n; + } + } + if(fd>=0) + { + hp->tty = strdup(ttyname(2)); + hp->auditfp = sfnew((Sfio_t*)0,NULL,-1,fd,SF_WRITE); + } + } + } +#endif return(1); } @@ -338,10 +408,19 @@ void hist_close(register History_t *hp) { + Shell_t *shp = (Shell_t*)hp->histshell; sfclose(hp->histfp); +#if SHOPT_AUDIT + if(hp->auditfp) + { + if(hp->tty) + free((void*)hp->tty); + sfclose(hp->auditfp); + } +#endif /* SHOPT_AUDIT */ free((char*)hp); hist_ptr = 0; - sh.hist_ptr = 0; + shp->hist_ptr = 0; #if SHOPT_ACCTFILE if(acctfd) { @@ -407,13 +486,13 @@ if(tmpname==name) tmpname = 0; } - hp = hist_ptr = 0; + hist_ptr = 0; if(fstat(sffileno(hist_old->histfp),&statb)>=0) { histinit = 1; histmode = statb.st_mode; } - if(!sh_histinit()) + if(!sh_histinit(hp->histshell)) { /* use the old history file */ hist_ptr = hist_old; @@ -668,7 +747,7 @@ if(sfsync(hp->histfp)<0) { hist_close(hp); - if(!sh_histinit()) + if(!sh_histinit(hp->histshell)) sh_offoption(SH_HISTORY); } hp->histflush = 0; @@ -718,6 +797,15 @@ *bufptr++ = '\n'; *bufptr++ = 0; size = bufptr - (char*)buff; +#if SHOPT_AUDIT + if(hp->auditfp) + { + Shell_t *shp = (Shell_t*)hp->histshell; + time_t t=time((time_t*)0); + sfprintf(hp->auditfp,"%u;%u;%s;%*s%c",sh_isoption(SH_PRIVILEGED)?shp->euserid:shp->userid,t,hp->tty,size,buff,0); + sfsync(hp->auditfp); + } +#endif /* SHOPT_AUDIT */ #if SHOPT_ACCTFILE if(acctfd) { @@ -876,7 +964,7 @@ } #if KSHELL /* allow a search to be aborted */ - if(sh.trapnote&SH_SIGSET) + if(((Shell_t*)hp->histshell)->trapnote&SH_SIGSET) break; #endif /* KSHELL */ } @@ -986,7 +1074,7 @@ if(!hp) #if KSHELL { - strncpy(string,sh.lastarg,size); + strncpy(string,((Shell_t*)hp->histshell)->lastarg,size); return(string); } #else Index: src/lib/libshell/common/edit/edit.c =================================================================== --- src/lib/libshell/common/edit/edit.c (revision 974) +++ src/lib/libshell/common/edit/edit.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -53,6 +53,8 @@ static char CURSOR_UP[20] = { ESC, '[', 'A', 0 }; + + #if SHOPT_MULTIBYTE # define is_cntrl(c) ((c<=STRIP) && iscntrl(c)) # define is_print(c) ((c&~STRIP) || isprint(c)) @@ -583,34 +585,39 @@ void ed_setup(register Edit_t *ep, int fd, int reedit) { + Shell_t *shp = ep->sh; register char *pp; - register char *last; + register char *last, *prev; char *ppmax; int myquote = 0, n; - register int qlen = 1; + register int qlen = 1, qwid; char inquote = 0; ep->e_fd = fd; ep->e_multiline = sh_isoption(SH_MULTILINE)!=0; #ifdef SIGWINCH - if(!(sh.sigflag[SIGWINCH]&SH_SIGFAULT)) + if(!(shp->sigflag[SIGWINCH]&SH_SIGFAULT)) { signal(SIGWINCH,sh_fault); - sh.sigflag[SIGWINCH] |= SH_SIGFAULT; + shp->sigflag[SIGWINCH] |= SH_SIGFAULT; } + pp = shp->st.trapcom[SIGWINCH]; + shp->st.trapcom[SIGWINCH] = 0; sh_fault(SIGWINCH); + shp->st.trapcom[SIGWINCH] = pp; + ep->sh->winch = 0; #endif #if KSHELL ep->e_stkptr = stakptr(0); ep->e_stkoff = staktell(); - if(!(last = sh.prompt)) + if(!(last = shp->prompt)) last = ""; - sh.prompt = 0; + shp->prompt = 0; #else last = ep->e_prbuff; #endif /* KSHELL */ - if(sh.hist_ptr) + if(shp->hist_ptr) { - register History_t *hp = sh.hist_ptr; + register History_t *hp = shp->hist_ptr; ep->e_hismax = hist_max(hp); ep->e_hismin = hist_min(hp); } @@ -631,7 +638,7 @@ *pp++ = '\r'; { register int c; - while(c= *last++) switch(c) + while(prev = last, c = mbchar(last)) switch(c) { case ESC: { @@ -642,7 +649,7 @@ { if(pp < ppmax) *pp++ = c; - if(c=='\a') + if(c=='\a' || c==ESC || c=='\r') break; if(skip || (c>='0' && c<='9')) continue; @@ -651,6 +658,8 @@ else if(n>2 || (c!= '[' && c!= ']')) break; } + if(c==0 || c==ESC || c=='\r') + last--; qlen += (n+1); break; } @@ -693,17 +702,22 @@ } if(pp < ppmax) { - qlen += inquote; - *pp++ = c; - if(!inquote && !is_print(c)) + if(inquote) + qlen++; + else if(!is_print(c)) ep->e_crlf = 0; + if((qwid = last - prev) > 1) + qlen += qwid - mbwidth(c); + while(prev < last && pp < ppmax) + *pp++ = *prev++; } + break; } } if(pp-ep->e_prompt > qlen) ep->e_plen = pp - ep->e_prompt - qlen; *pp = 0; - if((ep->e_wsize -= ep->e_plen) < 7) + if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7) { register int shift = 7-ep->e_wsize; ep->e_wsize = 7; @@ -736,7 +750,7 @@ #ifdef _cmd_tput char *term; if(!ep->e_term) - ep->e_term = nv_search("TERM",sh.var_tree,0); + ep->e_term = nv_search("TERM",shp->var_tree,0); if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)e_termname) && strcmp(term,ep->e_termname)) { sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0); @@ -774,8 +788,9 @@ register Edit_t *ep = (Edit_t*)context; register int rv= -1; register int delim = (ep->e_raw==RAWMODE?'\r':'\n'); + Shell_t *shp = ep->sh; int mode = -1; - int (*waitevent)(int,long,int) = sh.waitevent; + int (*waitevent)(int,long,int) = shp->waitevent; if(ep->e_raw==ALTMODE) mode = 1; if(size < 0) @@ -785,11 +800,27 @@ } sh_onstate(SH_TTYWAIT); errno = EINTR; - sh.waitevent = 0; + shp->waitevent = 0; while(rv<0 && errno==EINTR) { - if(sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) + if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP)) goto done; + if(ep->sh->winch) + { + ep->sh->winch = 0; + ep->e_winsz = ed_window(); + if(!ep->e_multiline && ep->e_wsize < MAXLINE) + ep->e_wsize = ep->e_winsz-2; + if(*ep->e_vi_insert) + { + buff[0] = ESC; + buff[1] = cntl('L'); + buff[2] = 'a'; + return(3); + } + buff[0] = cntl('L'); + return(1); + } /* an interrupt that should be ignored */ errno = 0; if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0) @@ -824,7 +855,7 @@ rv = read(fd,buff,size); if(rv>=0 || errno!=EINTR) break; - if(sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) + if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP)) goto done; /* an interrupt that should be ignored */ fixtime(); @@ -833,7 +864,7 @@ else if(rv>=0 && mode>0) rv = read(fd,buff,rv>0?rv:1); done: - sh.waitevent = waitevent; + shp->waitevent = waitevent; sh_offstate(SH_TTYWAIT); return(rv); } @@ -952,15 +983,17 @@ ed_flush(ep); ep->e_inmacro = 0; /* The while is necessary for reads of partial multbyte chars */ + *ep->e_vi_insert = (mode==-2); if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0) n = putstack(ep,readin,n,1); + *ep->e_vi_insert = 0; } if(ep->e_lookahead) { /* check for possible key mapping */ if((c = ep->e_lbuf[--ep->e_lookahead]) < 0) { - if(mode<=0 && sh.st.trap[SH_KEYTRAP]) + if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP]) { n=1; if((readin[0]= -c) == ESC) @@ -1075,7 +1108,14 @@ col = pos.col; } else + { pos.line = 0; + while(col > ep->e_winsz) + { + pos.line++; + col -= (ep->e_winsz+1); + } + } while(off-->0) { if(c) @@ -1104,53 +1144,75 @@ ed_putchar(ep,c); } +static void ed_nputchar(register Edit_t *ep, int n, int c) +{ + while(n-->0) + ed_putchar(ep,c); +} + int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first) { static int oldline; register int delta; + int clear = 0; Edpos_t newpos; delta = new - old; - if( delta == 0 ) + if(first < 0) + { + first = 0; + clear = 1; + } + if( delta == 0 && !clear) return(new); if(ep->e_multiline) { ep->e_curpos = ed_curpos(ep, physical, old,0,ep->e_curpos); + if(clear && old>=ep->e_peol && (clear=ep->e_winsz-ep->e_curpos.col)>0) + { + ed_nputchar(ep,clear,' '); + ed_nputchar(ep,clear,'\b'); + return(new); + } newpos = ed_curpos(ep, physical, new,old,ep->e_curpos); if(ep->e_curpos.col==0 && ep->e_curpos.line>0 && oldlinee_curpos.line && delta<0) ed_putstring(ep,"\r\n"); oldline = newpos.line; if(ep->e_curpos.line > newpos.line) { - int n; + int n,pline,plen=ep->e_plen; for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--) ed_putstring(ep,CURSOR_UP); - if(newpos.line==0 && (n=ep->e_plen- ep->e_curpos.col)>0) + pline = plen/(ep->e_winsz+1); + if(newpos.line <= pline) + plen -= pline*(ep->e_winsz+1); + else + plen = 0; + if((n=plen- ep->e_curpos.col)>0) { ep->e_curpos.col += n; ed_putchar(ep,'\r'); - if(!ep->e_crlf) + if(!ep->e_crlf && pline==0) ed_putstring(ep,ep->e_prompt); else { - int m = ep->e_winsz+1-ep->e_plen; + int m = ep->e_winsz+1-plen; ed_putchar(ep,'\n'); - n = ep->e_plen; + n = plen; if(m < ed_genlen(physical)) { while(physical[m] && n-->0) ed_putchar(ep,physical[m++]); } - while(n-->0) - ed_putchar(ep,' '); + ed_nputchar(ep,n,' '); ed_putstring(ep,CURSOR_UP); } } } else if(ep->e_curpos.line < newpos.line) { - for(;ep->e_curpos.line < newpos.line;ep->e_curpos.line++) - ed_putchar(ep,'\n'); + ed_nputchar(ep, newpos.line-ep->e_curpos.line,'\n'); + ep->e_curpos.line = newpos.line; ed_putchar(ep,'\r'); ep->e_curpos.col = 0; } @@ -1161,18 +1223,21 @@ newpos.line=0; if(delta<0) { + int bs= newpos.line && ep->e_plen>ep->e_winsz; /*** move to left ***/ delta = -delta; /*** attempt to optimize cursor movement ***/ - if(!ep->e_crlf || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) ) + if(!ep->e_crlf || bs || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) ) { - for( ; delta; delta-- ) - ed_putchar(ep,'\b'); + ed_nputchar(ep,delta,'\b'); + delta = 0; } else { if(newpos.line==0) ed_putstring(ep,ep->e_prompt); + else + ed_putchar(ep,'\r'); old = first; delta = new-first; } @@ -1244,6 +1309,7 @@ break; } *dp = 0; + ep->e_peol = dp-phys; return(r); } @@ -1375,8 +1441,7 @@ * This version will use termios when possible, otherwise termio */ - -tcgetattr(int fd, struct termios *tt) +int tcgetattr(int fd, struct termios *tt) { register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context); register int r,i; @@ -1398,7 +1463,7 @@ return(r); } -tcsetattr(int fd,int mode,struct termios *tt) +int tcsetattr(int fd,int mode,struct termios *tt) { register Edit_t *ep = (Edit_t*)(sh_getinterp()->ed_context); register int r; @@ -1446,6 +1511,7 @@ { register char *cp; int savexit; + Shell_t *shp = ep->sh; #if SHOPT_MULTIBYTE char buff[MAXLINE]; ed_external(ep->e_inbuf,cp=buff); @@ -1465,16 +1531,19 @@ nv_putval(ED_COLNOD,(char*)&ep->e_col,NV_NOFREE|NV_INTEGER); nv_putval(ED_TXTNOD,(char*)cp,NV_NOFREE); nv_putval(ED_MODENOD,ep->e_vi_insert,NV_NOFREE); - savexit = sh.savexit; - sh_trap(sh.st.trap[SH_KEYTRAP],0); - sh.savexit = savexit; + savexit = shp->savexit; + sh_trap(shp->st.trap[SH_KEYTRAP],0); + shp->savexit = savexit; if((cp = nv_getval(ED_CHRNOD)) == inbuff) nv_unset(ED_CHRNOD); - else + else if(bufsize>0) { strncpy(inbuff,cp,bufsize); + inbuff[bufsize-1]='\0'; insize = strlen(inbuff); } + else + insize = 0; nv_unset(ED_TXTNOD); return(insize); } Index: src/lib/libshell/common/edit/hexpand.c =================================================================== --- src/lib/libshell/common/edit/hexpand.c (revision 974) +++ src/lib/libshell/common/edit/hexpand.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/edit/emacs.c =================================================================== --- src/lib/libshell/common/edit/emacs.c (revision 974) +++ src/lib/libshell/common/edit/emacs.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -108,6 +108,7 @@ char CntrlO; char overflow; /* Screen overflow flag set */ char scvalid; /* Screen is up to date */ + char lastdraw; /* last update type */ int offset; /* Screen offset */ enum { @@ -195,6 +196,7 @@ } Prompt = prompt; ep->screen = Screen; + ep->lastdraw = FINAL; if(tty_raw(ERRIO,0) < 0) { return(reedit?reedit:ed_read(context, fd,buff,scend,0)); @@ -231,6 +233,12 @@ i = sigsetjmp(env,0); if (i !=0) { + if(ep->ed->e_multiline) + { + cur = eol; + draw(ep,FINAL); + ed_flush(ep->ed); + } tty_cooked(ERRIO); if (i == UEOF) { @@ -649,6 +657,8 @@ location.hist_command = hline; /* save current position */ location.hist_line = hloff; #endif + cur = 0; + draw(ep,UPDATE); hist_copy((char*)out,MAXLINE, hline,hloff); #if SHOPT_MULTIBYTE ed_internal((char*)(out),out); @@ -1000,6 +1010,26 @@ switch(i=ed_getchar(ep->ed,1)) { case 'A': + if(cur>0 && eol==cur && (cur<(SEARCHSIZE-2) || ep->prevdirection == -2)) + { + if(ep->lastdraw==APPEND && ep->prevdirection != -2) + { + out[cur] = 0; + gencpy(&((genchar*)lstring)[1],out); +#if SHOPT_MULTIBYTE + ed_external(&((genchar*)lstring)[1],lstring+1); +#endif /* SHOPT_MULTIBYTE */ + *lstring = '^'; + ep->prevdirection = -2; + } + if(*lstring) + { + ed_ungetchar(ep->ed,'\r'); + ed_ungetchar(ep->ed,cntl('R')); + return(-1); + } + } + *lstring = 0; ed_ungetchar(ep->ed,cntl('P')); return(-1); case 'B': @@ -1189,6 +1219,8 @@ } i = genlen(string); + if(ep->prevdirection == -2 && i!=2 || direction!=1) + ep->prevdirection = -1; if (direction < 1) { ep->prevdirection = -ep->prevdirection; @@ -1264,6 +1296,7 @@ sptr = drawbuff; logcursor = sptr + cur; longline = NORMAL; + ep->lastdraw = option; if (option == FIRST || option == REFRESH) { @@ -1377,6 +1410,9 @@ } #endif /* SHOPT_MULTIBYTE */ } + if(ep->ed->e_multiline && option == REFRESH) + ed_setcursor(ep->ed, ep->screen, ep->cursor-ep->screen, ep->ed->e_peol, -1); + /****************** @@ -1407,7 +1443,7 @@ i = (ncursor-nscreen) - ep->offset; setcursor(ep,i,0); if(option==FINAL && ep->ed->e_multiline) - setcursor(ep,nscend-nscreen,0); + setcursor(ep,nscend+1-nscreen,0); ep->scvalid = 1; return; } Index: src/lib/libshell/common/edit/completion.c =================================================================== --- src/lib/libshell/common/edit/completion.c (revision 974) +++ src/lib/libshell/common/edit/completion.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -68,7 +68,8 @@ static char *find_begin(char outbuff[], char *last, int endchar, int *type) { register char *cp=outbuff, *bp, *xp; - register int c,inquote = 0; + register int c,inquote = 0, inassign=0; + int mode=*type; bp = outbuff; *type = 0; while(cp < last) @@ -94,7 +95,7 @@ if(inquote == '\'') break; c = *(unsigned char*)cp; - if(isaletter(c) || c=='{') + if(mode!='*' && (isaletter(c) || c=='{')) { int dot = '.'; if(c=='{') @@ -112,7 +113,7 @@ if((c= mbchar(cp)) , c!=dot && !isaname(c)) break; } - if(cp>=last) + if(cp>=last && c!= '}') { *type='$'; return(++xp); @@ -120,6 +121,7 @@ } else if(c=='(') { + *type = mode; xp = find_begin(cp,last,')',type); if(*(cp=xp)!=')') bp = xp; @@ -129,8 +131,15 @@ break; case '=': if(!inquote) + { bp = cp; + inassign = 1; + } break; + case ':': + if(!inquote && inassign) + bp = cp; + break; case '~': if(*cp=='(') break; @@ -139,7 +148,10 @@ if(c && c==endchar) return(xp); if(!inquote && ismeta(c)) + { bp = cp; + inassign = 0; + } break; } } @@ -172,7 +184,7 @@ { if(count> ep->e_nlist) return(-1); - mode = '*'; + mode = '?'; av[0] = ep->e_clist[count-1]; av[1] = 0; } @@ -207,6 +219,7 @@ register int c; char *last = out; c = *(unsigned char*)out; + var = mode; begin = out = find_begin(outbuff,last,0,&var); /* addstar set to zero if * should not be added */ if(var=='$') @@ -234,6 +247,8 @@ out++; } } + if(mode=='?') + mode = '*'; if(var!='$' && mode=='\\' && out[-1]!='*') addstar = '*'; if(*begin=='~' && !strchr(begin,'/')) @@ -264,7 +279,7 @@ } else { - com = sh_argbuild(&narg,comptr,0); + com = sh_argbuild(ep->sh,&narg,comptr,0); /* special handling for leading quotes */ if(begin>outbuff && (begin[-1]=='"' || begin[-1]=='\'')) begin--; @@ -373,14 +388,9 @@ { Namval_t *np; /* add as tracked alias */ -#ifdef PATH_BFPATH Pathcomp_t *pp; if(*cp=='/' && (pp=path_dirfind(sh.pathlist,cp,'/')) && (np=nv_search(begin,sh.track_tree,NV_ADD))) path_alias(np,pp); -#else - if(*cp=='/' && (np=nv_search(begin,sh.track_tree,NV_ADD))) - path_alias(np,cp); -#endif out = strcopy(begin,cp); } /* add quotes if necessary */ Index: src/lib/libshell/common/scripts/shman.sh =================================================================== --- src/lib/libshell/common/scripts/shman.sh (revision 0) +++ src/lib/libshell/common/scripts/shman.sh (revision 1122) @@ -0,0 +1,358 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +function fatal_error +{ + print -u 2 "${progname}: $@" + exit 1 +} + +function debug_print +{ + # don't use "--" here to allow "-f" for formatting +# print -u2 "$@" +true +} + +# list man dirs calculated from MANPATH and locale +function enumerate_mandirs +{ + nameref md=$1 + integer i=0 + typeset m manlang + + if [[ "${LC_MESSAGES}" != "" ]] ; then + manlang="${LC_MESSAGES}" + else + manlang="${LANG}" + fi + + print -r -- "${MANPATH//:/$'\n'}" | while read m ; do + [[ "${manlang}" != "" && -d "${m}/${manlang}" ]] && md[$((i++))]="${m}/${manlang}" + [[ -d "${m}" ]] && md[$((i++))]="${m}" + done +} + +function enumerate_mansects +{ + nameref ms=$1 + typeset mandir="$2" + typeset mancf="${mandir}/man.cf" + typeset x s l + integer i=0 + + if [[ "${MANSECTS}" != "" ]] ; then + x="${MANSECTS//,/$'\n'}" + elif [[ -f "${mancf}" && -r "${mancf}" ]] ; then + x="$(cat "${mancf}" | /usr/xpg4/bin/egrep -v '^#|^[[:space:]]*$' | egrep '^MANSECTS=')" + x="${x/MANSECTS=}/" + x="${x//,/$'\n'}" + else + x="$(cd "${mandir}" ; \ + ls -1d ~(El)(sman|man).*/ | \ + while read s ; do \ + s="${s/~(El)(sman|man)/}" ; \ + s="${s/~(Er)\//}" ; \ + print -- "$s" ; \ + done)" + fi + + print -- "${x}" | + while read l ; do + [[ "${l}" != ~(Elr)[[:blank:]]* ]] && ms[$((i++))]="${l}" +# print -- "sect=$l" + done + +# print "enumerate_mansects: found $i/${#ms[*]} entries." + + return 0 +} + +# wrapper around more/less +function browse_manpage +{ + typeset tmpdirname + typeset doc_filename="$1" + typeset doc_title="$2" + + # squish characters in filename which are not allowed in a filesystem + # (currently '/') + doc_title="${doc_title//\//}" + + # check if we have "less" installed, if not fall back to /usr/xpg4/bin/more + if which less >/dev/null 2>&1 ; then + # use "cat" here to avoid that "less" may try funny things + cat <"${doc_filename}" | less -I -M "--prompt=MManual\ page\ ${doc_title}\ ?ltline\ %lt?L/%L.:" + else + tmpdirname="/tmp/shman_${PPID}_$$" + + mkdir -p "${tmpdirname}" || { printf -u2 "Couldn't create tmp. dir ${tmpdirname}" ; return 0 ; } + + ( + cd "${tmpdirname}" + + # note: we need to support /dev/stdin + cat <"${doc_filename}" >"./${doc_title}" + + /usr/xpg4/bin/more "${doc_title}" + + rm -f "${doc_title}" + ) + + rmdir "${tmpdirname}" + fi + + return 0 +} + +function show_manpage +{ + typeset -a mandirs + + enumerate_mandirs mandirs +# debug_print -- "${mandirs[@]}" + + integer num_mandirs=${#mandirs[*]} + + for ((i=0 ; i < num_mandirs ; i++ )) ; do + typeset mandir="${mandirs[i]}" + + typeset -a mansects + enumerate_mansects mansects "${mandir}" + integer num_mansects="${#mansects[*]}" +# debug_print -- "mansects=${mansects[@]}" + + for ((j=0 ; j < num_mansects ; j++ )) ; do + mansect="${mansects[j]}" + + # try 1: SGML manpage + match="${mandir}/sman${mansect}/${manname}.${mansect}" + if [[ -r "${match}" ]] ; then + typeset note nlink + + # follow SGML links if needed (needs rework, including protection against link loops) + while true ; do + debug_print -f "match: %s\n" "${match}" + + (cd "${mandir}" ; LC_MESSAGES=C /usr/lib/sgml/sgml2roff "${match}") >/tmp/xxx + read note nlink ] +[+NAME?man - find and display reference manual pages] +[+DESCRIPTION?The man command displays information from the reference + manuals. It displays complete manual pages that you select + by name, or one-line summaries selected either by keyword + (-k), or by the name of an associated file (-f). If no + manual page is located, man prints an error message.] +[+?write me.] +[k:keyword?Prints out one-line summaries from the windex database (table of contents) that + contain any of the given keywords. The windex database is created using + catman(1M).] +[l:list?Lists all manual pages found matching name within the search path.] +[M:mpath?Specifies an alternate search path for manual pages. path is a colon-separated + list of directories that contain manual page directory subtrees. For example, if + path is /usr/share/man:/usr/local/man, man searches for name in the standard + location, and then /usr/local/man. When used with the -k or -f options, the -M + option must appear first. Each directory in the path is assumed to contain subdirectories of the form man* or sman* , + one for each section. This option overrides the MANPATH environment variable.]:[path] +[s:section?Specifies sections of the manual for man to search. The directories searched for + name are limited to those specified by section. section can be a numerical + digit, perhaps followed by one or more letters to match the desired section of + the manual, for example, "3libucb". Also, section can be a word, for exam- + ple, local, new, old, public. section can also be a letter. + To specify multiple sections, separate each section with + a comma. This option overrides the MANPATH environment variable and the man.cf + file. See Search Path below for an explanation of how man conducts its + search.]:[section] + +name + +[+SEE ALSO?\bksh93\b(1), \bman\b(1)] +' + +typeset do_list=false +typeset do_keyword=false + +while getopts -a "${progname}" "${shman_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + M) MANPATH="${OPTARG}" ;; + l) do_list=true ;; + k) do_keyword=true ;; + s) MANSECTS="${OPTARG}" ;; + *) usage ;; + esac +done +shift $((OPTIND-1)) + +# cd /usr/man; LC_MESSAGES=C /usr/lib/sgml/sgml2roff /usr/man/sman1as/asadmin-list-timers.1as | tbl | eqn | nroff -u0 -Tlp -man - | col -x > /tmp/mpLQaqac + +typeset manname="$1" +debug_print "# searching for ${manname} ..." + +if ${do_keyword} ; then + list_keywords +elif ${do_list} ; then + list_manpages +else + show_manpage +fi + +# todo: better exit codes +exit 0 +# EOF. Index: src/lib/libshell/common/scripts/multifollow.sh =================================================================== --- src/lib/libshell/common/scripts/multifollow.sh (revision 0) +++ src/lib/libshell/common/scripts/multifollow.sh (revision 1122) @@ -0,0 +1,150 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +function fatal_error +{ + print -u 2 "${progname}: $@" + exit 1 +} + + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${multifollow_usage}" OPT '-?' + exit 2 +} + +# program start +builtin basename +builtin cat + +typeset progname="$(basename "${0}")" + +typeset -r multifollow_usage=$'+ +[-?\n@(#)\$Id: multifollow (Roland Mainz) 2008-04-28 \$\n] +[-author?Roland Mainz ] +[+NAME?multifollow - use tail -f on multiple files] +[+DESCRIPTION?\bmultifollow\b is a small utilty which can "follow" multiple + files similar to tail -f.] + +[ file ... ] + +[+SEE ALSO?\bksh93\b(1), \btail\b(1)] +' + +while getopts -a "${progname}" "${multifollow_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + *) usage ;; + esac +done +shift $((OPTIND-1)) + +# expecting at least one more arguments +(($# >= 1)) || usage + +builtin -f libshell.so.1 poll || fatal_error "poll builtin not found." + +typeset -a files +integer numfiles=0 +integer i + +# register trap to cleanup child processes +trap 'for ((i=0 ; i < numfiles ; i++ )) ; do kill -TERM ${files[i].childpid} ; done' EXIT + +# setup "tail -f" childs, FIFOs and information for the "poll" builtin +for (( ; $# > 0 ; numfiles++ )) ; do + typeset files[${numfiles}]=( + typeset name="$1" + typeset pipename="/tmp/multifollow_pipe_${PPID}_$$_${numfiles}" + integer childpid=-1 + + # poll(1) information + integer fd="-1" + typeset events="POLLIN" + typeset revents="" + ) + + mkfifo "${files[${numfiles}].pipename}" + redirect {files[numfiles].fd}<>"${files[numfiles].pipename}" + + tail -f "${files[${numfiles}].name}" >"${files[${numfiles}].pipename}" & + files[${numfiles}].childpid=$! + + rm "${files[${numfiles}].pipename}" + + shift +done + +typeset do_poll=true + +# event loop +while true ; do + if ${do_poll} ; then + for ((i=0 ; i < numfiles ; i++ )) ; do + files[i].revents="" + done + poll files + fi + do_poll=true + + for ((i=0 ; i < numfiles ; i++ )) ; do + if [[ "${files[i].revents}" != "" ]] ; then + # todo: investigate why we have to use "do_poll" at all - AFAIK it + # should be sufficient to call "poll" and get "revents" set if there + # are any remaining data... + if read -t0 -u${files[i].fd} line ; then + print -- "#${i}: ${line}" + do_poll=false + fi + fi + done +done + +fatal_error "not reached." +# EOF. Index: src/lib/libshell/common/scripts/test_net_sctp.sh =================================================================== --- src/lib/libshell/common/scripts/test_net_sctp.sh (revision 0) +++ src/lib/libshell/common/scripts/test_net_sctp.sh (revision 1122) @@ -0,0 +1,67 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# test_net_sctp - a simple ksh93 SCTP demo +# + +export PATH=/bin:/usr/bin + +set -o xtrace +set -o errexit + +# declare variables +integer netfd +typeset request + +# print intro +print "# testing SCTP support" +print "# (via fetching the main page of http://www.sctp.org/ via SCTP)" + +# open sctp stream and print it's number +redirect {netfd}<>/dev/sctp/www.sctp.org/80 +print "sctp fd=${netfd}" + +# send HTTP request +request="GET / HTTP/1.1\r\n" +request+="Host: www.sctp.org\r\n" +request+="User-Agent: ksh93/test_net_sctp (2008-02-17; $(uname -s -r -p))\r\n" +request+="Connection: close\r\n" +print -u${netfd} -n -- "${request}\r\n" + +# print response to stdout +cat <&${netfd} + +# close connection +redirect {netfd}<&- + +print "#done" + +#EOF. Index: src/lib/libshell/common/scripts/termclock.sh =================================================================== --- src/lib/libshell/common/scripts/termclock.sh (revision 0) +++ src/lib/libshell/common/scripts/termclock.sh (revision 1122) @@ -0,0 +1,315 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# termclock - a simple analog clock for terminals +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +function fatal_error +{ + print -u2 "${progname}: $*" + exit 1 +} + +# cache tput values (to avoid |fork()|'ing a "tput" child every second) +function tput_cup +{ + # static variable as cache for "tput_cup" + typeset -S -A tput_cup_cache + + integer y="$1" x="$2" + nameref c="tput_cup_cache[\"${y}_${x}\"]" + + if [[ "$c" == "" ]] ; then + # fast path for known terminal types + if [[ ${TERM} == ~(Elr)(vt100|vt220|xterm|xterm-color|dtterm) ]] ; then + c="${ printf "\E[%d;%dH" y+1 x+1 ; }" + else + c="${ tput cup $y $x ; }" + fi + fi + + print -n -- "$c" + return 0 +} + +# Get terminal size and put values into a compound variable with the integer +# members "columns" and "lines" +function get_term_size +{ + nameref rect=$1 + + rect.columns=${ tput cols ; } || return 1 + rect.lines=${ tput lines ; } || return 1 + + return 0 +} + +function draw_clock +{ + float angle a + float x y + integer i=1 + + for(( angle=0.0 ; angle < 360. ; angle+=6 )) ; do + (( + a=angle/360.*(2*M_PI) , + + x=clock.len_x*cos(a) , + y=clock.len_y*sin(a) + )) + + tput_cup $(( y+clock.middle_y )) $(( x+clock.middle_x )) + + # add "mark" every 30 degrees + if (( int(angle)%30 == 0 )) ; then + print -n "$(((++i)%12+1))" + else + print -n "x" + fi + done + return 0 +} + +function draw_hand +{ + float angle="$1" a + typeset ch="$2" + float length="$3" + float x y + + (( a=angle/360.*(2*M_PI) )) + + for (( s=0.0 ; s < 10. ; s+=0.5 )) ; do + (( + x=(clock.len_x*(s/10.)*(length/100.))*cos(a) , + y=(clock.len_y*(s/10.)*(length/100.))*sin(a) + )) + + tput_cup $(( y+clock.middle_y )) $(( x+clock.middle_x )) + print -n -- "${ch}" + done + return 0 +} + +function draw_clock_hand +{ + nameref hand=$1 + draw_hand $(( 360.*(hand.val/hand.scale)-90. )) "${hand.ch}" ${hand.length} + return 0 +} + +function clear_clock_hand +{ + nameref hand=$1 + draw_hand $(( 360.*(hand.val/hand.scale)-90. )) " " ${hand.length} + return 0 +} + +function main_loop +{ + typeset c + + # note: we can't use subshells when writing to the double-buffer file because this + # will render the tput value cache useless + while true ; do + if ${init_screen} ; then + init_screen="false" + + get_term_size termsize || fatal_error "Couldn't get terminal size." + + (( + clock.middle_x=termsize.columns/2.-.5 , + clock.middle_y=termsize.lines/2.-.5 , + clock.len_x=termsize.columns/2-2 , + clock.len_y=termsize.lines/2-2 , + )) + + { + clear + draw_clock + } >&6 + fi + + { + (( ${ date +"hours.val=%H , minutes.val=%M , seconds.val=%S" ; } )) + + # small trick to get a smooth "analog" flair + (( + hours.val+=minutes.val/60. , + minutes.val+=seconds.val/60. + )) + + draw_clock_hand seconds + draw_clock_hand minutes + draw_clock_hand hours + + # move cursor to home position + tput_cup 0 0 + } >&6 + + 6<#((0)) + cat <&6 + + redirect 6<&- ; rm -f "${scratchfile}" ; redirect 6<>"${scratchfile}" + + c="" ; read -r -t ${update_interval} -n 1 c + if [[ "$c" != "" ]] ; then + case "$c" in + ~(Ei)q | $'\E') return 0 ;; + esac + fi + + { + clear_clock_hand hours + clear_clock_hand minutes + clear_clock_hand seconds + } >&6 + done +} + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${termclock_usage}" OPT '-?' + exit 2 +} + +# program start +builtin basename +builtin cat +builtin date +builtin printf +builtin rm + +typeset progname="${ basename "${0}" ; }" + +float -r M_PI=3.14159265358979323846 + +# terminal size rect +typeset termsize=( + integer columns=-1 + integer lines=-1 +) + +typeset init_screen="true" + +typeset clock=( + float middle_x + float middle_y + integer len_x + integer len_y +) + + +# set clock properties +typeset seconds=( + float val + typeset ch + float scale + integer length ) +typeset minutes=( + float val + typeset ch + float scale + integer length ) +typeset hours=( + float val + typeset ch + float scale + integer length ) + +seconds.length=90 seconds.scale=60 seconds.ch="s" +minutes.length=75 minutes.scale=60 minutes.ch="m" +hours.length=50 hours.scale=12 hours.ch="h" + +float update_interval=0.9 + +typeset -r termclock_usage=$'+ +[-?\n@(#)\$Id: termclock (Roland Mainz) 2008-06-08 \$\n] +[-author?Roland Mainz ] +[-author?David Korn ] +[+NAME?termclock - analog clock for terminals] +[+DESCRIPTION?\btermclock\b is an analog clock for terminals. + The termclock program displays the time in analog or digital + form. The time is continuously updated at a frequency which + may be specified by the user.] +[u:update?Update interval (defaults to 0.9 seconds).]:[interval] +[+SEE ALSO?\bksh93\b(1), \bxclock\b(1)] +' + +while getopts -a "${progname}" "${termclock_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + u) update_interval=${OPTARG} ;; + *) usage ;; + esac +done +shift $((OPTIND-1)) + +# prechecks +which tput >/dev/null || fatal_error "tput not found." +which mktemp >/dev/null || fatal_error "mktemp not found." +(( update_interval < 0. || update_interval > 7200. )) && fatal_error "invalid update_interval value." + +# create temporary file for double-buffering and register an EXIT trap +# to remove this file when the shell interpreter exits +scratchfile="${ mktemp /tmp/termclock.pid$$.XXXXXX ; }" +if [[ -z "${scratchfile}" ]] ; then fatal_error "Could not create temporary file name." ; fi +trap 'rm -f "${scratchfile}"' EXIT +rm -f "${scratchfile}" ; redirect 6<>"${scratchfile}" || fatal_error "Could not create temporary file." + +# regiter trap to handle window size changes +trap 'init_screen="true"' WINCH + +main_loop + +# exiting - put cursor below clock +tput_cup $((termsize.lines-2)) 0 + +exit 0 +# EOF. Index: src/lib/libshell/common/scripts/mandelbrotset1.sh =================================================================== --- src/lib/libshell/common/scripts/mandelbrotset1.sh (revision 0) +++ src/lib/libshell/common/scripts/mandelbrotset1.sh (revision 1122) @@ -0,0 +1,278 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# mandelbrotset1 - a simple mandelbrot set generation and +# parallel execution demo +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +function printmsg +{ + print -u2 "$*" +} + +function fatal_error +{ + print -u2 "${progname}: $*" + exit 1 +} + +# Get terminal size and put values into a compound variable with the integer +# members "columns" and "lines" +function get_term_size +{ + nameref rect=$1 + + rect.columns=${ tput cols ; } || return 1 + rect.lines=${ tput lines ; } || return 1 + + return 0 +} + +function print_color +{ + print -n -- "${symbollist:${1}:1}" + return 0 +} + +function mandelbrot +{ + float x=$1 + float y=$2 + float xx + float yy + float x1=$3 + float y1=$4 + integer iteration=$5 + integer max_iteration=$6 + float mag + + for (( mag=0 ; mag < max_mag && iteration < max_iteration ; iteration++ )) ; do + (( + xx=x*x , + yy=y*y , + mag=xx+yy , + y=x*y*2+y1 , + x=xx-yy+x1 + )) + done + + print -- ${iteration} + + return 0 +} + +# build mandelbrot image serially +function loop_serial +{ + for (( y=y_min ; y < y_max ; y+=stepwidth )) ; do + for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do + print_color ${ mandelbrot ${x} ${y} ${x} ${y} 1 ${symbollistlen} ; } + done + + print + done + + return 0 +} + +# build mandelbrot image using parallel worker jobs +function loop_parallel +{ + integer numjobs=0 + # the following calculation suffers from rounding errors + integer lines_per_job=$(( ((m_height+(numcpus-1)) / numcpus) )) + + printmsg $"# lines_per_job=${lines_per_job}" + printmsg $"# numcpus=${numcpus}" + + # "renice" worker jobs + set -o bgnice + + if [[ "${TMPDIR}" == "" ]] ; then + TMPDIR="/tmp" + fi + + # try to generate a job identifer prefix which is unique across multiple hosts + jobident="job_host_$(uname -n)pid_$$_ppid${PPID}" + + printmsg $"## prepare..." + for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do + rm -f "${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput" + + (( numjobs++ )) + done + + printmsg $"## running ${numjobs} children..." + for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do + ( + for (( ; y < y_max && lines_per_job-- > 0 ; y+=stepwidth )) ; do + for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do + print_color ${ mandelbrot ${x} ${y} ${x} ${y} 1 ${symbollistlen} ; } + done + + print + done >"${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput" + ) & + done + + printmsg $"## waiting for ${numjobs} children..." + wait + + printmsg $"## output:" + for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do + print -- "$( < "${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput")" + rm "${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput" + done + + return 0 +} + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${mandelbrotset1_usage}" OPT '-?' + exit 2 +} + +# main +builtin basename +builtin cat +builtin printf +builtin rm +builtin sleep +builtin uname # loop_parallel needs the ksh93 builtin version to generate unique job file names + +typeset progname="${ basename "${0}" ; }" + +float x_max +float x_min +float y_max +float y_min +float m_width +float m_height +float max_mag +float stepwidth +integer numcpus + +# terminal size rect +typeset termsize=( + integer columns=-1 + integer lines=-1 +) + +get_term_size termsize || fatal_error "Couldn't get terminal size." + +typeset symbollist=' .:0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%#' +typeset symbollistlen=$(( ${#symbollist} - 1)) +typeset mode="parallel" + +max_mag=400 +stepwidth=0.1 +numcpus=16 + +(( m_width=termsize.columns-1 , m_height=termsize.lines-2 )) + +typeset -r mandelbrotset1_usage=$'+ +[-?\n@(#)\$Id: mandelbrotset1 (Roland Mainz) 2008-06-08 \$\n] +[-author?Roland Mainz ] +[+NAME?mandelbrotset1 - generate mandelbrot set fractals with ksh93] +[+DESCRIPTION?\bmandelbrotset1\b mandelbrot set fractal generator + which runs either in serial or parallel mode (using multiple worker jobs).] +[w:width?Width of fractal.]:[width] +[h:height?Height of fractal.]:[height] +[s:symbols?Symbols to build the fractal from.]:[symbolstring] +[m:mag?Magnification level.]:[magnificationlevel] +[p:stepwidth?Width per step.]:[widthperstep] +[S:serial?Run in serial mode.] +[P:parallel?Run in parallel mode.] +[M:mode?Execution mode.]:[mode] +[C:numcpus?Number of processors used for parallel execution.]:[numcpus] +[+SEE ALSO?\bjuliaset1\b(1), \bksh93\b(1)] +' + +while getopts -a "${progname}" "${mandelbrotset1_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + w) m_width="${OPTARG}" ;; + h) m_height="${OPTARG}" ;; + s) symbollist="${OPTARG}" ;; + m) max_mag="${OPTARG}" ;; + p) stepwidth="${OPTARG}" ;; + S) mode="serial" ;; + P) mode="parallel" ;; + M) mode="${OPTARG}" ;; + C) numcpus="${OPTARG}" ;; + *) usage ;; + esac +done +shift $((OPTIND-1)) + +printmsg "# width=${m_width}" +printmsg "# height=${m_height}" +printmsg "# max_mag=${max_mag}" +printmsg "# stepwidth=${stepwidth}" +printmsg "# symbollist='${symbollist}'" +printmsg "# mode=${mode}" + +(( symbollistlen=${#symbollist}-1 )) + +(( + x_max=m_width*stepwidth/2. , + x_min=-x_max , + y_max=m_height*stepwidth/2. , + y_min=-y_max +)) + +case "${mode}" in + parallel) loop_parallel ; exit $? ;; + serial) loop_serial ; exit $? ;; + *) fatal_error $"Unknown mode \"${mode}\"." ;; +esac + +fatal_error "not reached." +# EOF. Index: src/lib/libshell/common/scripts/crawlsrccomments.sh =================================================================== --- src/lib/libshell/common/scripts/crawlsrccomments.sh (revision 0) +++ src/lib/libshell/common/scripts/crawlsrccomments.sh (revision 1122) @@ -0,0 +1,1205 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +# constants values for tokenizer/parser stuff +typeset -r ch=( + newline=$'\n' + tab=$'\t' + formfeed=$'\f' +) + +function fatal_error +{ + print -u2 "${progname}: $*" + exit 1 +} + +function printmsg +{ + print -u2 "$*" +} + + +function attrstrtoattrarray +{ +#set -o xtrace + typeset s="$1" + nameref aa=$2 # attribute array + integer aa_count=0 + integer aa_count=0 + typeset nextattr + integer currattrlen=0 + typeset tagstr + typeset tagval + + while (( ${#s} > 0 )) ; do + # skip whitespaces + while [[ "${s:currattrlen:1}" == ~(E)[[:blank:][:space:]] ]] ; do + (( currattrlen++ )) + done + s="${s:currattrlen:${#s}}" + + # anything left ? + (( ${#s} == 0 )) && break + + # Pattern tests: + #x="foo=bar huz=123" ; print "${x##~(E)[[:alnum:]_-:]*=[^[:blank:]\"]*}" + #x='foo="ba=r o" huz=123' ; print "${x##~(E)[[:alnum:]_-:]*=\"[^\"]*\"}" + #x="foo='ba=r o' huz=123" ; print "${x##~(E)[[:alnum:]_-:]*=\'[^\"]*\'}" + #x="foox huz=123" ; print "${x##~(E)[[:alnum:]_-:]*}" + # All pattern combined via eregex (w|x|y|z): + #x='foo="bar=o" huz=123' ; print "${x##~(E)([[:alnum:]_-:]*=[^[:blank:]\"]*|[[:alnum:]_-:]*=\"[^\"]*\"|[[:alnum:]_-:]*=\'[^\"]*\')}" + nextattr="${s##~(E)([[:alnum:]_-:]*=[^[:blank:]\"]*|[[:alnum:]_-:]*=\"[^\"]*\"|[[:alnum:]_-:]*=\'[^\"]*\'|[[:alnum:]_-:]*)}" + currattrlen=$(( ${#s} - ${#nextattr})) + + # add entry + tagstr="${s:0:currattrlen}" + if [[ "${tagstr}" == *=* ]] ; then + # normal case: attribute with value + + tagval="${tagstr#*=}" + + # strip quotes ('' or "") + if [[ "${tagval}" == ~(Elr)(\'.*\'|\".*\") ]] ; then + tagval="${tagval:1:${#tagval}-2}" + fi + + aa[${aa_count}]=( name="${tagstr%%=*}" value="${tagval}" ) + else + # special case for HTML where you have something like + aa[${aa_count}]=( name="${tagstr}" ) + fi + (( aa_count++ )) + (( aa_count > 1000 )) && fatal_error "$0: aa_count too large" # assert + done +} + +# XML document handler +function handle_xml_document +{ +#set -o xtrace + nameref callbacks=${1} + typeset tag_type="${2}" + typeset tag_value="${3}" + typeset tag_attributes="${4}" + nameref doc=${callbacks["arg_tree"]} + nameref nodepath="${stack.items[stack.pos]}" + nameref nodesnum="${stack.items[stack.pos]}num" + + case "${tag_type}" in + tag_comment) + nodepath[${nodesnum}]+=( + typeset tagtype="comment" + typeset tagvalue="${tag_value}" + ) + (( nodesnum++ )) + ;; + esac + +# print "xmltok: '${tag_type}' = '${tag_value}'" +} + +function xml_tok +{ + typeset buf="" + typeset namebuf="" + typeset attrbuf="" + typeset c="" + typeset isendtag # bool: true/false + typeset issingletag # bool: true/false (used for tags like "
") + nameref callbacks=${1} + + [[ ! -z "${callbacks["document_start"]}" ]] && ${callbacks["document_start"]} "${1}" "document_start" + + while IFS='' read -r -N 1 c ; do + isendtag=false + + if [[ "$c" == "<" ]] ; then + # flush any text content + if [[ "$buf" != "" ]] ; then + [[ ! -z "${callbacks["tag_text"]}" ]] && ${callbacks["tag_text"]} "${1}" "tag_text" "$buf" + buf="" + fi + + IFS='' read -r -N 1 c + if [[ "$c" == "/" ]] ; then + isendtag=true + else + buf="$c" + fi + IFS='' read -r -d '>' c + buf+="$c" + + # handle comments + if [[ "$buf" == ~(El)!-- ]] ; then + # did we read the comment completely ? + if [[ "$buf" != ~(Elr)!--.*-- ]] ; then + buf+=">" + while [[ "$buf" != ~(Elr)!--.*-- ]] ; do + IFS='' read -r -N 1 c || break + buf+="$c" + done + fi + + [[ ! -z "${callbacks["tag_comment"]}" ]] && ${callbacks["tag_comment"]} "${1}" "tag_comment" "${buf:3:${#buf}-5}" + buf="" + continue + fi + + # check if the tag starts and ends at the same time (like "
") + if [[ "${buf}" == ~(Er).*/ ]] ; then + issingletag=true + buf="${buf%*/}" + else + issingletag=false + fi + + # check if the tag has attributes (e.g. space after name) + if [[ "$buf" == ~(E)[[:space:][:blank:]] ]] ; then + namebuf="${buf%%~(E)[[:space:][:blank:]].*}" + attrbuf="${buf#~(E).*[[:space:][:blank:]]}" + else + namebuf="$buf" + attrbuf="" + fi + + if ${isendtag} ; then + [[ ! -z "${callbacks["tag_end"]}" ]] && ${callbacks["tag_end"]} "${1}" "tag_end" "$namebuf" + else + [[ ! -z "${callbacks["tag_begin"]}" ]] && ${callbacks["tag_begin"]} "${1}" "tag_begin" "$namebuf" "$attrbuf" + + # handle tags like
(which are start- and end-tag in one piece) + if ${issingletag} ; then + [[ ! -z "${callbacks["tag_end"]}" ]] && ${callbacks["tag_end"]} "${1}" "tag_end" "$namebuf" + fi + fi + buf="" + else + buf+="$c" + fi + done + + [[ ! -z "${callbacks["document_end"]}" ]] && ${callbacks["document_end"]} "${1}" "document_end" "exit_success" + + print # final newline to make filters like "sed" happy +} + +# enumerate comments in a shell (or shell-like) script +function enumerate_comments_shell +{ + set -o errexit + + typeset input_file="$1" + nameref comment_array="$2" + integer max_num_comments="$3" + integer ca=0 # index in "comment_array" + + integer res=0 + + typeset comment="" + + while (( res == 0 )) ; do + IFS='' read -r line + (( res=$? )) + + if [[ "${line}" == ~(El)#.* ]] ; then + comment+="${line#\#}${ch.newline}" + else + if [[ "$comment" != "" ]] ; then + comment_array[ca++]="${comment}" + comment="" + + if (( ca > max_num_comments )) ; then + break + fi + fi + fi + done <"${input_file}" + + return 0 +} + + +# enumerate comments in a troff document +function enumerate_comments_troff +{ + set -o errexit + + typeset input_file="$1" + nameref comment_array="$2" + integer max_num_comments="$3" + integer ca=0 # index in "comment_array" + + integer res=0 + + typeset comment="" + + while (( res == 0 )) ; do + IFS='' read -r line + (( res=$? )) + + if [[ "${line}" == ~(El)\.*\\\" ]] ; then + comment+="${line#~(El)\.*\\\"}${ch.newline}" + else + if [[ "$comment" != "" ]] ; then + comment_array[ca++]="${comment}" + comment="" + + if (( ca > max_num_comments )) ; then + break + fi + fi + fi + done <"${input_file}" + + return 0 +} + + +# enumerate comments in files which are preprocessed by +# CPP (e.g. C, C++, Imakefile etc.) +function enumerate_comments_cpp +{ + set -o errexit +# set -o nounset + + integer err=0 + + typeset input_file="$1" + nameref comment_array="$2" + integer max_num_comments="$3" + integer max_filesize_for_scan="$4" + integer ca=0 # index in "comment_array" + + typeset content + integer content_length + + integer file_pos # file position + typeset line_pos=( + integer x=0 # X position in line + integer y=0 # Y position in line (line number) + ) + typeset c c2 + + typeset comment + + typeset state=( + # C comment state + typeset in_c_comment=false + # C++ comment state + typeset cxx=( + typeset in_comment=false + typeset comment_continued=false + # position of current //-pos + typeset comment_pos=( + integer x=-1 + integer y=-1 + ) + # position of previous //-pos + typeset comment_prev_pos=( + integer x=-1 + integer y=-1 + ) + ) + # literal state + typeset in_sq_literal=false # single-quote literal + typeset in_dq_literal=false # double-quote literal + ) + + content="$(< "${input_file}")" + + # Truncate file to "max_filesize_for_scan" charatcters. + # This was originally added to work around a performance problem with + # the ${str:offset:chunksize} operator which scales badly in ksh93 + # version 's' with the number of characters + if (( ${#content} > max_filesize_for_scan )) ; then + print -u2 -f "## WARNING: File '%s' truncated to %d characters\n" \ + "${input_file}" \ + max_filesize_for_scan + content="${content:0:max_filesize_for_scan}" + fi + content_length=${#content} + + # Iterate through the source code. The last character + # (when file_pos == content_length) will be empty to indicate + # EOF (this is needed for cases like when + # a C++ comment is not terminated by a newline... ;-/) + for (( file_pos=0 ; file_pos <= content_length ; file_pos++ )) ; do + c2="${content:file_pos:2}" + c="${c2:0:1}" + + if [[ "$c" == "${ch.newline}" ]] ; then + (( line_pos.x=0, line_pos.y++ )) + else + (( line_pos.x++ )) + fi + + if ${state.in_c_comment} ; then + if [[ "$c2" == "*/" ]] ; then + (( file_pos++, line_pos.x++ )) + state.in_c_comment=false + + # flush comment text + comment_array[ca++]="${comment}" + comment="" + + if (( ca > max_num_comments )) ; then + break + fi + else + comment+="$c" + fi + elif ${state.cxx.in_comment} ; then + if [[ "$c" == "${ch.newline}" || "$c" == "" ]] ; then + state.cxx.in_comment=false + + # flush comment text + if ${state.cxx.comment_continued} ; then + comment_array[ca-1]+="${ch.newline}${comment}" + (( state.cxx.comment_prev_pos.x=state.cxx.comment_pos.x , + state.cxx.comment_prev_pos.y=state.cxx.comment_pos.y )) + else + comment_array[ca++]="${comment}" + (( state.cxx.comment_prev_pos.x=state.cxx.comment_pos.x , + state.cxx.comment_prev_pos.y=state.cxx.comment_pos.y )) + fi + comment="" + + if (( ca > max_num_comments )) ; then + break + fi + else + comment+="$c" + fi + elif ${state.in_sq_literal} ; then + if [[ "$c" == "'" && "${content:file_pos-1:1}" != '\' ]] ; then + state.in_sq_literal=false + fi + elif ${state.in_dq_literal} ; then + if [[ "$c" == '"' && "${content:file_pos-1:1}" != '\' ]] ; then + state.in_dq_literal=false + fi + else + if [[ "$c2" == "/*" ]] ; then + (( file_pos++, line_pos.x++ )) + state.in_c_comment=true + comment="" + elif [[ "$c2" == "//" ]] ; then + (( file_pos++, line_pos.x++ )) + if (( state.cxx.comment_prev_pos.x == line_pos.x && \ + state.cxx.comment_prev_pos.y == (line_pos.y-1) )) ; then + state.cxx.comment_continued=true + else + state.cxx.comment_continued=false + fi + (( state.cxx.comment_pos.x=line_pos.x , state.cxx.comment_pos.y=line_pos.y )) + state.cxx.in_comment=true + comment="" + elif [[ "$c" == "'" && "${content:file_pos-1:1}" != '\' ]] ; then + state.in_sq_literal=true + elif [[ "$c" == '"' && "${content:file_pos-1:1}" != '\' ]] ; then + state.in_dq_literal=true + fi + fi + done + + if [[ "$comment" != "" ]] ; then + print -u2 "## ERROR: Comment text buffer not empty at EOF." + err=1 + fi + + if ${state.in_c_comment} ; then + print -u2 "## ERROR: C comment did not close before EOF." + err=1 + fi + + if ${state.cxx.in_comment} ; then + print -u2 "## ERROR: C++ comment did not close before EOF." + err=1 + fi + + if ${state.in_dq_literal} ; then + print -u2 "## ERROR: Double-quoted literal did not close before EOF." + err=1 + fi + + # We treat this one only as warning since things like "foo.html.cpp" may + # trigger this condition accidently + if ${state.in_sq_literal} ; then + print -u2 "## WARNING: Single-quoted literal did not close before EOF." + fi + + return $err +} + +# determine file type +function get_file_format +{ + set -o errexit + + typeset filename="$1" + nameref file_format="$2" + + typeset fileeval # evaluation result of /usr/bin/file + + # check whether "filename" is a plain, readable file + [[ ! -f "$filename" ]] && return 1 + [[ ! -r "$filename" ]] && return 1 + + # In theory this code would exclusively look at the contents of + # the file to figure out it's file format - unfortunately + # /usr/bin/file is virtually useless (the heuristics, matching + # and output unreliable) for many file formats and therefore + # we have to do a multi-stage approach which looks + # at the file's content if possible and at the filename + # otherwise. Fun... ;-( + + # pass one: Find matches for file formats where /usr/bin/file + # is known to be unreliable: + case "$filename" in + *.[ch] | *.cpp | *.cc | *.cxx | *.hxx) + file_format="c_source" + return 0 + ;; + *Imakefile) + file_format="imakefile" + return 0 + ;; + *Makefile) + file_format="makefile" + return 0 + ;; + esac + + # pass two: match by file content via /usr/bin/file + fileeval="$(LC_ALL=C /usr/bin/file "$filename")" + case "$fileeval" in + ~(E)roff) + file_format="troff" + return 0 + ;; + ~(E)html\ document) + file_format="html" + return 0 + ;; + ~(E)sgml\ document) + file_format="sgml" + return 0 + ;; + ~(E)executable.*(shell|(/|/r|/pf)(sh|ksh|ksh93|rksh93|dtksh|tksh|bash))\ script) + file_format="shell" + return 0 + ;; + ~(E)executable.*/perl\ script) + file_format="perl" + return 0 + ;; + esac + + # pass three: fallhack to filename matching + case "$filename" in + *.man) + file_format="troff" + return 0 + ;; + *.html) + file_format="html" + return 0 + ;; + *.sgml) + file_format="sgml" + return 0 + ;; + *.xml) + file_format="xml" + return 0 + ;; + *.png) + file_format="image_png" + return 0 + ;; + *.xcf) + file_format="image_xcf" + return 0 + ;; + *.shar) + file_format="archive_shell" + return 0 + ;; + *.sh) + file_format="shell" + return 0 + ;; + *.pcf) + file_format="font_pcf" + return 0 + ;; + *.bdf) + file_format="font_bdf" + return 0 + ;; + *.pmf) + file_format="font_pmf" + return 0 + ;; + *.ttf | *.otf) + file_format="font_ttf" + return 0 + ;; + *.pfa | *.pfb) + file_format="font_postscript" + return 0 + ;; + esac + + return 1 +} + +function extract_comments +{ + set -o errexit + + nameref records="$1" + typeset filename="$2" + integer max_num_comments="$3" + integer max_filesize_for_scan="$4" + + typeset datatype="" + + records[${filename}]=( + typeset filename="$filename" + + typeset fileformat_found="false" # "true" or "false" + typeset file_format="" + + typeset -A hashsum + + typeset comments_parsed="false" # "true" or "false" + typeset -a comments + ) + + records[${filename}].hashsum["md5"]="$(sum -x md5 < "$filename")" + records[${filename}].hashsum["sha1"]="$(sum -x sha1 < "$filename")" + + if get_file_format "$filename" datatype ; then + records[${filename}].fileformat_found="true" + records[${filename}].file_format="$datatype" + else + return 1 + fi + + case "$datatype" in + c_source|imakefile) + enumerate_comments_cpp "${filename}" "records[${filename}].comments" ${max_num_comments} ${max_filesize_for_scan} && \ + records[${filename}].comments_parsed=true + ;; + shell|makefile) + enumerate_comments_shell "${filename}" "records[${filename}].comments" ${max_num_comments} ${max_filesize_for_scan} && \ + records[${filename}].comments_parsed=true + ;; + troff) + enumerate_comments_troff "${filename}" "records[${filename}].comments" ${max_num_comments} ${max_filesize_for_scan} && \ + records[${filename}].comments_parsed=true + ;; + # NOTE: Disabled for now + #xml|html|sgml) + # enumerate_comments_xml "${filename}" "records[${filename}].comments" ${max_num_comments} ${max_filesize_for_scan} && \ + # records[${filename}].comments_parsed=true + # ;; + esac + + return 0 +} + +# parse HTTP return code, cookies etc. +function parse_http_response +{ + nameref response="$1" + typeset h statuscode statusmsg i + + # we use '\r' as additional IFS to filter the final '\r' + IFS=$' \t\r' read -r h statuscode statusmsg # read HTTP/1.[01] + [[ "$h" != ~(Eil)HTTP/.* ]] && { print -u2 -f "%s: HTTP/ header missing\n" "$0" ; return 1 ; } + [[ "$statuscode" != ~(Elr)[0-9]* ]] && { print -u2 -f "%s: invalid status code\n" "$0" ; return 1 ; } + response.statuscode="$statuscode" + response.statusmsg="$statusmsg" + + # skip remaining headers + while IFS='' read -r i ; do + [[ "$i" == $'\r' ]] && break + + # strip '\r' at the end + i="${i/~(Er)$'\r'/}" + + case "$i" in + ~(Eli)Content-Type:.*) + response.content_type="${i/~(El).*:[[:blank:]]*/}" + ;; + ~(Eli)Content-Length:[[:blank:]]*[0-9]*) + integer response.content_length="${i/~(El).*:[[:blank:]]*/}" + ;; + ~(Eli)Transfer-Encoding:.*) + response.transfer_encoding="${i/~(El).*:[[:blank:]]*/}" + ;; + esac + done + + return 0 +} + +function cat_http_body +{ + typeset emode="$1" + typeset hexchunksize="0" + integer chunksize=0 + + if [[ "${emode}" == "chunked" ]] ; then + while IFS=$'\r' read hexchunksize && + [[ "${hexchunksize}" == ~(Elri)[0-9abcdef]* ]] && + (( chunksize=16#${hexchunksize} )) && (( chunksize > 0 )) ; do + dd bs=1 count="${chunksize}" 2>/dev/null + done + else + cat + fi + + return 0 +} + +function cat_http +{ + typeset protocol="${1%://*}" + typeset path1="${1#*://}" # "http://foo.bat.net/x/y.html" ----> "foo.bat.net/x/y.html" + + typeset host="${path1%%/*}" + typeset path="${path1#*/}" + typeset port="${host##*:}" + + integer netfd + typeset -C httpresponse # http response + + # If URL did not contain a port number in the host part then look at the + # protocol to get the port number + if [[ "${port}" == "${host}" ]] ; then + case "${protocol}" in + "http") port=80 ;; + *) port="$(getent services "${protocol}" | sed 's/[^0-9]*//;s/\/.*//')" ;; + esac + else + host="${host%:*}" + fi + + printmsg "protocol=${protocol} port=${port} host=${host} path=${path}" + + # prechecks + [[ "${protocol}" == "" ]] && { print -u2 -f "%s: protocol not set.\n" "$0" ; return 1 ; } + [[ "${port}" == "" ]] && { print -u2 -f "%s: port not set.\n" "$0" ; return 1 ; } + [[ "${host}" == "" ]] && { print -u2 -f "%s: host not set.\n" "$0" ; return 1 ; } + [[ "${path}" == "" ]] && { print -u2 -f "%s: path not set.\n" "$0" ; return 1 ; } + + # open TCP channel + redirect {netfd}<>"/dev/tcp/${host}/${port}" + (( $? != 0 )) && { print -u2 -f "%s: Couldn't open %s\n" "$0" "${1}" ; return 1 ; } + + # send HTTP request + request="GET /${path} HTTP/1.1\r\n" + request+="Host: ${host}\r\n" + request+="User-Agent: crawlsrccomments/ksh93 (2008-06-14; $(uname -s -r -p))\r\n" + request+="Connection: close\r\n" + print -n -- "${request}\r\n" >&${netfd} + + # collect response and send it to stdout + parse_http_response httpresponse <&${netfd} + cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} + + # close connection + redirect {netfd}<&- + + return 0 +} + +function print_stats +{ + set -o errexit + + # gather some statistics + typeset stats=( + integer files_with_comments=0 + integer files_without_comments=0 + + integer files_without_known_format=0 + + integer files_with_license_info=0 + integer files_without_license_info=0 + + integer total_num_files=0 + ) + + for i in $(printf "%s\n" "${!records[@]}" | sort) ; do + if "${records[$i].comments_parsed}" ; then + (( stats.files_with_comments++ )) + else + (( stats.files_without_comments++ )) + fi + + if ! "${records[$i].fileformat_found}" ; then + (( stats.files_without_known_format++ )) + fi + + if "${records[$i].license_info_found}" ; then + (( stats.files_with_license_info++ )) + else + (( stats.files_without_license_info++ )) + fi + + (( stats.total_num_files++ )) + done + + printf "%B\n" stats + return 0 +} + + +function print_comments_plain +{ + set -o errexit + + nameref records=$1 + nameref options=$2 + typeset i j + + for i in $(printf "%s\n" "${!records[@]}" | sort) ; do + nameref node=records[$i] + + if [[ "${options.filepattern.accept}" != "" ]] && \ + [[ "${node.filename}" != ${options.filepattern.accept} ]] ; then + continue + fi + if [[ "${options.filepattern.reject}" != "" ]] && \ + [[ "${node.filename}" == ${options.filepattern.reject} ]] ; then + continue + fi + + node.license_info_found=false + + if ! "${node.comments_parsed}" ; then + continue + fi + + for j in "${!node.comments[@]}" ; do + typeset s="${node.comments[$j]}" + typeset match=false + + if [[ "${options.commentpattern.accept}" != "" ]] && \ + [[ "$s" == ${options.commentpattern.accept} ]] ; then + match=true + fi + if [[ "${options.commentpattern.reject}" != "" ]] && \ + [[ "$s" == ${options.commentpattern.reject} ]] ; then + match=false + fi + + if "${match}" ; then + printf "\f#### filename='%s',\tcomment=%s\n" "${node.filename}" "$j" + printf "%s\n" "$s" + node.license_info_found=true + fi + done + + if ! "${node.license_info_found}" ; then + printf "## no match found in '%s'," "${node.filename}" + printf "comments_parsed=%s, fileformat_found=%s, file_format=%s\n" \ + "${node.comments_parsed}" \ + "${node.fileformat_found}" \ + "${node.file_format}" + fi + done + + return 0 +} + +function print_comments_duplicates_compressed +{ + set -o errexit + + nameref records=$1 + nameref options=$2 + typeset i j + typeset -A hashed_comments + integer num_hashed_comments + + for i in $(printf "%s\n" "${!records[@]}" | sort) ; do + nameref node=records[$i] + + if [[ "${options.filepattern.accept}" != "" ]] && \ + [[ "${node.filename}" != ${options.filepattern.accept} ]] ; then + continue + fi + if [[ "${options.filepattern.reject}" != "" ]] && \ + [[ "${node.filename}" == ${options.filepattern.reject} ]] ; then + continue + fi + + node.license_info_found=false + + if ! "${node.comments_parsed}" ; then + continue + fi + + for j in "${!node.comments[@]}" ; do + typeset s="${node.comments[$j]}" + typeset match=false + + if [[ "${options.commentpattern.accept}" != "" ]] && \ + [[ "$s" == ${options.commentpattern.accept} ]] ; then + match=true + fi + if [[ "${options.commentpattern.reject}" != "" ]] && \ + [[ "$s" == ${options.commentpattern.reject} ]] ; then + match=false + fi + + + if "${match}" ; then + typeset -l hashstring # lowercase + + # compress the comment (e.g. convert whiteapces and '.,:;()"' to newline characters) ... + hashstring="${s//+([\n\r\t\v*#.,:;\(\)\"[:space:][:blank:]])/${ch.newline}}" + # ... and then create a MD5 hash from this string + hash="$(sum -x md5 <<<"${hashstring}")" + + nameref hc_node=hashed_comments[${hash}] + + if [[ "${hc_node}" == "" ]] ; then + # build node if there isn't one yet + typeset -a hc_node.fileids + typeset hc_node.comment="$s" + fi + + hc_node.fileids+=( "$(printf "%s (md5='%s', sha1='%s')\n" "${node.filename}" "${node.hashsum["md5"]}" "${node.hashsum["sha1"]}")" ) + + node.license_info_found=true + fi + done + + if ! "${node.license_info_found}" ; then + printf "## no match found in " + printf "%s (md5='%s', sha1='%s'), " "${node.filename}" "${node.hashsum["md5"]}" "${node.hashsum["sha1"]}" + printf "comments_parsed=%s, fileformat_found=%s, file_format=%s\n" \ + "${node.comments_parsed}" \ + "${node.fileformat_found}" \ + "${node.file_format}" + fi + done + + # print comments and all fileids (filename+hash sums) which include this comment + for i in "${!hashed_comments[@]}" ; do + printf "\f## The comment (ID=%s) ..." "${i}" + printf "\n-- snip --" + printf "\n%s" "${hashed_comments[${i}].comment}" + printf "\n-- snip --" + printf "\n... applies to the following files:\n" + printf "\t%s\n" "${hashed_comments[${i}].fileids[@]}" # printf repeats the format string for each array memeber + done + + return 0 +} + +function do_crawl +{ + set -o errexit + + typeset options=( + integer max_filesize_for_scan=$((256*1024)) + integer max_num_comments=$((2**62)) # FIXME: This should be "+Inf" (=Infinite) + ) + + shift + while getopts -a "${progname}" "${do_crawl_usage}" OPT "$@" ; do + printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + S) options.max_filesize_for_scan="${OPTARG}" ;; + N) options.max_num_comments="${OPTARG}" ;; + *) usage do_crawl_usage ;; + esac + done + shift $((OPTIND-1)) + + typeset scan=( + typeset -A records + ) + + # read filenames from stdin + while read i ; do + printf "## scanning %s ...\n" "$i" + extract_comments scan.records "$i" ${options.max_num_comments} ${options.max_filesize_for_scan} || true + done + + # print compound variable array (we strip the "typeset -A records" for now) + printf "%B\n" scan | + sed $'s/^#.*$//;s/^\(//;s/^\)//;s/^\ttypeset -A records=\(//;s/^\t\)//' >"crawlsrccomments_extracted_comments.cpv" + + print "# Wrote results to crawlsrccomments_extracted_comments.cpv" + + return 0 +} + +function do_getcomments +{ + set -o errexit + + # vars + typeset scan=( + typeset -A records + ) + typeset database + typeset tmp + + typeset options=( + typeset database="crawlsrccomments_extracted_comments.cpv" + + typeset print_stats=false + typeset zapduplicates=false + typeset filepattern=( + typeset accept="*" + typeset reject="" + ) + typeset commentpattern=( + typeset accept="~(Ei)(license|copyright)" + typeset reject="" + ) + ) + + shift + while getopts -a "${progname}" "${do_getcomments_usage}" OPT "$@" ; do + # printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + c) options.commentpattern.accept="${OPTARG}" ;; + C) options.commentpattern.reject="${OPTARG}" ;; + D) options.database="${OPTARG}" ;; + l) options.filepattern.accept="${OPTARG}" ;; + L) options.filepattern.reject="${OPTARG}" ;; + S) options.print_stats=true ;; + +S) options.print_stats=false ;; + Z) options.zapduplicates=true ;; + +Z) options.zapduplicates=false ;; + *) usage do_getcomments_usage ;; + esac + done + shift $((OPTIND-1)) + + # array of temporary files which should be cleaned-up upon exit + typeset -a tmpfiles + trap 'set -o errexit ; print -u2 "# Cleaning up..." ; ((${#tmpfiles[@]} > 0)) && rm -- "${tmpfiles[@]}" ; print -u2 "# Done."' EXIT + + # Support for HTTP URLs + if [[ "${options.database}" == ~(El)http://.* ]] ; then + database="/tmp/extract_license_cat_http_${PPID}_$$.tmp" + tmpfiles+=( "${database}" ) + print -u2 "# Loading URL..." + cat_http "${options.database}" >"${database}" + print -u2 "# Loading URL done." + else + database="${options.database}" + fi + + if [[ ! -r "${database}" ]] ; then + fatal_error "Can't read ${database}." + fi + + # Support for compressed database files + case "$(LC_ALL=C /usr/bin/file "${database}")" in + *bzip2*) + tmp="/tmp/extract_license_bzcat_${PPID}_$$.tmp" + tmpfiles+=( "${tmp}" ) + print -u2 "# Uncompressing data (bzip2) ..." + bzcat <"${database}" >"${tmp}" + print -u2 "# Uncompression done." + database="${tmp}" + ;; + *gzip*) + tmp="/tmp/extract_license_bzcat_${PPID}_$$.tmp" + tmpfiles+=( "${tmp}" ) + print -u2 "# Uncompressing data (gzip) ..." + gunzip -c <"${database}" >"${tmp}" + print -u2 "# Uncompression done." + database="${tmp}" + ;; + esac + + # Read compound variable which contain all recorded comments + print -u2 "# reading records..." + { + printf "(" + cat "${database}" + printf ")\n" + } | read -C scan.records || fatal_error 'Error reading data.' + print -u2 -f "# reading %d records done.\n" "${#scan.records[@]}" + + # print comments + print -u2 "# processing data..." + print "## comments start:" + if "${options.zapduplicates}" ; then + print_comments_duplicates_compressed scan.records options + else + print_comments_plain scan.records options + fi + print "## comments end" + print -u2 "# processing data done." + + if "${options.print_stats}" ; then + print_stats + fi + + return 0 +} + +function usage +{ + nameref usagemsg=$1 + OPTIND=0 + getopts -a "${progname}" "${usagemsg}" OPT '-?' + exit 2 +} + +typeset -r do_getcomments_usage=$'+ +[-?\n@(#)\$Id: getcomments (Roland Mainz) 2008-06-14 \$\n] +[-author?Roland Mainz ] +[+NAME?getcomments - extract license information from source files] +[+DESCRIPTION?\bgetcomments\b is a small utilty script which extracts + license information from the "\bgetcomments\b"-database + file created by \bcrawl\b. The script allows various + filters (see options below) to be applied on the database] +[+?The license extraction is done in two steps - first a crawler script + called \bcrawl\b will scan all source files, extract + the comments and stores this information in a "database" file called + "crawlsrccomments_extracted_comments.cpv" and then \bextract_license\b allows + queries on this database.] +[D:database?Database file for input (either file or http://-URL).]:[database] +[l:acceptfilepattern?Process only files which match pattern.]:[pattern] +[L:rejectfilepattern?Process only files which do not match pattern.]:[pattern] +[c:acceptcommentpattern?Match comments which match pattern. Defaults to ~(Ei)(license|copyright)]:[pattern] +[C:rejectcommentpattern?Discard comments which match pattern. Defaults to ""]:[pattern] +[S:stats?Print statistics.] +[Z:zapsimilar?Combine similar/duplicate comments in the report.] +[+SEE ALSO?\bksh93\b(1), \bsvcprop\b(1)] +' + +typeset -r do_crawl_usage=$'+ +[-?\n@(#)\$Id: crawl (Roland Mainz) 2008-06-14 \$\n] +[-author?Roland Mainz ] +[+NAME?crawl - crawl comment information from source files] +[+DESCRIPTION?\bcrawl\b is a small utilty script which reads + a list of source code files from stdin, determinates the type of + syntax used by these files and then extracts + comments from the source code and stores this information into a + "database"-like file called "crawlsrccomments_extracted_comments.cpv" which can then + be processed by \bextract_license\b or similar processing tools.] +[S:scanmaxcharacters?Scan a maximum number of numchars characters for comments. + Defaults to 256K characters.]:[numchars] +[N:maxnumcomments?Maximum numbers of comments to crawl. Defaults to "+Infinite"]:[numcomments] +[+SEE ALSO?\bksh93\b(1), \bsvcprop\b(1)] +' + +typeset -r crawlsrccomments_usage=$'+ +[-?\n@(#)\$Id: crawlsrccomments (Roland Mainz) 2008-06-14 \$\n] +[-author?Roland Mainz ] +[+NAME?crawlsrccomments - extract and filter comment information from source files] +[+DESCRIPTION?\bcrawlsrccomments\b is a small utilty script which reads + a list of source code files from stdin, determinates the type of + syntax used by these files and then extracts + comments from the source code and stores this information into a + "database"-like file called "crawlsrccomments_extracted_comments.cpv" which can then + be processed by \bextract_license\b or similar processing tools.] + +[crawl|getcomments] options + +[+SEE ALSO?\bksh93\b(1), \bsvcprop\b(1)] +' + + +# program start +builtin basename +builtin cat +builtin date +builtin uname +builtin rm +builtin sum || fatal_error "sum builtin not found." + +# exit at the first error we hit +set -o errexit + +typeset progname="${ basename "${0}" ; }" + +while getopts -a "${progname}" "${crawlsrccomments_usage}" OPT ; do + # printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + *) usage crawlsrccomments_usage ;; + esac +done +shift $((OPTIND-1)) + +typeset cmd="$1" + +case "$cmd" in + "crawl") + progname+=" ${cmd}" + do_crawl "$@" + exit $? + ;; + "getcomments") + progname+=" ${cmd}" + do_getcomments "$@" + exit $? + ;; + *) + usage crawlsrccomments_usage + ;; +esac + +fatal_error "not reached." +# EOF. Index: src/lib/libshell/common/scripts/filemutexdemo1.sh =================================================================== --- src/lib/libshell/common/scripts/filemutexdemo1.sh (revision 0) +++ src/lib/libshell/common/scripts/filemutexdemo1.sh (revision 1122) @@ -0,0 +1,269 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# filemutexdemo1 - a simple locking demo which supports read/write +# locks and critical sections (like JAVA's "syncronized" keyword) +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +# Definition for a mutex which uses the filesystem for locking +typeset -T filemutex_t=( + typeset name + + typeset lock_dirname + + typeset locked_exclusive="false" + typeset locked_shared="false" + + # keep track of subshell level. The problem is that we do not know a + # way to figure out whether someone calls "unlock" in a subshell and then + # leaves the subshell and calls "unlock" again + integer subshell=-1 + + typeset lock_dirname + + # create a filemutex instance (including lock directory) + function create + { + # make sure we return an error if the init didn't work + set -o errexit + + [[ "$1" == "" ]] && return 1 + + _.name="$1" + _.lock_dirname="/tmp/filemutex_t_${_.name}.lock" + + mkdir "${_.lock_dirname}" + + # last entry, used to mark the mutex as initalised+valid + (( _.subshell=.sh.subshell )) + return 0 + } + + # use a filemutex instance (same as "create" but without creating + # the lock directory) + function create_child + { + # make sure we return an error if the init didn't work + set -o errexit + + [[ "$1" == "" ]] && return 1 + + _.name="$1" + _.lock_dirname="/tmp/filemutex_t_${_.name}.lock" + + # last entry, used to mark the mutex as initalised+valid + (( _.subshell=.sh.subshell )) + return 0 + } + + function check_subshell + { + (( _.subshell == .sh.subshell )) && return 0 + print -u2 -f "filemutex_t.%s(%s): Wrong subshell level\n" "$1" "${_.name}" + return 1 + } + + function try_lock_shared + { + _.check_subshell "try_lock_shared" || return 1 + + mkdir "${_.lock_dirname}/shared_${PPID}_$$" 2>/dev/null || return 1 + _.locked_shared="true" + return 0 + } + + function lock_shared + { + float interval=0.2 + + _.check_subshell "lock_shared" || return 1 + + while ! _.try_lock_shared ; do sleep ${interval} ; (( interval+=interval/10. )) ; done + return 0 + } + + function try_lock_exclusive + { + _.check_subshell "try_lock_exclusive" || return 1 + + rmdir "${_.lock_dirname}" 2>/dev/null || return 1 + _.locked_exclusive="true" + return 0 + } + + function lock_exclusive + { + float interval=0.2 + + _.check_subshell "lock_exclusive" || return 1 + + while ! _.try_lock_exclusive ; do sleep ${interval} ; (( interval+=interval/10. )) ; done + return 0 + } + + # critical section support (like java's "synchronized" keyword) + function synchronized + { + integer retcode + + _.check_subshell "synchronized" || return 1 + + _.lock_exclusive + + "$@" + (( retcode=$? )) + + _.unlock + + return ${retcode} + } + + # critical section support with shared lock + function synchronized_shared + { + integer retcode + + _.check_subshell "synchronized_shared" || return 1 + + _.lock_shared + + "$@" + (( retcode=$? )) + + _.unlock + + return ${retcode} + } + + function unlock + { + # return an error if rmdir/mkdir/check_subshell fail... + set -o errexit + + _.check_subshell "unlock" + + if ${_.locked_shared} ; then + rmdir "${_.lock_dirname}/shared_${PPID}_$$" + _.locked_shared="false" + return 0 + elif ${_.locked_exclusive} ; then + mkdir "${_.lock_dirname}" + _.locked_exclusive="false" + return 0 + fi + + print -u2 -f "filemutex_t.unlock(%s): mutex '%s' not locked." "$1" "${_.name}" + return 1 + } + + # destroy mutex if noone is using it anymore (not the same as "unset" !!)) + function destroy + { + _.check_subshell "destroy" || return 1 + + (${_.locked_exclusive} || ${_.locked_shared}) && _.unlock + rmdir "${_.lock_dirname}" + return 0 + } +) + +# main +builtin mkdir +builtin rmdir + +print "## Start." + +typeset -r mymutexname="hello_world" + +filemutex_t fs + +fs.create "${mymutexname}" || print -u2 "Mutex init failed." + +print "# Starting child which keeps an exclusive lock for 10 seconds..." +( + filemutex_t child_fs + + child_fs.create_child "${mymutexname}" + + child_fs.lock_exclusive + sleep 10 + child_fs.unlock +) & + +sleep 1 + +printf "%T: # Waiting to obtain a shared lock...\n" +fs.lock_shared +printf "%T: # Obtained shared lock\n" + +printf "fs.locked_exclusive=%s, fs.locked_shared=%s\n" "${fs.locked_exclusive}" "${fs.locked_shared}" + +ls -lad /tmp/filemutex*/* + +printf "%T: # Executing child which runs printf '|%%s|\\\n' 'hello' 'world' inside a synchronized section\n" +( + filemutex_t child_fs + + child_fs.create_child "${mymutexname}" + + child_fs.synchronized printf '|%s|\n' 'hello' 'world' +) & + +printf "%T: # Sleeping 5 secs while holding the shared lock...\n" +sleep 5. + +printf "%T: # Releasing shared lock...\n" +fs.unlock + +sleep 5. +print "# Destroying lock..." +fs.destroy + +print "## Done." + +exit 0 Index: src/lib/libshell/common/scripts/primenumbers1.sh =================================================================== --- src/lib/libshell/common/scripts/primenumbers1.sh (revision 0) +++ src/lib/libshell/common/scripts/primenumbers1.sh (revision 1122) @@ -0,0 +1,117 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# primenumbers1 - a simple prime number generator +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + + +# check whether arg1 is a prime number via comparing it against the "pn" array +function is_prime +{ + integer i + integer num=$1 + float max_pn + + (( max_pn=sqrt(num)+1. )) + + for (( i=0 ; i < num_pn && pn[i] < max_pn ; i++)) ; do + (( num % pn[i] == 0 )) && return 1; + done + return 0 +} + +# main +set -o errexit + +# get arguments +integer max_prime=$1 # maximum prime number +typeset outputformat=$2 + +# variables +integer -a pn # integer array for the prime numbers +integer num_pn=1 # number of prime numbers +integer n # current number which should be tested +pn[0]=2 # start value + +# prechecks +(( max_prime > 1 )) || { print -u2 -f "%s: requires a positive integer as first input.\n" "$0" ; exit 1 ; } + +# calculate prime numbers +printf $"# %s: Calculating prime numbes from 1 to %i\n" "${ date '+%T' ; }" max_prime 1>&2 + +for (( n=3 ; n < max_prime ; n+=2 )) ; do + if is_prime $n ; then + (( pn[num_pn++]=n )) + fi +done + +# print results +printf $"# %s: Calculation done, printing results:\n" "${ date '+%T' ; }" 1>&2 + +for (( n=0 ; n < num_pn ; n++ )) ; do + # print prime number + case ${outputformat} in + block) + printf $"%i$( (( n % 8 == 0 )) && print -r '\n' || print -r ',\t')" pn[n] + ;; + line) + printf $"%i\n" pn[n] + ;; + *) + printf $"prime %i:\t%i\n" n pn[n] + ;; + esac +done + +if [[ ${outputformat} == "block" ]] && (( n % 8 != 1 )); then + print +fi + +printf $"# %s: Done.\n" "${ date '+%T' ; }" 1>&2 + +#EOF. Index: src/lib/libshell/common/scripts/gnaw.sh =================================================================== --- src/lib/libshell/common/scripts/gnaw.sh (revision 0) +++ src/lib/libshell/common/scripts/gnaw.sh (revision 1122) @@ -0,0 +1,1034 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# gnaw - a simple ksh93 technology demo +# +# Note that this script has been written with the main idea to show +# many of ksh93's new features (comparing to ksh88/bash) and not +# as an example of efficient&&clean script code (much of the code +# could be done more efficient using compound variables, this script +# focus is the usage of associative arrays). +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +function print_setcursorpos +{ + print -n -- "${vtcode[cup_${1}_${2}]}" +} + +function beep +{ + ${quiet} || print -n -- "${vtcode["bel"]}" +} + +function fatal_error +{ + print -u2 "${progname}: $*" + exit 1 +} + +# Get terminal size and put values into a compound variable with the integer +# members "columns" and "lines" +function get_term_size +{ + nameref rect=$1 + + rect.columns=${ tput cols ; } || return 1 + rect.lines=${ tput lines ; } || return 1 + + return 0 +} + +function print_levelmap +{ + integer screen_y_offset=$1 + integer start_y_pos=$2 # start at this line in the map + integer max_numlines=$3 # maximum lines we're allowed to render + integer x + integer y + typeset line="" + + print_setcursorpos 0 ${screen_y_offset} + + for (( y=start_y_pos; (y-start_y_pos) < max_numlines && y < levelmap["max_y"] ; y++ )) ; do + line="" + for (( x=0 ; x < levelmap["max_x"] ; x++ )) ; do + line+="${levelmap["${x}_${y}"]}" + done + + print -- "${line} " + done + + # print lines filled with spaces for each line not filled + # by the level map + line="${vtcode["spaceline"]:0:${levelmap["max_x"]}}" + for (( ; (y-start_y_pos) < max_numlines ; y++ )) ; do + print -- "${line} " + done + return 0 +} + +function level_completed +{ + integer i + typeset dummy + typeset render_buffer="$( + print -n -- "${vtcode["clear"]}" + cat < %s <--\n" "${player["score"]}" + printf " LIVES: --> %s <--\n" "${player["lives"]}" + )" + print -- "${render_buffer}${end_of_frame}" + + # wait five seconds and swallow any user input + for (( i=0 ; i < 50 ; i++ )) ; do + read -r -t 0.1 -n 1 dummy + done + + print "Press any key to continue...${end_of_frame}" + # wait five secs or for a key + read -r -t 5 -n 1 dummy +} + +function game_over +{ + typeset dummy + typeset render_buffer="$( + print -n -- "${vtcode["clear"]}" + cat < %s <--\n" "${player["score"]}" + )" + print -r -- "${render_buffer}${end_of_frame}" + + # wait five seconds and swallow any user input + for (( i=0 ; i < 50 ; i++ )) ; do + read -r -t 0.1 -n 1 dummy + done + + print "Press any key to continue...${end_of_frame}" + # wait five secs or for a key + read -r -t 5 -n 1 dummy +} + +function run_logo +{ + typeset render_buffer="$( + cat <======================================\ +> /-\ .--. | +> | OO| / _.-' .-. .-. .-. .-. | +> | | \ '-. '-' '-' '-' '-' | +> ^^^^^ '--' | +>======\ /================\ .-. | +> | | | '-' | + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ENDOFTEXT + print " GNAW - the ksh93 maze game" + print "\n\tMenu:" + + print "\t - [L]evels:" + for (( i=0 ; i < numlevels ; i++ )) ; do + printf "\t %s %s \n" "$( (( i == selected_level )) && print -n "*" || print -n " ")" "${levellist[i]##levelmap_}" + done + + print "\t - Rendering options:" + printf "\t [%s] Use [U]nicode\n" "$( (( game_use_unicode == 1 )) && print -n "x" || print -n "_" )" + printf "\t [%s] Use [C]olors\n" "$( (( game_use_colors == 1 )) && print -n "x" || print -n "_" )" + + print "\t - [S]tart - [Q]uit" + + # wait 30 secs (before we switch to "attract mode") + c="" ; read -r -t 30 -n 1 c + case "$c" in + 'l') (( selected_level=(selected_level+numlevels+1) % numlevels )) ;; + 'L') (( selected_level=(selected_level+numlevels-1) % numlevels )) ;; + ~(Ei)s) + (( game_use_colors == 1 )) && print -- "${vtcode["bg_black"]}" + case "${game_use_colors}${game_use_unicode}" in + "00") main_loop "${levellist[selected_level]}" ;; + "01") main_loop "${levellist[selected_level]}" | map_filter 0 1 ;; + "10") main_loop "${levellist[selected_level]}" | map_filter 1 0 ;; + "11") main_loop "${levellist[selected_level]}" | map_filter 1 1 ;; + esac + print -- "${vtcode["vtreset"]}" + ;; + ~(Ei)q|$'\E') + # make sure we do not exit on a cursor key (e.g. [A,B,C,D) + read -r -t 0.01 -n 1 c + if [[ "$c" == "[" ]] ; then + # this was a cursor key sequence, just eat the 3rd charcater + read -r -t 0.01 -n 1 c + else + exit 0 + fi + ;; + ~(Ei)u) (( game_use_unicode=(game_use_unicode+2+1) % 2)) ;; + ~(Ei)c) (( game_use_colors=(game_use_colors+2+1) % 2)) ;; + "") break ;; # timeout, switch to attract mode + *) beep ;; + esac + done + + print -n -- "${vtcode["clear"]}" + attract_mode + done +} + +function levelmap_stripes +{ +cat <= screen_y_offset && m_pos_y < render_num_lines )) ; then + print_setcursorpos ${m_pos_x} ${m_pos_y} + print -n "x" + fi + done + + # status block + print_setcursorpos 0 $((render_num_lines+screen_y_offset)) + emptyline=" " + print -n " >> ${player["message"]} <<${emptyline:0:${#emptyline}-${#player["message"]}}" + )" + print -r -- "${render_buffer}${end_of_frame}" +# print "renderbuffersize=$(print "${render_buffer}" | wc -c) ${end_of_frame}" +} + +function main_loop +{ + float sleep_per_cycle=0.2 + float seconds_before_read + integer num_cycles=0 + float rs + + print -n -- "${vtcode["clear"]}" + + read_levelmap "$1" + + # player init + player["pos_x"]=${levelmap["playerstartpos_x"]} + player["pos_y"]=${levelmap["playerstartpos_y"]} + player["score"]=0 # player score + player["lives"]=5 # number of lives + player["invulnerable"]=10 # cycles how long the player remains invulnerable + player["message"]="Go..." + + monsterlist="maw claw jitterbug tentacle grendel" + + for currmonster in ${monsterlist} ; do + monster[${currmonster}_"pos_x"]=${levelmap["monsterstartpos_x"]} + monster[${currmonster}_"pos_y"]=${levelmap["monsterstartpos_y"]} + monster[${currmonster}_"xstep"]=0 + monster[${currmonster}_"ystep"]=0 + monster[${currmonster}_"homing"]=0 + done + + # main game cycle loop + while true ; do + num_cycles+=1 + seconds_before_read=${SECONDS} + c="" ; read -r -t ${sleep_per_cycle} -n 1 c + + if [[ "$c" != "" ]] ; then + # special case handling for cursor keys which are usually composed + # of three characters (e.g. "[D"). If only is hit we + # quicky exit + if [[ "$c" == $'\E' ]] ; then + read -r -t 0.1 -n 1 c + if [[ "$c" != "[" ]] ; then + return 0 + fi + + # we assume the user is using the cursor keys, this |read| + # should fetch the 3rd byte of the three-character sequence + # for the cursor keys + read -r -t 0.1 -n 1 c + fi + + # if the user hit a key the "read" above was interrupted + # and didn't wait exactly |sleep_per_cycle| seconds. + # We wait here some moments (|rs|="remaining seconds") to + # avoid that the game gets "faster" when more user input + # is given. + (( rs=sleep_per_cycle-(SECONDS-seconds_before_read) )) + (( rs > 0.001 )) && sleep ${rs} + + player["message"]="" + + case "$c" in + j|D|4) (( player["pos_x"]-=1 )) ;; + k|C|6) (( player["pos_x"]+=1 )) ;; + i|A|8) (( player["pos_y"]-=1 )) ;; + m|B|2) (( player["pos_y"]+=1 )) ;; + + q) return 0 ;; + esac + + if [[ "${levelmap["${player["pos_x"]}_${player["pos_y"]}"]}" == "." ]] ; then + levelmap["${player["pos_x"]}_${player["pos_y"]}"]=" " + (( levelmap["numdots"]-=1 )) + + (( player["score"]+=10 )) + player["message"]='GNAW!!' + + if (( levelmap["numdots"] <= 0 )) ; then + level_completed + return 0 + fi + fi + fi + + # generic player status change + if (( player["invulnerable"] > 0 )) ; then + (( player["invulnerable"]-=1 )) + fi + if (( player["lives"] <= 0 )) ; then + game_over + return 0 + fi + + # move monsters + for currmonster in ${monsterlist} ; do + # make monster as half as slow then the others when it is following the user + if (( monster[${currmonster}_"homing"] > 0 )) ; then + (( (num_cycles%2) > 0 )) && continue + fi + + if [[ ${monster[${currmonster}_"pos_x"]} == ${player["pos_x"]} ]] ; then + if (( (monster[${currmonster}_"pos_y"]-player["pos_y"]) > 0 )) ; then + (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=-1 )) + else + (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=+1 )) + fi + monster[${currmonster}_"homing"]=1 + if (( player["invulnerable"] <= 0 )) ; then + player["message"]="Attention: ${currmonster} is chasing you" + fi + elif (( monster[${currmonster}_"pos_y"] == player["pos_y"] )) ; then + if (( (monster[${currmonster}_"pos_x"]-player["pos_x"]) > 0 )) ; then + (( monster[${currmonster}_"xstep"]=-1 , monster[${currmonster}_"ystep"]=-0 )) + else + (( monster[${currmonster}_"xstep"]=+1 , monster[${currmonster}_"ystep"]=+0 )) + fi + monster[${currmonster}_"homing"]=1 + if (( player["invulnerable"] <= 0 )) ; then + player["message"]="Attention: ${currmonster} is chasing you" + fi + else + if (( monster[${currmonster}_"homing"] == 0 )) ; then + case $((SECONDS % 6 + RANDOM % 4)) in + 0) (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=+0 )) ;; + 2) (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=+1 )) ;; + 3) (( monster[${currmonster}_"xstep"]=+1 , monster[${currmonster}_"ystep"]=+0 )) ;; + 5) (( monster[${currmonster}_"xstep"]=+0 , monster[${currmonster}_"ystep"]=-1 )) ;; + 6) (( monster[${currmonster}_"xstep"]=-1 , monster[${currmonster}_"ystep"]=+0 )) ;; + esac + fi + fi + + (( monster[${currmonster}_"pos_x"]=monster[${currmonster}_"pos_x"]+monster[${currmonster}_"xstep"] )) + (( monster[${currmonster}_"pos_y"]=monster[${currmonster}_"pos_y"]+monster[${currmonster}_"ystep"] )) + + # check if a monster hit the player + if (( player["invulnerable"] <= 0 )) ; then + if (( monster[${currmonster}_"pos_x"] == player["pos_x"] && \ + monster[${currmonster}_"pos_y"] == player["pos_y"] )) ; then + # if player was hit by a monster take one life and + # make him invulnerable for 10 cycles to avoid that + # the next cycle steals more lives + player["message"]="Ouuuchhhh" + player["invulnerable"]=10 + (( player["lives"]-=1 )) + + beep ; beep ; sleep 0.2 ; beep ; beep + fi + fi + done + + render_game + done +} + +function map_filter +{ + typeset ch_player ch_monster ch_wall var + + if (( $1 == 1 )) ; then + ch_player="${vtcode["fg_yellow"]}" + ch_monster="${vtcode["fg_red"]}" + ch_wall="${vtcode["fg_blue"]}" + else + ch_player="" + ch_monster="" + ch_wall="" + fi + + if (( $2 == 1 )) ; then + # unicode map + ch_player+="$(printf '\u[24d2]')" + ch_monster+="$(printf '\u[2605]')" + ch_wall+="$(printf '\u[25a6]')" + else + # ascii map + ch_player+="@" + ch_monster+="x" + ch_wall+="#" + fi + + # note that this filter currently defeats the "double-buffering" + while IFS='' read -r -d "${end_of_frame}" var ; do + var="${var// /${vtcode["fg_grey"]} }" + var="${var//\./${vtcode["fg_lightred"]}.}" + var="${var//@/${ch_player}}" + var="${var//x/${ch_monster}}" + var="${var//#/${ch_wall}}" + + print -r -- "${var}" + done +} + +function exit_trap +{ + # restore stty settings + stty ${saved_stty} + + print "bye." +} + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${gnaw_usage}" OPT '-?' + exit 2 +} + +# program start +# make sure we use the ksh93 "cat" builtin which supports the "-u" option +builtin basename +builtin cat +builtin printf # we need this for positional parameters ('printf "%2\$s %1\$s" hello world' = "world hello") +builtin sleep +builtin wc + +typeset progname="${ basename "${0}" ; }" + +# terminal size rect +typeset termsize=( + integer columns=-1 + integer lines=-1 +) + +# global variables +typeset quiet=false + +typeset -A levelmap +typeset -A player +typeset -A monster +# global rendering options +integer game_use_colors=0 +integer game_use_unicode=0 + +typeset -r gnaw_usage=$'+ +[-?\n@(#)\$Id: gnaw (Roland Mainz) 2008-06-08 \$\n] +[-author?Roland Mainz ] +[+NAME?gnaw - maze game written in ksh93] +[+DESCRIPTION?\bgnaw\b is a maze game. + The player maneuvers a yellow "@" sign to navigate a maze while eating + small dots. A level is finished when all the dots are eaten. Five monsters + (maw, claw, jitterbug, tentacle and grendel) also wander the maze in an attempt + to catch the "@". Each level begins with all ghosts in their home, and "@" near + the bottom of the maze. The monsters are released from the home one by one at the + start of each level and start their rentless hunt after the player.] +[q:quiet?Disable use of terminal bell.] +[+SEE ALSO?\bksh93\b(1)] +' + +while getopts -a "${progname}" "${gnaw_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + q) quiet=true ;; + +q) quiet=false ;; + *) usage ;; + esac +done +shift $((OPTIND-1)) + +# save stty values and register the exit trap which restores these values on exit +saved_stty="$(stty -g)" +trap exit_trap EXIT + +print "Loading..." + +# set stty values, "-icanon min 1 time 0 -inpck" should improve input latency, +# "-echo" turns the terminal echo off +stty -icanon min 1 time 0 -inpck -echo + +get_term_size termsize || fatal_error "Couldn't get terminal size." + +# prechecks +(( termsize.columns < 60 )) && fatal_error "Terminal width must be larger than 60 columns (currently ${termsize.columns})." + +typeset -A vtcode +# color values taken from http://frexx.de/xterm-256-notes/, other +# codes from http://vt100.net/docs/vt100-tm/ +vtcode=( + ["bg_black"]="$(print -n "\E[40m")" + ["fg_black"]="$(print -n "\E[30m")" + ["fg_red"]="$(print -n "\E[31m")" + ["fg_lightred"]="$(print -n "\E[1;31m")" + ["fg_green"]="$(print -n "\E[32m")" + ["fg_lightgreen"]="$(print -n "\E[1;32m")" + ["fg_yellow"]="$(print -n "\E[33m")" + ["fg_lightyellow"]="$(print -n "\E[1;33m")" + ["fg_blue"]="$(print -n "\E[34m")" + ["fg_lightblue"]="$(print -n "\E[1;34m")" + ["fg_grey"]="$(print -n "\E[1;37m")" + ["fg_white"]="$(print -n "\E[37m")" + + # misc other vt stuff + ["vtreset"]="$(tput reset)" + ["clear"]="$(tput clear)" + ["bel"]="$(tput bel)" + ["spaceline"]="$(for (( i=0 ; i < termsize.columns ; i++ )) ; do print -n " " ; done)" +) + +# character used to as marker that a single frame ends at this point - this +# is used by the "double buffering" code to make sure the "read" builtin +# can read a whole "frame" instead of reading stuff line-by-line +typeset -r end_of_frame=$'\t' + +# get terminal sequence to move cursor to position x,y +# (see http://vt100.net/docs/vt100-ug/chapter3.html#CPR) +case ${TERM} in + xterm | xterm-color | vt100 | vt220 | dtterm | sun | sun-color) + cup="$(infocmp -1 | \ + egrep '^[[:space:]]*cup=' | \ + sed -e 's/.*cup=//' \ + -e 's/%[%id]*p1[%id]*/%2\\\$d/g' \ + -e 's/%[%id]*p2[%id]*/%1\\\$d/g' \ + -e 's/,$//')" + for (( x=0 ; x < termsize.columns ; x++ )) ; do + for (( y=0 ; y < termsize.lines ; y++ )) ; do + vtcode[cup_${x}_${y}]="$(printf "${cup}" $((x + 1)) $((y + 1)) )" + done + done + ;; + *) + printf "# Unrecognised terminal type '%s', fetching %dx%d items from terminfo database, please wait...\n" "${TERM}" "${termsize.columns}" "${termsize.lines}" + for (( x=0 ; x < termsize.columns ; x++ )) ; do + for (( y=0 ; y < termsize.lines ; y++ )) ; do + vtcode[cup_${x}_${y}]="$(tput cup ${y} ${x})" + done + done + ;; +esac + +print -- "${vtcode["vtreset"]}" + +run_logo +run_menu + +exit 0 +# EOF. Index: src/lib/libshell/common/scripts/svcproptree1.sh =================================================================== --- src/lib/libshell/common/scripts/svcproptree1.sh (revision 0) +++ src/lib/libshell/common/scripts/svcproptree1.sh (revision 1122) @@ -0,0 +1,174 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +function fatal_error +{ + print -u2 "${progname}: $*" + exit 1 +} + + +function svcproptovartree +{ + nameref tree=$1 + + typeset name + typeset servicename + typeset propname + + typeset datatype + + typeset -a fields + integer num_fields + integer i + + while IFS=' ' read -A fields ; do + num_fields=${#fields[*]} + + name="${fields[0]}" + datatype="${fields[1]}" + # parse service/property name + servicename="${name%~(Er):properties/.*}" + servicename="${servicename/~(El)svc:\//}" # strip "svc:/" + propname="${name#~(El).*:properties/}" + + if [[ "${tree["${servicename}"].properties[*]}" == "" ]] ; then + typeset -A tree["${servicename}"].properties=( ) + fi + + nameref node=tree["${servicename}"].properties["${propname}"] + + node=( + typeset datatype="${datatype}" + typeset valuelist="true" + typeset -a values + ) + + for (( i=2 ; i < num_fields ; i++ )) ; do + node.values+=( "${fields[i]}" ) + done + done + + return 0 +} + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${svcproptree1_usage}" OPT '-?' + exit 2 +} + +# program start +builtin basename +builtin cat +builtin date +builtin uname + +typeset progname="${ basename "${0}" ; }" + +typeset -r svcproptree1_usage=$'+ +[-?\n@(#)\$Id: svcproptree1 (Roland Mainz) 2008-06-11 \$\n] +[-author?Roland Mainz ] +[+NAME?svcproptree1 - SMF tree demo] +[+DESCRIPTION?\bxvcproptree1\b is a small ksh93 compound variable demo + which reads accepts a SMF service pattern name input file, + reads the matching service properties and converts them into an internal + variable tree representation and outputs it in the format + specified by viewmode (either "list", "namelist" or "tree")..] + +pattern viewmode + +[+SEE ALSO?\bksh93\b(1), svcprop\b(1)\b] +' + +while getopts -a "${progname}" "${svcproptree1_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + *) usage ;; + esac +done +shift $((OPTIND-1)) + +typeset svcpattern="$1" +typeset viewmode="$2" + +if [[ "${viewmode}" != ~(Elr)(list|namelist|tree) ]] ; then + fatal_error $"Invalid view mode \"${viewmode}\"." +fi + +typeset svc=( + typeset -A proptree +) + +typeset s + +s="$(/usr/bin/svcprop -f "${svcpattern}")" || fatal_error $"svcprop failed with exit code $?." +print -u2 $"#loading completed." + +print -r -- "$s" | svcproptovartree svc.proptree +print -u2 $"#parsing completed." + +case "${viewmode}" in + list) + set | egrep "^svc.proptree\[" | fgrep -v ']=$' + ;; + namelist) + typeset + | egrep "^svc.proptree\[" + ;; + tree) + printf "%B\n" svc + ;; + *) + fatal_error $"Invalid view mode \"${viewmode}\"." + ;; +esac + +print -u2 $"#done." + +exit 0 +# EOF. Index: src/lib/libshell/common/scripts/shtwitter.sh =================================================================== --- src/lib/libshell/common/scripts/shtwitter.sh (revision 0) +++ src/lib/libshell/common/scripts/shtwitter.sh (revision 1122) @@ -0,0 +1,356 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +function fatal_error +{ + print -u2 "${progname}: $*" + exit 1 +} + +function encode_x_www_form_urlencoded +{ + nameref formdata=$1 + nameref content="formdata.content" + integer numformelements=${#formdata.form[*]} + integer i j + + content="" + + for (( i=0 ; i < numformelements ; i++ )) ; do + nameref element="formdata.form[${i}]" + typeset data="${element.data}" + integer datalen="${#data}" + typeset c + + [[ "$content" != "" ]] && content+="&" + + content+="${element.name}=" + + for ((j=0 ; j < datalen ; j++)) ; do + c="${data:j:1}" + case "$c" in + ' ') c="+" ;; + '!') c="%21" ;; + '*') c="%2A" ;; + "'") c="%27" ;; + '(') c="%28" ;; + ')') c="%29" ;; + ';') c="%3B" ;; + ':') c="%3A" ;; + '@') c="%40" ;; + '&') c="%26" ;; + '=') c="%3D" ;; + '+') c="%2B" ;; + '$') c="%24" ;; + ',') c="%2C" ;; + '/') c="%2F" ;; + '?') c="%3F" ;; + '%') c="%25" ;; + '#') c="%23" ;; + '[') c="%5B" ;; + '\') c="%5C" ;; # we need this to avoid the '\'-quoting hell + ']') c="%5D" ;; + *) ;; + esac + content+="$c" + done + done + + formdata.content_length=${#content} + + return 0 +} + +# parse HTTP return code, cookies etc. +function parse_http_response +{ + nameref response="$1" + typeset h statuscode statusmsg i + + # we use '\r' as additional IFS to filter the final '\r' + IFS=$' \t\r' read -r h statuscode statusmsg # read HTTP/1.[01] + [[ "$h" != ~(Eil)HTTP/.* ]] && { print -u2 -f "%s: HTTP/ header missing\n" "$0" ; return 1 ; } + [[ "$statuscode" != ~(Elr)[0-9]* ]] && { print -u2 -f "%s: invalid status code\n" "$0" ; return 1 ; } + response.statuscode="$statuscode" + response.statusmsg="$statusmsg" + + # skip remaining headers + while IFS='' read -r i ; do + [[ "$i" == $'\r' ]] && break + + # strip '\r' at the end + i="${i/~(Er)$'\r'/}" + + case "$i" in + ~(Eli)Content-Type:.*) + response.content_type="${i/~(El).*:[[:blank:]]*/}" + ;; + ~(Eli)Content-Length:[[:blank:]]*[0-9]*) + integer response.content_length="${i/~(El).*:[[:blank:]]*/}" + ;; + ~(Eli)Transfer-Encoding:.*) + response.transfer_encoding="${i/~(El).*:[[:blank:]]*/}" + ;; + esac + done + + return 0 +} + +function cat_http_body +{ + typeset emode="$1" + typeset hexchunksize="0" + integer chunksize=0 + + if [[ "${emode}" == "chunked" ]] ; then + while IFS=$'\r' read hexchunksize && + [[ "${hexchunksize}" == ~(Elri)[0-9abcdef]* ]] && + (( chunksize=16#${hexchunksize} )) && (( chunksize > 0 )) ; do + dd bs=1 count="${chunksize}" 2>/dev/null + done + else + cat + fi + + return 0 +} + +function encode_http_basic_auth +{ + typeset user="$1" + typeset passwd="$2" + typeset s + integer s_len + typeset -b base64var + + # ksh93 binary variables use base64 encoding, the same as the + # HTTP basic authentification. We only have to read the + # plaintext user:passwd string into the binary variable "base64var" + # and then print this variable as ASCII. + s="${user}:${passwd}" + s_len="${#s}" + print -n "${s}" | read -N${s_len} base64var + + print -- "${base64var}" # print ASCII (base64) representation of binary var + + return 0 +} + +function put_twitter_message +{ + [[ "$SHTWITTER_USER" == "" ]] && fatal_error "SHTWITTER_USER not set." + [[ "$SHTWITTER_PASSWD" == "" ]] && fatal_error "SHTWITTER_PASSWD not set." + + # site setup + typeset url_host="twitter.com" + typeset url_path="/statuses/update.xml" + typeset url="http://${url_host}${url_path}" + integer netfd # http stream number + typeset msgtext="$1" + typeset -C httpresponse # http response + + # argument for "encode_x_www_form_urlencoded" + typeset urlform=( + # input + typeset -a form + # output + typeset content + integer content_length + ) + + typeset request="" + typeset content="" + + urlform.form=( + ( name="status" data="${msgtext}" ) + ) + + encode_x_www_form_urlencoded urlform + + content="${urlform.content}" + + request="POST ${url_path} HTTP/1.1\r\n" + request+="Host: ${url_host}\r\n" + request+="Authorization: Basic ${ encode_http_basic_auth "${SHTWITTER_USER}" "${SHTWITTER_PASSWD}" ; }\r\n" + request+="User-Agent: ${http_user_agent}\r\n" + request+="Connection: close\r\n" + request+="Content-Type: application/x-www-form-urlencoded\r\n" + request+="Content-Length: $(( urlform.content_length ))\r\n" + + redirect {netfd}<>"/dev/tcp/${url_host}/80" + (( $? != 0 )) && { print -u2 -f "Could not open connection to %s\n." "${url_host}" ; return 1 ; } + + # send http post + { + print -n -- "${request}\r\n" + print -n -- "${content}\r\n" + } >&${netfd} + + # process reply + parse_http_response httpresponse <&${netfd} + response="${ cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} ; }" + + # close connection + redirect {netfd}<&- + + printf "twitter response was (%s,%s): %s\n" "${httpresponse.statuscode}" "${httpresponse.statusmsg}" "${response}" + + if (( httpresponse.statuscode >= 200 && httpresponse.statuscode <= 299 )) ; then + return 0 + else + return 1 + fi + + # not reached +} + +function verify_twitter_credentials +{ + [[ "$SHTWITTER_USER" == "" ]] && fatal_error "SHTWITTER_USER not set." + [[ "$SHTWITTER_PASSWD" == "" ]] && fatal_error "SHTWITTER_PASSWD not set." + + # site setup + typeset url_host="twitter.com" + typeset url_path="/account/verify_credentials.xml" + typeset url="http://${url_host}${url_path}" + integer netfd # http stream number + typeset -C httpresponse # http response + + typeset request="" + + request="POST ${url_path} HTTP/1.1\r\n" + request+="Host: ${url_host}\r\n" + request+="Authorization: Basic ${ encode_http_basic_auth "${SHTWITTER_USER}" "${SHTWITTER_PASSWD}" ; }\r\n" + request+="User-Agent: ${http_user_agent}\r\n" + request+="Connection: close\r\n" + request+="Content-Type: application/x-www-form-urlencoded\r\n" + request+="Content-Length: 0\r\n" # dummy + + redirect {netfd}<>"/dev/tcp/${url_host}/80" + (( $? != 0 )) && { print -u2 -f "Could not open connection to %s.\n" "${url_host}" ; return 1 ; } + + # send http post + { + print -n -- "${request}\r\n" + } >&${netfd} + + # process reply + parse_http_response httpresponse <&${netfd} + response="${ cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} ; }" + + # close connection + redirect {netfd}<&- + + printf "twitter response was (%s,%s): %s\n" "${httpresponse.statuscode}" "${httpresponse.statusmsg}" "${response}" + + if (( httpresponse.statuscode >= 200 && httpresponse.statuscode <= 299 )) ; then + return 0 + else + return 1 + fi + + # not reached +} + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${shtwitter_usage}" OPT '-?' + exit 2 +} + +# program start +builtin basename +builtin cat +builtin date +builtin uname + +typeset progname="${ basename "${0}" ; }" + +# HTTP protocol client identifer +typeset -r http_user_agent="shtwitter/ksh93 (2008-06-14; ${ uname -s -r -p ; })" + +typeset -r shtwitter_usage=$'+ +[-?\n@(#)\$Id: shtwitter (Roland Mainz) 2008-06-14 \$\n] +[-author?Roland Mainz ] +[+NAME?shtwitter - read/write text data to internet clipboards] +[+DESCRIPTION?\bshtwitter\b is a small utility which can read and write text + to the twitter.com microblogging site.] +[+?The first arg \bmethod\b describes one of the methods, "update" posts a + text message to the users twitter blog, returning the raw response + message from the twitter server.] +[+?The second arg \bstring\b contains the string data which should be + stored on twitter.com.] + +method [ string ] + +[+SEE ALSO?\bksh93\b(1), \brssread\b(1), \bshtinyurl\b(1), http://www.twitter.com] +' + +while getopts -a "${progname}" "${shtwitter_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + *) usage ;; + esac +done +shift $((OPTIND-1)) + +# expecting at least one more argument +(($# >= 1)) || usage + +typeset method="$1" +shift + +case "${method}" in + update|blog) put_twitter_message "$@" ; exit $? ;; + verify_credentials) verify_twitter_credentials "$@" ; exit $? ;; + *) usage ;; +esac + +fatal_error "not reached." +# EOF. Index: src/lib/libshell/common/scripts/xmldocumenttree1.sh =================================================================== --- src/lib/libshell/common/scripts/xmldocumenttree1.sh (revision 0) +++ src/lib/libshell/common/scripts/xmldocumenttree1.sh (revision 1122) @@ -0,0 +1,358 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +function fatal_error +{ + print -u 2 "${progname}: $*" + exit 1 +} + +function attrstrtoattrarray +{ +#set -o xtrace + typeset s="$1" + nameref aa=$2 # attribute array + integer aa_count=0 + integer aa_count=0 + typeset nextattr + integer currattrlen=0 + typeset tagstr + typeset tagval + + while (( ${#s} > 0 )) ; do + # skip whitespaces + while [[ "${s:currattrlen:1}" == ~(E)[[:blank:][:space:]] ]] ; do + (( currattrlen++ )) + done + s="${s:currattrlen:${#s}}" + + # anything left ? + (( ${#s} == 0 )) && break + + # Pattern tests: + #x="foo=bar huz=123" ; print "${x##~(E)[[:alnum:]_-:]*=[^[:blank:]\"]*}" + #x='foo="ba=r o" huz=123' ; print "${x##~(E)[[:alnum:]_-:]*=\"[^\"]*\"}" + #x="foo='ba=r o' huz=123" ; print "${x##~(E)[[:alnum:]_-:]*=\'[^\"]*\'}" + #x="foox huz=123" ; print "${x##~(E)[[:alnum:]_-:]*}" + # All pattern combined via eregex (w|x|y|z): + #x='foo="bar=o" huz=123' ; print "${x##~(E)([[:alnum:]_-:]*=[^[:blank:]\"]*|[[:alnum:]_-:]*=\"[^\"]*\"|[[:alnum:]_-:]*=\'[^\"]*\')}" + nextattr="${s##~(E)([[:alnum:]_-:]*=[^[:blank:]\"]*|[[:alnum:]_-:]*=\"[^\"]*\"|[[:alnum:]_-:]*=\'[^\"]*\'|[[:alnum:]_-:]*)}" + currattrlen=$(( ${#s} - ${#nextattr})) + + # add entry + tagstr="${s:0:currattrlen}" + if [[ "${tagstr}" == *=* ]] ; then + # normal case: attribute with value + + tagval="${tagstr#*=}" + + # strip quotes ('' or "") + if [[ "${tagval}" == ~(Elr)(\'.*\'|\".*\") ]] ; then + tagval="${tagval:1:${#tagval}-2}" + fi + + aa[${aa_count}]=( name="${tagstr%%=*}" value="${tagval}" ) + else + # special case for HTML where you have something like + aa[${aa_count}]=( name="${tagstr}" ) + fi + (( aa_count++ )) + (( aa_count > 1000 )) && fatal_error "$0: aa_count too large" # assert + done +} + + +function handle_document +{ +#set -o xtrace + nameref callbacks=${1} + typeset tag_type="${2}" + typeset tag_value="${3}" + typeset tag_attributes="${4}" + nameref doc=${callbacks["arg_tree"]} + nameref nodepath="${stack.items[stack.pos]}" + nameref nodesnum="${stack.items[stack.pos]}num" + + case "${tag_type}" in + tag_begin) + nodepath[${nodesnum}]+=( + typeset tagtype="element" + typeset tagname="${tag_value}" + typeset -A tagattributes=( ) + typeset -A nodes=( ) + integer nodesnum=0 + ) + + # fill attributes + if [[ "${tag_attributes}" != "" ]] ; then + attrstrtoattrarray "${tag_attributes}" "nodepath[${nodesnum}].tagattributes" + fi + + (( stack.pos++ )) + stack.items[stack.pos]="${stack.items[stack.pos-1]}[${nodesnum}].nodes" + (( nodesnum++ )) + ;; + tag_end) + (( stack.pos-- )) + ;; + tag_text) + nodepath[${nodesnum}]+=( + typeset tagtype="text" + typeset tagvalue="${tag_value}" + ) + (( nodesnum++ )) + ;; + tag_comment) + nodepath[${nodesnum}]+=( + typeset tagtype="comment" + typeset tagvalue="${tag_value}" + ) + (( nodesnum++ )) + ;; + document_start) + ;; + document_end) + ;; + esac + +# print "xmltok: '${tag_type}' = '${tag_value}'" +} + +function xml_tok +{ + typeset buf="" + typeset namebuf="" + typeset attrbuf="" + typeset c="" + typeset isendtag # bool: true/false + typeset issingletag # bool: true/false (used for tags like "
") + nameref callbacks=${1} + + [[ ! -z "${callbacks["document_start"]}" ]] && ${callbacks["document_start"]} "${1}" "document_start" + + while IFS='' read -r -N 1 c ; do + isendtag=false + + if [[ "$c" == "<" ]] ; then + # flush any text content + if [[ "$buf" != "" ]] ; then + [[ ! -z "${callbacks["tag_text"]}" ]] && ${callbacks["tag_text"]} "${1}" "tag_text" "$buf" + buf="" + fi + + IFS='' read -r -N 1 c + if [[ "$c" == "/" ]] ; then + isendtag=true + else + buf="$c" + fi + IFS='' read -r -d '>' c + buf+="$c" + + # handle comments + if [[ "$buf" == ~(El)!-- ]] ; then + # did we read the comment completely ? + if [[ "$buf" != ~(Elr)!--.*-- ]] ; then + buf+=">" + while [[ "$buf" != ~(Elr)!--.*-- ]] ; do + IFS='' read -r -N 1 c || break + buf+="$c" + done + fi + + [[ ! -z "${callbacks["tag_comment"]}" ]] && ${callbacks["tag_comment"]} "${1}" "tag_comment" "${buf:3:${#buf}-5}" + buf="" + continue + fi + + # check if the tag starts and ends at the same time (like "
") + if [[ "${buf}" == ~(Er).*/ ]] ; then + issingletag=true + buf="${buf%*/}" + else + issingletag=false + fi + + # check if the tag has attributes (e.g. space after name) + if [[ "$buf" == ~(E)[[:space:][:blank:]] ]] ; then + namebuf="${buf%%~(E)[[:space:][:blank:]].*}" + attrbuf="${buf#~(E).*[[:space:][:blank:]]}" + else + namebuf="$buf" + attrbuf="" + fi + + if ${isendtag} ; then + [[ ! -z "${callbacks["tag_end"]}" ]] && ${callbacks["tag_end"]} "${1}" "tag_end" "$namebuf" + else + [[ ! -z "${callbacks["tag_begin"]}" ]] && ${callbacks["tag_begin"]} "${1}" "tag_begin" "$namebuf" "$attrbuf" + + # handle tags like
(which are start- and end-tag in one piece) + if ${issingletag} ; then + [[ ! -z "${callbacks["tag_end"]}" ]] && ${callbacks["tag_end"]} "${1}" "tag_end" "$namebuf" + fi + fi + buf="" + else + buf+="$c" + fi + done + + [[ ! -z "${callbacks["document_end"]}" ]] && ${callbacks["document_end"]} "${1}" "document_end" "exit_success" + + print # final newline to make filters like "sed" happy +} + +function print_sample1_xml +{ +cat < + + + nocrocodile + + + + myfootext + mybartext + + + myttttext + + +EOF +} + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${xmldocumenttree1_usage}" OPT '-?' + exit 2 +} + +# program start +builtin basename +builtin cat +builtin date +builtin uname + +typeset progname="${ basename "${0}" ; }" + +typeset -r xmldocumenttree1_usage=$'+ +[-?\n@(#)\$Id: xmldocumenttree1 (Roland Mainz) 2008-06-14 \$\n] +[-author?Roland Mainz ] +[+NAME?xmldocumenttree1 - XML tree demo] +[+DESCRIPTION?\bxmldocumenttree\b is a small ksh93 compound variable demo + which reads a XML input file, converts it into an internal + variable tree representation and outputs it in the format + specified by viewmode (either "list", "namelist" or "tree").] + +file viewmode + +[+SEE ALSO?\bksh93\b(1)] +' + +while getopts -a "${progname}" "${xmldocumenttree1_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + *) usage ;; + esac +done +shift $((OPTIND-1)) + +typeset xmlfile="$1" +typeset viewmode="$2" + +if [[ "${xmlfile}" == "" ]] ; then + fatal_error $"No file given." +fi + +if [[ "${viewmode}" != ~(Elr)(list|namelist|tree) ]] ; then + fatal_error $"Invalid view mode \"${viewmode}\"." +fi + +typeset -C xdoc +typeset -A xdoc.nodes +integer xdoc.nodesnum=0 + +typeset -C stack +typeset -a stack.items=( [0]="doc.nodes" ) +integer stack.pos=0 + +# setup callbacks for xml_tok +typeset -A document_cb # callbacks for xml_tok +document_cb["document_start"]="handle_document" +document_cb["document_end"]="handle_document" +document_cb["tag_begin"]="handle_document" +document_cb["tag_end"]="handle_document" +document_cb["tag_text"]="handle_document" +document_cb["tag_comment"]="handle_document" +# argument for "handle_document" +document_cb["arg_tree"]="xdoc" + + +if [[ "${xmlfile}" == "#sample1" ]] ; then + print_sample1_xml | xml_tok document_cb +elif [[ "${xmlfile}" == "#sample2" ]] ; then + /usr/sfw/bin/wget \ + --user-agent='ksh93_xmldocumenttree' \ + --output-document=- \ + 'http://www.google.com/custom?q=gummi+bears' | + /usr/bin/iconv -f "ISO8859-1" | + xml_tok document_cb +else + cat "${xmlfile}" | xml_tok document_cb +fi + +print -u2 "#parsing completed." + +case "${viewmode}" in + list) + set | egrep "xdoc.*(tagname|tagtype|tagval|tagattributes)" | fgrep -v ']=$' + ;; + namelist) + typeset + | egrep "xdoc.*(tagname|tagtype|tagval|tagattributes)" + ;; + tree) + print -- "${xdoc}" + ;; + *) + fatal_error $"Invalid view mode \"${viewmode}\"." + ;; +esac + +print -u2 "#done." + +exit 0 +# EOF. Index: src/lib/libshell/common/scripts/shnote.sh =================================================================== --- src/lib/libshell/common/scripts/shnote.sh (revision 0) +++ src/lib/libshell/common/scripts/shnote.sh (revision 1122) @@ -0,0 +1,424 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +function fatal_error +{ + print -u2 "${progname}: $*" + exit 1 +} + +# fixme: use "stat" builtin instead of "ls" +function get_filesize +{ + typeset filename="$1" + typeset dummy # dummy string + integer filesize=-1 + + if [[ -f "${filename}" ]] ; then + # fixme: Set IFS when using "read" in a function + ls -lb "${filename}" | read dummy dummy dummy dummy filesize dummy + fi + + print -- ${filesize} + + return 0 +} + +function encode_multipart_form_data +{ + nameref formdata="$1" + nameref content="formdata.content" + integer numformelements=${#formdata.form[*]} + integer i + typeset tmp + + content="" + + # todo: add support to upload files + for (( i=0 ; i < numformelements ; i++ )) ; do + nameref element="formdata.form[${i}]" + + content+="--${formdata.boundary}\n" + content+="Content-Disposition: form-data; name=\"${element.name}\"\n" + content+="\n" + # make sure we quote the '\' properly since we pass these data to one instance of + # "print" when putting the content on the wire. + content+="${element.data//\\/\\\\}\n" # fixme: may need encoding for non-ASCII data + done + + # we have to de-quote the content before we can count the real numer of bytes in the payload + tmp="$(print -- "${content}")" + formdata.content_length=${#tmp} + + # add content tail (which MUST not be added to the content length) + content+="--${formdata.boundary}--\n" + + return 0 +} + +# parse HTTP return code, cookies etc. +function parse_http_response +{ + nameref response="$1" + typeset h statuscode statusmsg i + + # we use '\r' as additional IFS to filter the final '\r' + IFS=$' \t\r' read -r h statuscode statusmsg # read HTTP/1.[01] + [[ "$h" != ~(Eil)HTTP/.* ]] && { print -u2 -f "%s: HTTP/ header missing\n" "$0" ; return 1 ; } + [[ "$statuscode" != ~(Elr)[0-9]* ]] && { print -u2 -f "%s: invalid status code\n" "$0" ; return 1 ; } + response.statuscode="$statuscode" + response.statusmsg="$statusmsg" + + # skip remaining headers + while IFS='' read -r i ; do + [[ "$i" == $'\r' ]] && break + + # strip '\r' at the end + i="${i/~(Er)$'\r'/}" + + case "$i" in + ~(Eli)Content-Type:.*) + response.content_type="${i/~(El).*:[[:blank:]]*/}" + ;; + ~(Eli)Content-Length:[[:blank:]]*[0-9]*) + integer response.content_length="${i/~(El).*:[[:blank:]]*/}" + ;; + ~(Eli)Transfer-Encoding:.*) + response.transfer_encoding="${i/~(El).*:[[:blank:]]*/}" + ;; + esac + done + + return 0 +} + +function cat_http_body +{ + typeset emode="$1" + typeset hexchunksize="0" + integer chunksize=0 + + if [[ "${emode}" == "chunked" ]] ; then + while IFS=$'\r' read hexchunksize && + [[ "${hexchunksize}" == ~(Elri)[0-9abcdef]* ]] && + (( chunksize=16#${hexchunksize} )) && (( chunksize > 0 )) ; do + dd bs=1 count="${chunksize}" 2>/dev/null + done + else + cat + fi + + return 0 +} + +function history_write_record +{ + # rec: history record: + # rec.title + # rec.description + # rec.provider + # rec.providertoken + # rec.url + nameref rec="$1" + integer histfd + + mkdir -p "${HOME}/.shnote" + + { + # write a single-line record which can be read + # as a compound variable back into the shell + printf "title=%q description=%q date=%q provider=%q providertoken=%q url=%q\n" \ + "${rec.title}" \ + "${rec.description}" \ + "$(date)" \ + "${rec.provider}" \ + "${rec.providertoken}" \ + "${rec.url}" + } >>"${history_file}" + + return $? +} + +function print_history +{ + integer histfd # http stream number + typeset line + + # default output format is: + # / <date> <access url> + [[ "$1" == "-l" ]] || printf "# %s\t\t\t\t\t%s\t%s\n" "<url>" "<title>" "<date>" + + # no history file ? + if [[ ! -f "${history_file}" ]] ; then + return 0 + fi + + # open history file + redirect {histfd}<>"${history_file}" + (( $? != 0 )) && { print -u2 "Couldn't open history file." ; return 1 ; } + + while read -u${histfd} line ; do + typeset -C rec + + printf "( %s )\n" "${line}" | read -C rec + + if [[ "$1" == "-l" ]] ; then + print -- "${rec}" + else + printf "%s\t%s\t%s\n" "${rec.url}" "${rec.title}" "${rec.date}" + fi + + unset rec + done + + # close history file + redirect {histfd}<&- + + return 0 +} + +function put_note_pastebin_ca +{ + # key to autheticate this script against pastebin.ca + typeset -r pastebin_ca_key="9CFXFyeNC3iga/vthok75kTBu5kSSLPD" + # site setup + typeset url_host="opensolaris.pastebin.ca" + typeset url_path="/quiet-paste.php?api=${pastebin_ca_key}" + typeset url="http://${url_host}${url_path}" + integer netfd # http stream number + typeset -C httpresponse + + # argument for "encode_multipart_form_data" + typeset mimeform=( + # input + typeset boundary + typeset -a form + # output + typeset content + integer content_length + ) + + typeset request="" + typeset content="" + + typeset -r boundary="--------shnote_${RANDOM}_Xfish_${RANDOM}_Yeats_${RANDOM}_Zchicken_${RANDOM}monster_--------" + + mimeform.boundary="${boundary}" + mimeform.form=( # we use explicit index numbers since we rely on them below when filling the history + [0]=( name="name" data="${LOGNAME}" ) + [1]=( name="expiry" data="Never" ) + [2]=( name="type" data="1" ) + [3]=( name="description" data="logname=${LOGNAME};hostname=$(hostname);date=$(date)" ) + [4]=( name="content" data="$1" ) + ) + encode_multipart_form_data mimeform + + content="${mimeform.content}" + + request="POST ${url_path} HTTP/1.1\r\n" + request+="Host: ${url_host}\r\n" + request+="User-Agent: ${http_user_agent}\r\n" + request+="Connection: close\r\n" + request+="Content-Type: multipart/form-data; boundary=${boundary}\r\n" + request+="Content-Length: $(( mimeform.content_length ))\r\n" + + redirect {netfd}<>"/dev/tcp/${url_host}/80" + (( $? != 0 )) && { print -u2 "Couldn't open connection to ${url_host}." ; return 1 ; } + + # send http post + { + print -n -- "${request}\r\n" + print -n -- "${content}\r\n" + } >&${netfd} + + # process reply + parse_http_response httpresponse <&${netfd} + response="$(cat_http_body "${httpresponse.transfer_encoding}" <&${netfd})" + + # close connection + redirect {netfd}<&- + + if [[ "${response}" == ~(E).*SUCCESS.* ]] ; then + typeset response_token="${response/~(E).*SUCCESS:/}" + + printf "SUCCESS: http://opensolaris.pastebin.ca/%s\n" "${response_token}" + + # write history entry + typeset histrec=( + title="${mimeform.form[0].data}" + description="${mimeform.form[3].data}" + providertoken="${response_token}" + provider="opensolaris.pastebin.ca" + url="http://opensolaris.pastebin.ca/${response_token}" + ) + + history_write_record histrec + return 0 + else + printf "ERROR: %s\n" "${response}" + return 1 + fi + + # not reached +} + +function get_note_pastebin_ca +{ + typeset recordname="$1" + integer netfd # http stream number + + case "${recordname}" in + ~(Elr)[0-9][0-9]*) + # pass-through + ;; + ~(Elr)http://opensolaris.pastebin.ca/raw/[0-9]*) + recordname="${recordname/~(El)http:\/\/opensolaris.pastebin.ca\/raw\//}" + ;; + ~(Elr)http://opensolaris.pastebin.ca/[0-9]*) + recordname="${recordname/~(El)http:\/\/opensolaris.pastebin.ca\//}" + ;; + *) + fatal_error "Unsupported record name ${recordname}." + esac + + print -u2 -f "# Record name is '%s'\n" "${recordname}" + + typeset url_host="opensolaris.pastebin.ca" + typeset url_path="/raw/${recordname}" + typeset url="http://${url_host}${url_path}" + # I hereby curse Solaris for not having an entry for "http" in /etc/services + + # open TCP channel + redirect {netfd}<>"/dev/tcp/${url_host}/80" + (( $? != 0 )) && { print -u2 "Couldn't open connection to ${url_host}." ; return 1 ; } + + # send HTTP request + request="GET ${url_path} HTTP/1.1\r\n" + request+="Host: ${url_host}\r\n" + request+="User-Agent: ${http_user_agent}\r\n" + request+="Connection: close\r\n" + print -u${netfd} -- "${request}\r\n" + + # collect response and send it to stdout + parse_http_response httpresponse <&${netfd} + cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} + + # close connection + redirect {netfd}<&- + + print # add newline + + return 0 +} + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${USAGE}" OPT '-?' + exit 2 +} + +# program start +builtin basename +builtin cat +builtin date +builtin uname + +typeset progname="${ basename "${0}" ; }" + +# HTTP protocol client identifer +typeset -r http_user_agent="shnote/ksh93 (2008-06-14; $(uname -s -r -p))" + +# name of history log (the number after "history" is some kind of version +# counter to handle incompatible changes to the history file format) +typeset -r history_file="${HOME}/.shnote/history0.txt" + +typeset -r shnote_usage=$'+ +[-?\n@(#)\$Id: shnote (Roland Mainz) 2008-06-14 \$\n] +[-author?Roland Mainz <roland.mainz@nrubsig.org>] +[+NAME?shnote - read/write text data to internet clipboards] +[+DESCRIPTION?\bshnote\b is a small utilty which can read and write text + data to internet "clipboards" such as opensolaris.pastebin.ca.] +[+?The first arg \bmethod\b describes one of the methods, "put" saves a string + to the internet clipboard, returning an identifer and the full URL + where the data are stored. The method "get" retrives the raw + information using the identifer from the previous "put" action.] +[+?The second arg \bstring\b contains either the string data which should be + stored on the clipboard using the "put" method, the "get" method uses + this information as identifer to retrive the raw data from the clipboard.] + +method [ string ] + +[+SEE ALSO?\bksh93\b(1), \brssread\b(1), \bshtwitter\b(1), \bshtinyurl\b(1), http://opensolaris.pastebin.ca] +' + +while getopts -a "${progname}" "${shnote_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + *) usage ;; + esac +done +shift $((OPTIND-1)) + +# expecting at least one more argument, the single method below will do +# the checks for more arguments if needed ("put" and "get" methods need +# at least one extra argument, "hist" none). +(($# >= 1)) || usage + +typeset method="$1" +shift + +# todo: "history" mode +case "${method}" in + put) put_note_pastebin_ca "$@" ; exit $? ;; + get) get_note_pastebin_ca "$@" ; exit $? ;; + hist) print_history "$@" ; exit $? ;; + *) usage ;; +esac + +fatal_error "not reached." +# EOF. Index: src/lib/libshell/common/scripts/shtinyurl.sh =================================================================== --- src/lib/libshell/common/scripts/shtinyurl.sh (revision 0) +++ src/lib/libshell/common/scripts/shtinyurl.sh (revision 1122) @@ -0,0 +1,204 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +function fatal_error +{ + print -u2 "${progname}: $*" + exit 1 +} + +# parse HTTP return code, cookies etc. +function parse_http_response +{ + nameref response="$1" + typeset h statuscode statusmsg i + + # we use '\r' as additional IFS to filter the final '\r' + IFS=$' \t\r' read -r h statuscode statusmsg # read HTTP/1.[01] <code> + [[ "$h" != ~(Eil)HTTP/.* ]] && { print -u2 -f "%s: HTTP/ header missing\n" "$0" ; return 1 ; } + [[ "$statuscode" != ~(Elr)[0-9]* ]] && { print -u2 -f "%s: invalid status code\n" "$0" ; return 1 ; } + response.statuscode="$statuscode" + response.statusmsg="$statusmsg" + + # skip remaining headers + while IFS='' read -r i ; do + [[ "$i" == $'\r' ]] && break + + # strip '\r' at the end + i="${i/~(Er)$'\r'/}" + + case "$i" in + ~(Eli)Content-Type:.*) + response.content_type="${i/~(El).*:[[:blank:]]*/}" + ;; + ~(Eli)Content-Length:[[:blank:]]*[0-9]*) + integer response.content_length="${i/~(El).*:[[:blank:]]*/}" + ;; + ~(Eli)Transfer-Encoding:.*) + response.transfer_encoding="${i/~(El).*:[[:blank:]]*/}" + ;; + esac + done + + return 0 +} + +function cat_http_body +{ + typeset emode="$1" + typeset hexchunksize="0" + integer chunksize=0 + + if [[ "${emode}" == "chunked" ]] ; then + while IFS=$'\r' read hexchunksize && + [[ "${hexchunksize}" == ~(Elri)[0-9abcdef]* ]] && + (( chunksize=16#${hexchunksize} )) && (( chunksize > 0 )) ; do + dd bs=1 count="${chunksize}" 2>/dev/null + done + else + cat + fi + + return 0 +} + +function request_tinyurl +{ + # site setup + typeset url_host="tinyurl.com" + typeset url_path="/api-create.php" + typeset url="http://${url_host}${url_path}" + integer netfd # http stream number + typeset inputurl="$1" + typeset -C httpresponse # http response + typeset request="" + + # we assume "inputurl" is a correctly encoded URL which doesn't + # require any further mangling + url_path+="?url=${inputurl}" + + request="GET ${url_path} HTTP/1.1\r\n" + request+="Host: ${url_host}\r\n" + request+="User-Agent: ${http_user_agent}\r\n" + request+="Connection: close\r\n" + + redirect {netfd}<>"/dev/tcp/${url_host}/80" + (( $? != 0 )) && { print -u2 -f "Couldn't open connection to %s.\n" "${url_host}" ; return 1 ; } + + # send http post + { + print -n -- "${request}\r\n" + } >&${netfd} + + # process reply + parse_http_response httpresponse <&${netfd} + response="${ cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} ; }" + + # close connection + redirect {netfd}<&- + + if (( httpresponse.statuscode >= 200 && httpresponse.statuscode <= 299 )) ; then + print -r -- "${response}" + return 0 + else + print -u2 -f "tinyurl response was (%s,%s):\n%s\n" "${httpresponse.statuscode}" "${httpresponse.statusmsg}" "${response}" + return 1 + fi + + # not reached +} + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${shtinyurl_usage}" OPT '-?' + exit 2 +} + +# program start +builtin basename +builtin cat +builtin date +builtin uname + +typeset progname="${ basename "${0}" ; }" + +# HTTP protocol client identifer +typeset -r http_user_agent="shtinyurl/ksh93 (2008-06-14; ${ uname -s -r -p ; })" + +typeset -r shtinyurl_usage=$'+ +[-?\n@(#)\$Id: shtinyurl (Roland Mainz) 2008-06-14 \$\n] +[-author?Roland Mainz <roland.mainz@nrubsig.org>] +[+NAME?shtinyurl - create short tinyurl.com alias URL from long URL] +[+DESCRIPTION?\bshtinyurl\b is a small utility which passes a given URL + to the tinyurl.com service which creates short aliases in the + form of http://tinyurl.com/XXXXXXXX to redirect long URLs.] +[+?The first arg \burl\b describes a long URL which is transformed into + a tinyurl.com short alias.] + +url + +[+SEE ALSO?\bksh93\b(1), \brssread\b(1), \bshtwitter\b(1), http://www.tinyurl.com] +' + +while getopts -a "${progname}" "${shtinyurl_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + *) usage ;; + esac +done +shift $((OPTIND-1)) + +# expecting at least one more argument +(($# >= 1)) || usage + +typeset url="$1" +shift + +request_tinyurl "${url}" +exit $? +# EOF. Index: src/lib/libshell/common/scripts/shpiano.sh =================================================================== --- src/lib/libshell/common/scripts/shpiano.sh (revision 0) +++ src/lib/libshell/common/scripts/shpiano.sh (revision 1122) @@ -0,0 +1,1388 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +# Make sure all math stuff runs in the "C" locale to avoid problems +# with alternative # radix point representations (e.g. ',' instead of +# '.' in de_DE.*-locales). This needs to be set _before_ any +# floating-point constants are defined in this script). +if [[ "${LC_ALL}" != "" ]] ; then + export \ + LC_MONETARY="${LC_ALL}" \ + LC_MESSAGES="${LC_ALL}" \ + LC_COLLATE="${LC_ALL}" \ + LC_CTYPE="${LC_ALL}" + unset LC_ALL +fi +export LC_NUMERIC=C + +function fatal_error +{ + print -u2 "${progname}: $*" + exit 1 +} + +function beep +{ + tput bel + return 0 +} + +# array which holds frequency and sample data +# (the data are created on demand, "sample_set" indicates whether the "sample" variable +# needs to be filled or not) +typeset -A tones=( + ["C3"]=( float freq=261.63 ; typeset sample_set="false" ; typeset -b sample ) + ["C#3"]=( float freq=277.18 ; typeset sample_set="false" ; typeset -b sample ) + ["D3"]=( float freq=293.66 ; typeset sample_set="false" ; typeset -b sample ) + ["D#3"]=( float freq=311.13 ; typeset sample_set="false" ; typeset -b sample ) + ["E3"]=( float freq=329.63 ; typeset sample_set="false" ; typeset -b sample ) + ["F3"]=( float freq=349.23 ; typeset sample_set="false" ; typeset -b sample ) + ["F#3"]=( float freq=369.99 ; typeset sample_set="false" ; typeset -b sample ) + ["G3"]=( float freq=391.99 ; typeset sample_set="false" ; typeset -b sample ) + ["G#3"]=( float freq=415.31 ; typeset sample_set="false" ; typeset -b sample ) + ["A3"]=( float freq=440.00 ; typeset sample_set="false" ; typeset -b sample ) + ["A#3"]=( float freq=466.16 ; typeset sample_set="false" ; typeset -b sample ) + ["B3"]=( float freq=493.88 ; typeset sample_set="false" ; typeset -b sample ) + ["C4"]=( float freq=523.25 ; typeset sample_set="false" ; typeset -b sample ) + ["C#4"]=( float freq=554.37 ; typeset sample_set="false" ; typeset -b sample ) + ["D4"]=( float freq=587.33 ; typeset sample_set="false" ; typeset -b sample ) + ["D#4"]=( float freq=622.25 ; typeset sample_set="false" ; typeset -b sample ) + ["E4"]=( float freq=659.26 ; typeset sample_set="false" ; typeset -b sample ) + ["F4"]=( float freq=698.46 ; typeset sample_set="false" ; typeset -b sample ) + ["F#4"]=( float freq=739.99 ; typeset sample_set="false" ; typeset -b sample ) + ["G4"]=( float freq=783.99 ; typeset sample_set="false" ; typeset -b sample ) + ["G#4"]=( float freq=830.61 ; typeset sample_set="false" ; typeset -b sample ) + ["A4"]=( float freq=880.00 ; typeset sample_set="false" ; typeset -b sample ) + ["A#4"]=( float freq=932.32 ; typeset sample_set="false" ; typeset -b sample ) + ["B4"]=( float freq=987.77 ; typeset sample_set="false" ; typeset -b sample ) + ["C5"]=( float freq=1046.5 ; typeset sample_set="false" ; typeset -b sample ) + + # dummy entry for pause + ["p"]=( float freq=NaN ; typeset sample_set="false" ; typeset -b sample ) +) + +# alias table which translates the various names of "notes" to the matching entry +# in the "tones" table +typeset -r -A notes=( + ["C3"]=( nameref val=tones["C3"] ) ["key_d"]=( nameref val=tones["C3"] ) + ["C#3"]=( nameref val=tones["C#3"] ) ["key_r"]=( nameref val=tones["C#3"] ) + ["D3"]=( nameref val=tones["D3"] ) ["key_f"]=( nameref val=tones["D3"] ) + ["D#3"]=( nameref val=tones["D#3"] ) ["key_t"]=( nameref val=tones["D#3"] ) + ["E3"]=( nameref val=tones["E3"] ) ["key_g"]=( nameref val=tones["E3"] ) + ["F3"]=( nameref val=tones["F3"] ) ["key_h"]=( nameref val=tones["F3"] ) + ["F#3"]=( nameref val=tones["F#3"] ) ["key_u"]=( nameref val=tones["F#3"] ) + ["G3"]=( nameref val=tones["G3"] ) ["key_j"]=( nameref val=tones["G3"] ) + ["G#3"]=( nameref val=tones["G#3"] ) ["key_i"]=( nameref val=tones["G#3"] ) + ["A3"]=( nameref val=tones["A3"] ) ["key_k"]=( nameref val=tones["A3"] ) + ["A#3"]=( nameref val=tones["A#3"] ) ["key_o"]=( nameref val=tones["A#3"] ) + ["B3"]=( nameref val=tones["B3"] ) ["key_l"]=( nameref val=tones["B3"] ) + ["C4"]=( nameref val=tones["C4"] ) ["key_D"]=( nameref val=tones["C4"] ) + ["C#4"]=( nameref val=tones["C#4"] ) ["key_R"]=( nameref val=tones["C#4"] ) + ["D4"]=( nameref val=tones["D4"] ) ["key_F"]=( nameref val=tones["D4"] ) + ["D#4"]=( nameref val=tones["D#4"] ) ["key_T"]=( nameref val=tones["D#4"] ) + ["E4"]=( nameref val=tones["E4"] ) ["key_G"]=( nameref val=tones["E4"] ) + ["F4"]=( nameref val=tones["F4"] ) ["key_H"]=( nameref val=tones["F4"] ) + ["F#4"]=( nameref val=tones["F#4"] ) ["key_U"]=( nameref val=tones["F#4"] ) + ["G4"]=( nameref val=tones["G4"] ) ["key_J"]=( nameref val=tones["G4"] ) + ["G#4"]=( nameref val=tones["G#4"] ) ["key_I"]=( nameref val=tones["G#4"] ) + ["A4"]=( nameref val=tones["A4"] ) ["key_K"]=( nameref val=tones["A4"] ) + ["A#4"]=( nameref val=tones["A#4"] ) ["key_O"]=( nameref val=tones["A#4"] ) + ["B4"]=( nameref val=tones["B4"] ) ["key_L"]=( nameref val=tones["B4"] ) + ["C5"]=( nameref val=tones["C5"] ) +) + +# array used to convert a 14-bit unsigned PCM value to +# inverted 8-bit u-law +# (values were "stolen" from usr/src/cmd/audio/utilities/g711.c +integer -r -a audio_pcmulinear14bittoulaw8bit=( + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 + 0x01 0x01 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 0x02 + 0x02 0x02 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 0x03 + 0x03 0x03 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 + 0x04 0x04 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05 + 0x05 0x05 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 + 0x06 0x06 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 0x07 + 0x07 0x07 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 + 0x08 0x08 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 + 0x09 0x09 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a + 0x0a 0x0a 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b + 0x0b 0x0b 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c + 0x0c 0x0c 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d + 0x0d 0x0d 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e + 0x0e 0x0e 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f + 0x0f 0x0f 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 + 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 + 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 + 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 + 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 + 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 + 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 + 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 + 0x10 0x10 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 + 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 + 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 + 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 + 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 + 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 + 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 + 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 + 0x11 0x11 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 + 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 + 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 + 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 + 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 + 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 + 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 + 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 0x12 + 0x12 0x12 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 + 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 + 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 + 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 + 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 + 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 + 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 + 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 0x13 + 0x13 0x13 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 + 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 + 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 + 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 + 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 + 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 + 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 + 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 0x14 + 0x14 0x14 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 + 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 + 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 + 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 + 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 + 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 + 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 + 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 0x15 + 0x15 0x15 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 + 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 + 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 + 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 + 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 + 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 + 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 + 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 0x16 + 0x16 0x16 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 + 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 + 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 + 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 + 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 + 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 + 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 + 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 0x17 + 0x17 0x17 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 + 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 + 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 + 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 + 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 + 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 + 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 + 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 0x18 + 0x18 0x18 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 + 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 + 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 + 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 + 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 + 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 + 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 + 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 0x19 + 0x19 0x19 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a + 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a + 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a + 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a + 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a + 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a + 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a + 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a 0x1a + 0x1a 0x1a 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b + 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b + 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b + 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b + 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b + 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b + 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b + 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b 0x1b + 0x1b 0x1b 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c + 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c + 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c + 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c + 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c + 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c + 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c + 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c 0x1c + 0x1c 0x1c 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d + 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d + 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d + 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d + 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d + 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d + 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d + 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d 0x1d + 0x1d 0x1d 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e + 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e + 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e + 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e + 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e + 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e + 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e + 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e 0x1e + 0x1e 0x1e 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f + 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f + 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f + 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f + 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f + 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f + 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f + 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f 0x1f + 0x1f 0x1f 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 + 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 + 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 + 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 + 0x20 0x20 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 + 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 + 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 + 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 0x21 + 0x21 0x21 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 + 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 + 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 + 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 + 0x22 0x22 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 + 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 + 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 + 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 + 0x23 0x23 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 + 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 + 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 + 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 0x24 + 0x24 0x24 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 + 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 + 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 + 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 0x25 + 0x25 0x25 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 + 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 + 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 + 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 0x26 + 0x26 0x26 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 + 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 + 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 + 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 0x27 + 0x27 0x27 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 + 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 + 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 + 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 0x28 + 0x28 0x28 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 + 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 + 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 + 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 0x29 + 0x29 0x29 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a + 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a + 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a + 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a + 0x2a 0x2a 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b + 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b + 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b + 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b 0x2b + 0x2b 0x2b 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c + 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c + 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c + 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c 0x2c + 0x2c 0x2c 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d + 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d + 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d + 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d 0x2d + 0x2d 0x2d 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e + 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e + 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e + 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e 0x2e + 0x2e 0x2e 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f + 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f + 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f + 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f 0x2f + 0x2f 0x2f 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 + 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 + 0x30 0x30 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 + 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 0x31 + 0x31 0x31 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 + 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 0x32 + 0x32 0x32 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 + 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 + 0x33 0x33 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 + 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 0x34 + 0x34 0x34 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 + 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 0x35 + 0x35 0x35 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 + 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 0x36 + 0x36 0x36 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 + 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 0x37 + 0x37 0x37 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 + 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 + 0x38 0x38 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 + 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 0x39 + 0x39 0x39 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a + 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a 0x3a + 0x3a 0x3a 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b + 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b 0x3b + 0x3b 0x3b 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c + 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c + 0x3c 0x3c 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d + 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d 0x3d + 0x3d 0x3d 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e + 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e 0x3e + 0x3e 0x3e 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f + 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f + 0x3f 0x3f 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0x40 + 0x40 0x40 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 + 0x41 0x41 0x42 0x42 0x42 0x42 0x42 0x42 0x42 0x42 0x42 0x42 0x42 0x42 0x42 0x42 + 0x42 0x42 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43 + 0x43 0x43 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44 + 0x44 0x44 0x45 0x45 0x45 0x45 0x45 0x45 0x45 0x45 0x45 0x45 0x45 0x45 0x45 0x45 + 0x45 0x45 0x46 0x46 0x46 0x46 0x46 0x46 0x46 0x46 0x46 0x46 0x46 0x46 0x46 0x46 + 0x46 0x46 0x47 0x47 0x47 0x47 0x47 0x47 0x47 0x47 0x47 0x47 0x47 0x47 0x47 0x47 + 0x47 0x47 0x48 0x48 0x48 0x48 0x48 0x48 0x48 0x48 0x48 0x48 0x48 0x48 0x48 0x48 + 0x48 0x48 0x49 0x49 0x49 0x49 0x49 0x49 0x49 0x49 0x49 0x49 0x49 0x49 0x49 0x49 + 0x49 0x49 0x4a 0x4a 0x4a 0x4a 0x4a 0x4a 0x4a 0x4a 0x4a 0x4a 0x4a 0x4a 0x4a 0x4a + 0x4a 0x4a 0x4b 0x4b 0x4b 0x4b 0x4b 0x4b 0x4b 0x4b 0x4b 0x4b 0x4b 0x4b 0x4b 0x4b + 0x4b 0x4b 0x4c 0x4c 0x4c 0x4c 0x4c 0x4c 0x4c 0x4c 0x4c 0x4c 0x4c 0x4c 0x4c 0x4c + 0x4c 0x4c 0x4d 0x4d 0x4d 0x4d 0x4d 0x4d 0x4d 0x4d 0x4d 0x4d 0x4d 0x4d 0x4d 0x4d + 0x4d 0x4d 0x4e 0x4e 0x4e 0x4e 0x4e 0x4e 0x4e 0x4e 0x4e 0x4e 0x4e 0x4e 0x4e 0x4e + 0x4e 0x4e 0x4f 0x4f 0x4f 0x4f 0x4f 0x4f 0x4f 0x4f 0x4f 0x4f 0x4f 0x4f 0x4f 0x4f + 0x4f 0x4f 0x50 0x50 0x50 0x50 0x50 0x50 0x50 0x50 0x51 0x51 0x51 0x51 0x51 0x51 + 0x51 0x51 0x52 0x52 0x52 0x52 0x52 0x52 0x52 0x52 0x53 0x53 0x53 0x53 0x53 0x53 + 0x53 0x53 0x54 0x54 0x54 0x54 0x54 0x54 0x54 0x54 0x55 0x55 0x55 0x55 0x55 0x55 + 0x55 0x55 0x56 0x56 0x56 0x56 0x56 0x56 0x56 0x56 0x57 0x57 0x57 0x57 0x57 0x57 + 0x57 0x57 0x58 0x58 0x58 0x58 0x58 0x58 0x58 0x58 0x59 0x59 0x59 0x59 0x59 0x59 + 0x59 0x59 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5b 0x5b 0x5b 0x5b 0x5b 0x5b + 0x5b 0x5b 0x5c 0x5c 0x5c 0x5c 0x5c 0x5c 0x5c 0x5c 0x5d 0x5d 0x5d 0x5d 0x5d 0x5d + 0x5d 0x5d 0x5e 0x5e 0x5e 0x5e 0x5e 0x5e 0x5e 0x5e 0x5f 0x5f 0x5f 0x5f 0x5f 0x5f + 0x5f 0x5f 0x60 0x60 0x60 0x60 0x61 0x61 0x61 0x61 0x62 0x62 0x62 0x62 0x63 0x63 + 0x63 0x63 0x64 0x64 0x64 0x64 0x65 0x65 0x65 0x65 0x66 0x66 0x66 0x66 0x67 0x67 + 0x67 0x67 0x68 0x68 0x68 0x68 0x69 0x69 0x69 0x69 0x6a 0x6a 0x6a 0x6a 0x6b 0x6b + 0x6b 0x6b 0x6c 0x6c 0x6c 0x6c 0x6d 0x6d 0x6d 0x6d 0x6e 0x6e 0x6e 0x6e 0x6f 0x6f + 0x6f 0x6f 0x70 0x70 0x71 0x71 0x72 0x72 0x73 0x73 0x74 0x74 0x75 0x75 0x76 0x76 + 0x77 0x77 0x78 0x78 0x79 0x79 0x7a 0x7a 0x7b 0x7b 0x7c 0x7c 0x7d 0x7d 0x7e 0x7e + 0xff 0xfe 0xfe 0xfd 0xfd 0xfc 0xfc 0xfb 0xfb 0xfa 0xfa 0xf9 0xf9 0xf8 0xf8 0xf7 + 0xf7 0xf6 0xf6 0xf5 0xf5 0xf4 0xf4 0xf3 0xf3 0xf2 0xf2 0xf1 0xf1 0xf0 0xf0 0xef + 0xef 0xef 0xef 0xee 0xee 0xee 0xee 0xed 0xed 0xed 0xed 0xec 0xec 0xec 0xec 0xeb + 0xeb 0xeb 0xeb 0xea 0xea 0xea 0xea 0xe9 0xe9 0xe9 0xe9 0xe8 0xe8 0xe8 0xe8 0xe7 + 0xe7 0xe7 0xe7 0xe6 0xe6 0xe6 0xe6 0xe5 0xe5 0xe5 0xe5 0xe4 0xe4 0xe4 0xe4 0xe3 + 0xe3 0xe3 0xe3 0xe2 0xe2 0xe2 0xe2 0xe1 0xe1 0xe1 0xe1 0xe0 0xe0 0xe0 0xe0 0xdf + 0xdf 0xdf 0xdf 0xdf 0xdf 0xdf 0xdf 0xde 0xde 0xde 0xde 0xde 0xde 0xde 0xde 0xdd + 0xdd 0xdd 0xdd 0xdd 0xdd 0xdd 0xdd 0xdc 0xdc 0xdc 0xdc 0xdc 0xdc 0xdc 0xdc 0xdb + 0xdb 0xdb 0xdb 0xdb 0xdb 0xdb 0xdb 0xda 0xda 0xda 0xda 0xda 0xda 0xda 0xda 0xd9 + 0xd9 0xd9 0xd9 0xd9 0xd9 0xd9 0xd9 0xd8 0xd8 0xd8 0xd8 0xd8 0xd8 0xd8 0xd8 0xd7 + 0xd7 0xd7 0xd7 0xd7 0xd7 0xd7 0xd7 0xd6 0xd6 0xd6 0xd6 0xd6 0xd6 0xd6 0xd6 0xd5 + 0xd5 0xd5 0xd5 0xd5 0xd5 0xd5 0xd5 0xd4 0xd4 0xd4 0xd4 0xd4 0xd4 0xd4 0xd4 0xd3 + 0xd3 0xd3 0xd3 0xd3 0xd3 0xd3 0xd3 0xd2 0xd2 0xd2 0xd2 0xd2 0xd2 0xd2 0xd2 0xd1 + 0xd1 0xd1 0xd1 0xd1 0xd1 0xd1 0xd1 0xd0 0xd0 0xd0 0xd0 0xd0 0xd0 0xd0 0xd0 0xcf + 0xcf 0xcf 0xcf 0xcf 0xcf 0xcf 0xcf 0xcf 0xcf 0xcf 0xcf 0xcf 0xcf 0xcf 0xcf 0xce + 0xce 0xce 0xce 0xce 0xce 0xce 0xce 0xce 0xce 0xce 0xce 0xce 0xce 0xce 0xce 0xcd + 0xcd 0xcd 0xcd 0xcd 0xcd 0xcd 0xcd 0xcd 0xcd 0xcd 0xcd 0xcd 0xcd 0xcd 0xcd 0xcc + 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc 0xcb + 0xcb 0xcb 0xcb 0xcb 0xcb 0xcb 0xcb 0xcb 0xcb 0xcb 0xcb 0xcb 0xcb 0xcb 0xcb 0xca + 0xca 0xca 0xca 0xca 0xca 0xca 0xca 0xca 0xca 0xca 0xca 0xca 0xca 0xca 0xca 0xc9 + 0xc9 0xc9 0xc9 0xc9 0xc9 0xc9 0xc9 0xc9 0xc9 0xc9 0xc9 0xc9 0xc9 0xc9 0xc9 0xc8 + 0xc8 0xc8 0xc8 0xc8 0xc8 0xc8 0xc8 0xc8 0xc8 0xc8 0xc8 0xc8 0xc8 0xc8 0xc8 0xc7 + 0xc7 0xc7 0xc7 0xc7 0xc7 0xc7 0xc7 0xc7 0xc7 0xc7 0xc7 0xc7 0xc7 0xc7 0xc7 0xc6 + 0xc6 0xc6 0xc6 0xc6 0xc6 0xc6 0xc6 0xc6 0xc6 0xc6 0xc6 0xc6 0xc6 0xc6 0xc6 0xc5 + 0xc5 0xc5 0xc5 0xc5 0xc5 0xc5 0xc5 0xc5 0xc5 0xc5 0xc5 0xc5 0xc5 0xc5 0xc5 0xc4 + 0xc4 0xc4 0xc4 0xc4 0xc4 0xc4 0xc4 0xc4 0xc4 0xc4 0xc4 0xc4 0xc4 0xc4 0xc4 0xc3 + 0xc3 0xc3 0xc3 0xc3 0xc3 0xc3 0xc3 0xc3 0xc3 0xc3 0xc3 0xc3 0xc3 0xc3 0xc3 0xc2 + 0xc2 0xc2 0xc2 0xc2 0xc2 0xc2 0xc2 0xc2 0xc2 0xc2 0xc2 0xc2 0xc2 0xc2 0xc2 0xc1 + 0xc1 0xc1 0xc1 0xc1 0xc1 0xc1 0xc1 0xc1 0xc1 0xc1 0xc1 0xc1 0xc1 0xc1 0xc1 0xc0 + 0xc0 0xc0 0xc0 0xc0 0xc0 0xc0 0xc0 0xc0 0xc0 0xc0 0xc0 0xc0 0xc0 0xc0 0xc0 0xbf + 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf + 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbf 0xbe + 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe + 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbe 0xbd + 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd + 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbd 0xbc + 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc + 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbc 0xbb + 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb + 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xbb 0xba + 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba + 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xba 0xb9 + 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 + 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb9 0xb8 + 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 + 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb8 0xb7 + 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 + 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb7 0xb6 + 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 + 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb6 0xb5 + 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 + 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb5 0xb4 + 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 + 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb4 0xb3 + 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 + 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb3 0xb2 + 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 + 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb2 0xb1 + 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 + 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb1 0xb0 + 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 + 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xb0 0xaf + 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf + 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf + 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf + 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xaf 0xae + 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae + 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae + 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae + 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xae 0xad + 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad + 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad + 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad + 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xad 0xac + 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac + 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac + 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac + 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xac 0xab + 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab + 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab + 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab + 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xaa + 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa + 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa + 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa + 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xa9 + 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 + 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 + 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 + 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa9 0xa8 + 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 + 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 + 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 + 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa8 0xa7 + 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 + 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 + 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 + 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa7 0xa6 + 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 + 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 + 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 + 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa6 0xa5 + 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 + 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 + 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 + 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa5 0xa4 + 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 + 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 + 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 + 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa4 0xa3 + 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 + 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 + 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 + 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa3 0xa2 + 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 + 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 + 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 + 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa2 0xa1 + 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 + 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 + 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 + 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa1 0xa0 + 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 + 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 + 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 + 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0xa0 0x9f + 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f + 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f + 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f + 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f + 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f + 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f + 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f + 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9f 0x9e + 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e + 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e + 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e + 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e + 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e + 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e + 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e + 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9e 0x9d + 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d + 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d + 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d + 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d + 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d + 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d + 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d + 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9d 0x9c + 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c + 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c + 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c + 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c + 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c + 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c + 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c + 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9c 0x9b + 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b + 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b + 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b + 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b + 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b + 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b + 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b + 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9b 0x9a + 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a + 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a + 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a + 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a + 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a + 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a + 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a + 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x9a 0x99 + 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 + 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 + 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 + 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 + 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 + 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 + 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 + 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x99 0x98 + 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 + 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 + 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 + 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 + 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 + 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 + 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 + 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x98 0x97 + 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 + 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 + 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 + 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 + 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 + 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 + 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 + 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x97 0x96 + 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 + 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 + 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 + 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 + 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 + 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 + 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 + 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x95 + 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 + 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 + 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 + 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 + 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 + 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 + 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 + 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x95 0x94 + 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 + 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 + 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 + 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 + 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 + 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 + 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 + 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x94 0x93 + 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 + 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 + 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 + 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 + 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 + 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 + 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 + 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x93 0x92 + 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 + 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 + 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 + 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 + 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 + 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 + 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 + 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x92 0x91 + 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 + 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 + 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 + 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 + 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 + 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 + 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 + 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x91 0x90 + 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 + 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 + 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 + 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 + 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 + 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 + 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 + 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f + 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8f 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e + 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8e 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d + 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8d 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c + 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8c 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b + 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8b 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a + 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x8a 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 + 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x89 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 + 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x88 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 + 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x87 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 + 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x86 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 + 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x85 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 + 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x84 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 + 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x83 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 + 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x82 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 + 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x81 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 +) + +# base64 handling stuff +typeset -r base64chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +function bytearraytobase64 +{ + nameref bytearray=$1 + typeset out="" + integer len + integer i i0 i1 i2 + + (( len=${#bytearray[*]}-1 )) + for (( i=0 ; i < len ; i+=3 )) ; do + (( i0=bytearray[i+0] , i1=bytearray[i+1] , i2=bytearray[i+2] )) + + out+="${base64chars:$(( i0 >> 2 )):1}" + out+="${base64chars:$(( ((i0 & 0x03) << 4) | ((i1 & 0xf0) >> 4) )):1}" + (( (i+1) < len )) && { out+="${base64chars:$(( ((i1 & 0x0f) << 2) | ((i2 & 0xc0) >> 6) )):1}" ; } || out+="=" + (( (i+2) < len )) && { out+="${base64chars:$(( i2 & 0x3f )):1}" ; } || out+="=" + done + + printf "%s" "${out}" + return 0 +} + + +# stack layout: +# stack.currpos = current position +# stack.data = nameref to integer array +function stack_init +{ + nameref stk=$1 + stk.currpos=0 + return 0 +} + +function stack_put_byte +{ + nameref stk=$1 + stk.data[stk.currpos++]=$(( $2 & 0xFF )) + return 0 +} + +function stack_put_uint16 +{ + integer val=$2 + stack_put_byte $1 $(( (val >> 8) & 0xFF )) + stack_put_byte $1 $(( val & 0xFF )) + return 0 +} + +# put an au(4) header on a stack variable +function audio_put_au_header +{ + nameref au=$1 + + # au_magic: magic number + stack_put_byte au $(('.')) + stack_put_byte au $(('s')) + stack_put_byte au $(('n')) + stack_put_byte au $(('d')) + # au_offset + stack_put_byte au 0x00 + stack_put_byte au 0x00 + stack_put_byte au 0x00 + stack_put_byte au 0x1C + # au_data_size (0xFFFFFFFF = AUDIO_AU_UNKNOWN_SIZE ((unsigned)(~0))) + stack_put_byte au 0xFF + stack_put_byte au 0xFF + stack_put_byte au 0xFF + stack_put_byte au 0xFF + # au_encoding + stack_put_byte au 0x00 + stack_put_byte au 0x00 + stack_put_byte au 0x00 + stack_put_byte au 1 + # au_sample_rate + stack_put_byte au 0x00 + stack_put_byte au 0x00 + stack_put_byte au 0x1f + stack_put_byte au 0x40 + # au_channels + stack_put_byte au 0x00 + stack_put_byte au 0x00 + stack_put_byte au 0x00 + stack_put_byte au 0x01 + # dummy + stack_put_byte au 0 + stack_put_byte au 0 + stack_put_byte au 0 + stack_put_byte au 0 + return 0 +} + +function print_piano_layout +{ + cat <<ENDOFTEXT +---------------------------------------------------- + | ##### ##### | ##### ##### ##### | + | ##### ##### | ##### ##### ##### | + | ##### ##### | ##### ##### ##### | + | #cis# #dis# | #fis# #gis# #ais# | + | #des# # es# | #ges# # as# # b # | + | \###/ \###/ | \###/ \###/ \###/ | + | | | | | | | | + | | | | | | | | + | c | d | e | f | g | a | h | + | | | | | | | | +/\-----/\-----/\-----/\-----/\-----/\-----/\-----/\- + +Keys: + R T U I O + D F G H J K L +ENDOFTEXT + return 0 +} + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${shpiano_usage}" OPT '-?' + exit 2 +} + +# program start +builtin basename + +typeset progname="${ basename "${0}" ; }" + +typeset -r shpiano_usage=$'+ +[-?\n@(#)\$Id: shpiano (Roland Mainz) 2008-06-08 \$\n] +[-author?Roland Mainz <roland.mainz@nrubsig.org>] +[+NAME?shpiano - simple audio demo] +[+DESCRIPTION?\bshpiano\b is a small demo application which converts + keyboard input into 8bit Mu-law audio samples which are + send to /dev/audio.] +[+SEE ALSO?\bksh93\b(1), \bau\b(4), \baudio\b(7i)] +' + +while getopts -a "${progname}" "${shpiano_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + *) usage ;; + esac +done +shift $((OPTIND-1)) + +float -r M_PI=3.14159265358979323846 + +float sample_rate=8000. +float duration=0.10 +float freq +float w # temporary "wave" value +integer i +integer audiofd # audio device file descriptor +typeset key +typeset audio=( typeset -i currpos=0 ; typeset -a -i data=( [0]=0 ) ) # stack object + +clear +print_piano_layout + +if [[ "${AUDIODEV}" == "" ]] ; then + AUDIODEV="/dev/audio" +fi +print -u2 -f "Playing sound to device\n" "${AUDIODEV}" + +# open channel to audio device +redirect {audiofd}<>"${AUDIODEV}" +(( $? != 0 )) && fatal_error "Couldn't open audio device." + +# build pause sample +stack_init audio +for ((i=0 ; i < ((sample_rate*duration)/2.) ; i++)) ; do + stack_put_byte audio 0 +done +typeset -b pause_sample=${ bytearraytobase64 audio.data ; } + +stack_init audio +audio_put_au_header audio +typeset -b au_header=${ bytearraytobase64 audio.data ; } + +# begin playing +printf "%B" au_header >&${audiofd} + +# warning: the math used here is so wrong that your head may +# explode when you continue reading this +while read -r -N 1 key?" > " ; do + if [[ ${key} == ~(E)($'\E'|'q'|'Q') ]] ; then + break # quit + fi + + printf "\r" + if [[ -z "${notes[key_${key}]}" ]] ; then + nameref curr_note=notes["p"].val + (( freq=1.*(1./duration) )) + else + nameref curr_note=notes[key_${key}].val + (( freq=curr_note.freq )) + fi + +# printf "note=%s sample_rate=%f, freq=%f\n" "${!curr_note}" sample_rate freq >&2 + + # Create sample data if they didn't exist yet and + # store them in the "tones" array + if ! ${curr_note.sample_set} ; then + stack_init audio + + for ((i=0 ; i < (sample_rate*duration) ; i++)) ; do + # first create the sinus wave... + (( w=sin( ((i*freq)/sample_rate) * (2.*M_PI)) )) + # ...scale it to 14bit signed PCM linear and... + (( w=8192.+w*8191. )) + # ...then convert it to 8bit ulaw + # ("audio_pcmulinear14bittoulaw8bit" is unsigned but we use + # "8192" above as starting point to do the "signed to unsigned" + # conversion) ... + stack_put_byte audio $(( audio_pcmulinear14bittoulaw8bit[int(w)] )) + done + + curr_note.sample=${ bytearraytobase64 audio.data ; } + curr_note.sample_set="true" + fi + + # output sample + { + printf "%B" curr_note.sample + printf "%B" pause_sample + } >&${audiofd} +done + +# close audio device +redirect {audiofd}<&- + +print -u2 "# done." +exit 0 +#EOF. Index: src/lib/libshell/common/scripts/rssread.sh =================================================================== --- src/lib/libshell/common/scripts/rssread.sh (revision 0) +++ src/lib/libshell/common/scripts/rssread.sh (revision 1122) @@ -0,0 +1,551 @@ +#!/usr/bin/ksh93 + +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# rssread - a simple RSS2.0 reader with RSS to XHTML to +# plaintext conversion. +# + +# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant +export PATH=/usr/xpg4/bin:/bin:/usr/bin + +function printmsg +{ + print -u2 "$*" +} + +function debugmsg +{ +# printmsg "$*" +true +} + +function fatal_error +{ + print -u2 "${progname}: $*" + exit 1 +} + +# parse HTTP return code, cookies etc. +function parse_http_response +{ + nameref response="$1" + typeset h statuscode statusmsg i + + # we use '\r' as additional IFS to filter the final '\r' + IFS=$' \t\r' read -r h statuscode statusmsg # read HTTP/1.[01] <code> + [[ "$h" != ~(Eil)HTTP/.* ]] && { print -u2 -f "%s: HTTP/ header missing\n" "$0" ; return 1 ; } + [[ "$statuscode" != ~(Elr)[0-9]* ]] && { print -u2 -f "%s: invalid status code\n" "$0" ; return 1 ; } + response.statuscode="$statuscode" + response.statusmsg="$statusmsg" + + # skip remaining headers + while IFS='' read -r i ; do + [[ "$i" == $'\r' ]] && break + + # strip '\r' at the end + i="${i/~(Er)$'\r'/}" + + case "$i" in + ~(Eli)Content-Type:.*) + response.content_type="${i/~(El).*:[[:blank:]]*/}" + ;; + ~(Eli)Content-Length:[[:blank:]]*[0-9]*) + integer response.content_length="${i/~(El).*:[[:blank:]]*/}" + ;; + ~(Eli)Transfer-Encoding:.*) + response.transfer_encoding="${i/~(El).*:[[:blank:]]*/}" + ;; + esac + done + + return 0 +} + +function cat_http_body +{ + typeset emode="$1" + typeset hexchunksize="0" + integer chunksize=0 + + if [[ "${emode}" == "chunked" ]] ; then + while IFS=$'\r' read hexchunksize && + [[ "${hexchunksize}" == ~(Elri)[0-9abcdef]* ]] && + (( chunksize=16#${hexchunksize} )) && (( chunksize > 0 )) ; do + dd bs=1 count="${chunksize}" 2>/dev/null + done + else + cat + fi + + return 0 +} + +function cat_http +{ + typeset protocol="${1%://*}" + typeset path1="${1#*://}" # "http://foo.bat.net/x/y.html" ----> "foo.bat.net/x/y.html" + + typeset host="${path1%%/*}" + typeset path="${path1#*/}" + typeset port="${host##*:}" + + integer netfd + typeset -C httpresponse # http response + + # If URL did not contain a port number in the host part then look at the + # protocol to get the port number + if [[ "${port}" == "${host}" ]] ; then + case "${protocol}" in + "http") port=80 ;; + *) port="$(getent services "${protocol}" | sed 's/[^0-9]*//;s/\/.*//')" ;; + esac + else + host="${host%:*}" + fi + + printmsg "protocol=${protocol} port=${port} host=${host} path=${path}" + + # prechecks + [[ "${protocol}" == "" ]] && { print -u2 -f "%s: protocol not set.\n" "$0" ; return 1 ; } + [[ "${port}" == "" ]] && { print -u2 -f "%s: port not set.\n" "$0" ; return 1 ; } + [[ "${host}" == "" ]] && { print -u2 -f "%s: host not set.\n" "$0" ; return 1 ; } + [[ "${path}" == "" ]] && { print -u2 -f "%s: path not set.\n" "$0" ; return 1 ; } + + # open TCP channel + redirect {netfd}<>"/dev/tcp/${host}/${port}" + (( $? != 0 )) && { print -u2 -f "%s: Couldn't open %s\n" "$0" "${1}" ; return 1 ; } + + # send HTTP request + request="GET /${path} HTTP/1.1\r\n" + request+="Host: ${host}\r\n" + request+="User-Agent: rssread/ksh93 (2008-06-14; $(uname -s -r -p))\r\n" + request+="Connection: close\r\n" + print -n -- "${request}\r\n" >&${netfd} + + # collect response and send it to stdout + parse_http_response httpresponse <&${netfd} + cat_http_body "${httpresponse.transfer_encoding}" <&${netfd} + + # close connection + redirect {netfd}<&- + + return 0 +} + +function html_entity_to_ascii +{ + typeset buf + typeset entity + typeset c + typeset value + + # Todo: Add more HTML/MathML entities here + # Note we use a static variable (typeset -S) here to make sure we + # don't loose the cache data between calls + typeset -S -A entity_cache=( + # entity to ascii (fixme: add UTF-8 transliterations) + ["nbsp"]=' ' + ["lt"]='<' + ["le"]='<=' + ["gt"]='>' + ["ge"]='>=' + ["amp"]='&' + ["quot"]='"' + ["apos"]="'" + ) + + buf="" + while IFS='' read -r -N 1 c ; do + if [[ "$c" != "&" ]] ; then + print -n -r -- "${c}" + continue + fi + + entity="" + while IFS='' read -r -N 1 c ; do + case "$c" in + ";") + break + ;; + ~(Eilr)[a-z0-9#]) + entity+="$c" + continue + ;; + *) +# debugmsg "error &${entity}${c}#" + + print -n -r -- "${entity}${c}" + entity="" + continue 2 + ;; + esac + done + + value="" + if [[ "${entity_cache["${entity}"]}" != "" ]] ; then +# debugmsg "match #${entity}# = #${entity_cache["${entity}"]}#" + value="${entity_cache["${entity}"]}" + else + if [[ "${entity:0:1}" == "#" ]] ; then + # decimal literal + value="${ printf "\u[${ printf "%x" "${entity:1:8}" ; }]" ; }" + elif [[ "${entity:0:7}" == ~(Eilr)[0-9a-f]* ]] ; then + # hexadecimal literal + value="${ printf "\u[${entity:0:7}]" ; }" + else + # unknown literal - pass-through + value="ENT=|${entity}|" + fi + + entity_cache["${entity}"]="${value}" + +# debugmsg "lookup #${entity}# = #${entity_cache["${entity}"]}#" + fi + + printf "%s" "${value}" + done + + return 0 +} + +# dumb xhtml handler - no CSS, tables, images, iframes or nested +# structures are supported (and we assume that the input is correct +# xhtml). The code was written in a trial&&error manner and should be +# rewritten to parse xhtml correctly. +function handle_html +{ + # we can't use global variables here when multiple callbacks use the same + # callback function - but we can use the callback associative array for + # variable storage instead + nameref callbacks=${1} + typeset tag_type="$2" + typeset tag_value="$3" + + case "${tag_type}" in + tag_begin) + case "${tag_value}" in + br) printf "\n" ;; + hr) printf "\n-------------------------------------\n" ;; + pre) callbacks["html_pre"]='true' ;; + p) printf "\n" ;; + esac + ;; + + tag_end) + case "${tag_value}" in + pre) callbacks["html_pre"]='false' ;; + esac + ;; + + tag_text) + if ${callbacks["html_pre"]} ; then + printf "%s" "${tag_value}" + else + # compress spaces/newlines/tabs/etc. + printf "%s" "${tag_value//+([\n\r\t\v[:space:][:blank:]])/ }" + fi + ;; + + document_start) + callbacks["html_pre"]='false' + ;; + document_end) ;; + esac + + return 0 +} + +function handle_rss +{ + # we can't use global variables here when multiple callbacks use the same + # callback function - but we can use the callback associative array for + # variable storage instead + nameref callbacks=${1} + typeset tag_type="$2" + typeset tag_value="$3" + + case "${tag_type}" in + tag_begin) + case "${tag_value}" in + item) + item["title"]="" + item["link"]="" + item["tag"]="" + item["description"]="" + ;; + esac + callbacks["textbuf"]="" + ;; + tag_end) + case "${tag_value}" in + item) + # note that each RSS item needs to be converted seperately from RSS to HTML to plain text + # to make sure that the state of one RSS item doesn't affect others + ( + printf $"<br />#### RSS item: title: %s ####" "${item["title"]}" + printf $"<br />## author: %s" "${item["author"]}" + printf $"<br />## link: %s" "${item["link"]}" + printf $"<br />## date: %s" "${item["pubDate"]}" + printf $"<br />## begin description:" + printf $"<br />%s<br />" "${item["description"]}" + printf $"<br />## end description<br />" + print # extra newline to make sure the sed pipeline gets flushed + ) | + html_entity_to_ascii | # convert XML entities (e.g. decode RSS content to HTML code) + xml_tok "xhtmltok_cb" | # convert HTML to plain text + html_entity_to_ascii # convert HTML entities + ;; + title) item["title"]="${callbacks["textbuf"]}" ; callbacks["textbuf"]="" ;; + link) item["link"]="${callbacks["textbuf"]}" ; callbacks["textbuf"]="" ;; + dc:creator | author) item["author"]="${callbacks["textbuf"]}" ; callbacks["textbuf"]="" ;; + dc:date | pubDate) item["pubDate"]="${callbacks["textbuf"]}" ; callbacks["textbuf"]="" ;; + description) item["description"]="${callbacks["textbuf"]}" ; callbacks["textbuf"]="" ;; + esac + callbacks["textbuf"]="" + ;; + tag_text) + callbacks["textbuf"]+="${tag_value}" + ;; + document_start) ;; + document_end) ;; + esac + return 0 +} + +function xml_tok +{ + typeset buf="" + typeset namebuf="" + typeset attrbuf="" + typeset c="" + typeset isendtag # bool: true/false + typeset issingletag # bool: true/false (used for tags like "<br />") + nameref callbacks=${1} + + [[ ! -z "${callbacks["document_start"]}" ]] && ${callbacks["document_start"]} "${1}" "document_start" + + while IFS='' read -r -N 1 c ; do + isendtag=false + + if [[ "$c" == "<" ]] ; then + # flush any text content + if [[ "$buf" != "" ]] ; then + [[ ! -z "${callbacks["tag_text"]}" ]] && ${callbacks["tag_text"]} "${1}" "tag_text" "$buf" + buf="" + fi + + IFS='' read -r -N 1 c + if [[ "$c" == "/" ]] ; then + isendtag=true + else + buf="$c" + fi + IFS='' read -r -d '>' c + buf+="$c" + + # handle comments + if [[ "$buf" == ~(El)!-- ]] ; then + # did we read the comment completely ? + if [[ "$buf" != ~(Elr)!--.*-- ]] ; then + buf+=">" + while [[ "$buf" != ~(Elr)!--.*-- ]] ; do + IFS='' read -r -N 1 c || break + buf+="$c" + done + fi + + [[ ! -z "${callbacks["tag_comment"]}" ]] && ${callbacks["tag_comment"]} "${1}" "tag_comment" "${buf:3:${#buf}-5}" + buf="" + continue + fi + + # check if the tag starts and ends at the same time (like "<br />") + if [[ "${buf}" == ~(Er).*/ ]] ; then + issingletag=true + buf="${buf%*/}" + else + issingletag=false + fi + + # check if the tag has attributes (e.g. space after name) + if [[ "$buf" == ~(E)[[:space:][:blank:]] ]] ; then + namebuf="${buf%%~(E)[[:space:][:blank:]].*}" + attrbuf="${buf#~(E).*[[:space:][:blank:]]}" + else + namebuf="$buf" + attrbuf="" + fi + + if ${isendtag} ; then + [[ ! -z "${callbacks["tag_end"]}" ]] && ${callbacks["tag_end"]} "${1}" "tag_end" "$namebuf" + else + [[ ! -z "${callbacks["tag_begin"]}" ]] && ${callbacks["tag_begin"]} "${1}" "tag_begin" "$namebuf" "$attrbuf" + + # handle tags like <br/> (which are start- and end-tag in one piece) + if ${issingletag} ; then + [[ ! -z "${callbacks["tag_end"]}" ]] && ${callbacks["tag_end"]} "${1}" "tag_end" "$namebuf" + fi + fi + buf="" + else + buf+="$c" + fi + done + + [[ ! -z "${callbacks["document_end"]}" ]] && ${callbacks["document_end"]} "${1}" "document_end" "exit_success" + + print # final newline to make filters like "sed" happy +} + +# return the value of LC_MESSAGES needed for subprocesses which +# want to run in a different locale/encoding +function get_lc_messages +{ + [[ "${LC_ALL}" != "" ]] && { print "${LC_ALL}" ; return 0 ; } + [[ "${LC_MESSAGES}" != "" ]] && { print "${LC_MESSAGES}" ; return 0 ; } + [[ "${LANG}" != "" ]] && { print "${LANG}" ; return 0 ; } + print "C" ; return 0 +} + +function do_rssread +{ + # set unicode locale since RSS is encoded in UTF-8 + # (and make sure $LC_MESSAGES is set to the parent + # process's locale that all error messages are using + # the callers locale/encoding) + export \ + LC_MESSAGES="${ get_lc_messages ; }" \ + LC_MONETARY="en_US.UTF-8" \ + LC_NUMERIC="en_US.UTF-8" \ + LC_COLLATE="en_US.UTF-8" \ + LC_CTYPE="en_US.UTF-8" \ + LC_TIME="en_US.UTF-8" \ + LANG="en_US.UTF-8" + + # need extra newline after cat_http to terminate line with $'\n' + { cat_http "$1" ; print ; } | + xml_tok "rsstok_cb" + return 0 +} + +function usage +{ + OPTIND=0 + getopts -a "${progname}" "${rssread_usage}" OPT '-?' + exit 2 +} + +# make sure we use the ksh93 builtin versions +builtin basename +builtin cat +builtin printf + +typeset -A rsstok_cb # callbacks for xml_tok +rsstok_cb["tag_begin"]="handle_rss" +rsstok_cb["tag_end"]="handle_rss" +rsstok_cb["tag_text"]="handle_rss" +rsstok_cb["textbuf"]="" + +typeset -A xhtmltok_cb # callbacks for xml_tok +xhtmltok_cb["tag_begin"]="handle_html" +xhtmltok_cb["tag_end"]="handle_html" +xhtmltok_cb["tag_text"]="handle_html" +xhtmltok_cb["textbuf"]="" +xhtmltok_cb["html_pre"]='false' + +typeset -A item + +typeset -A bookmark_urls + +# "ramdom" urls for testing +bookmark_urls=( + ["google_blogs_ksh"]="http://blogsearch.google.com/blogsearch_feeds?hl=en&scoring=d&q=(%22ksh93%22%7C%22ksh+93%22+%7C+%22korn93%22+%7C+%22korn+93%22)&ie=utf-8&num=100&output=rss" + ["ksh93_integration"]="http://www.opensolaris.org/rss/os/project/ksh93-integration/announcements/rss2.xml" + # some Sun staff/sites + ["blogs_sun_com"]="http://blogs.sun.com/main/feed/entries/rss" + ["jmcp"]="http://www.jmcp.homeunix.com/roller/jmcp/feed/entries/rss" + ["katakai"]="http://blogs.sun.com/katakai/feed/entries/rss" + ["alanc"]="http://blogs.sun.com/alanc/feed/entries/rss" + ["planetsun"]="http://www.planetsun.org/rss20.xml" + ["planetsolaris"]="http://www.planetsolaris.org/rss20.xml" + ["planetopensolaris"]="http://planet.opensolaris.org/rss20.xml" + ["theregister_uk"]="http://www.theregister.co.uk/headlines.rss" + ["heise"]="http://www.heise.de/newsticker/heise.rdf" + ["slashdot"]="http://rss.slashdot.org/Slashdot/slashdot" +) + +typeset progname="${ basename "${0}" ; }" + +typeset -r rssread_usage=$'+ +[-?\n@(#)\$Id: rssread (Roland Mainz) 2008-06-14 \$\n] +[-author?Roland Mainz <roland.mainz@sun.com>] +[+NAME?rssread - fetch RSS messages and convert them to plain text] +[+DESCRIPTION?\brssread\b RSS to plain text converter + which fetches RSS streams via HTTP and converts them from + RSS to HTML to plain text in the current locale/encoding.] +[I:noiconv?Do not convert data from UTF-8 to current locale/encoding.] + +[ url ] + +[+SEE ALSO?\bksh93\b(1), \bshnote\b(1)] +' + +typeset noiconv=false + +while getopts -a "${progname}" "${rssread_usage}" OPT ; do +# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" + case ${OPT} in + I) noiconv=true ;; + +I) noiconv=false ;; + *) usage ;; + esac +done +shift $((OPTIND-1)) + +typeset url="$1" + +if [[ "${url}" == "" ]] ; then + fatal_error $"No url given." +fi + +if [[ "${bookmark_urls[${url}]}" != "" ]] ; then + printmsg $"Using bookmark ${url} = ${bookmark_urls[${url}]}" + url="${bookmark_urls[${url}]}" +fi + +if ${noiconv} ; then + do_rssread "${url}" +else + do_rssread "${url}" | iconv -f "UTF-8" - - +fi + +exit 0 +#EOF. Index: src/lib/libshell/common/fun/rssread =================================================================== --- src/lib/libshell/common/fun/rssread (revision 974) +++ src/lib/libshell/common/fun/rssread (revision 1122) @@ -1,414 +0,0 @@ -#!/bin/ksh93 - -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "@(#)rssread 1.1 07/06/27 SMI" -# - -# -# rssread - a simple RSS2.0 reader with RSS to XHTML to -# plaintext conversion. -# - -# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant -export PATH=/usr/xpg4/bin:/bin:/usr/bin - -function printmsg -{ - print -u 2 "$@" -} - -function debugmsg -{ -# printmsg "$@" -true -} - -function fatal_error -{ - print -u 2 "${progname}: $@" - exit 1 -} - -function cat_http -{ -( - protocol="${1%://*}" - path1="${1#*://}" # "http://foo.bat.net/x/y.html" ----> "foo.bat.net/x/y.html" - - host="${path1%%/*}" - path="${path1#*/}" - port="${host##*:}" - - # If URL did not contain a port number in the host part then look at the - # protocol to get the port number - if [ "${port}" = "${host}" ] ; then - case "${protocol}" in - "http") port=80 ;; - *) port="$(getent services "${protocol}" | sed 's/[^0-9]*//;s/\/.*//')" ;; - esac - else - host="${host%:*}" - fi - - printmsg "protocol=${protocol} port=${port} host=${host} path=${path}" - - # prechecks - [ "${protocol}" = "" ] && fatal_error "protocol not set." - [ "${port}" = "" ] && fatal_error "port not set." - [ "${host}" = "" ] && fatal_error "host not set." - [ "${path}" = "" ] && fatal_error "path not set." - - # open TCP channel - exec 3<>"/dev/tcp/${host}/${port}" - - # send HTTP request - request="GET /${path} HTTP/1.0\n" - request+="Host: ${host}\n" - request+="User-Agent: ksh93/rssread (2007-01-16; $(uname -s -r -p))\n" - print "${request}\n" >&3 - - # collect response and send it to stdout - cat <&3 -) -} - -function html_entity_to_ascii -{ - typeset -A entity_cache - - # Todo: Add more HTML/MathML entities here - entity_cache["nbsp"]=" " - entity_cache["lt"]="<" - entity_cache["gt"]=">" - entity_cache["amp"]="&" - entity_cache["quot"]="\"" - entity_cache["apos"]="'" - - buf="" - while read -r -N 1 c ; do - if [ "$c" != "&" ] ; then - printf "%s" "${c}" - continue - fi - - entity="" - while read -r -N 1 c ; do - case "$c" in - ";") - break - ;; - ~(Eilr)[a-z0-9#]) - entity+="$c" - continue - ;; - *) - debugmsg "error &${entity}${c}#" - - print -n "${entity}${c}" - entity="" - continue 2 - ;; - esac - done - - value="" - if [ "${entity_cache["${entity}"]}" != "" ] ; then - debugmsg "match #${entity}# = #${entity_cache["${entity}"]}#" - value="${entity_cache["${entity}"]}" - else - if [ "${entity:0:1}" = "#" ] ; then - # decimal literal - value="$(printf "\u[$(printf "%x" "${entity:1:8}")]")" - elif [[ "${entity:0:7}" = ~(Eilr)[0-9a-f]* ]] ; then - # hexadecimal literal - value="$(printf "\u[${entity:0:7}]")" - else - # unknown literal - pass-through - value="<ENT=${entity}>" - fi - - entity_cache["${entity}"]="${value}" - - debugmsg "lookup #${entity}# = #${entity_cache["${entity}"]}#" - fi - - printf "%s" "$value" - done -} - -# dumb xhtml handler - no CSS, tables, images, iframes or nested -# structures are supported (and we assume that the input is correct -# xhtml). The code was written in a trial&&error manner and should be -# rewritten to parse xhtml correctly. -function handle_html -{ - # we can't use global variables here when multiple callbacks use the same - # callback function - but we can use the callback associative array for - # variable storage instead - nameref callbacks=${1} - tag_type="$2" - tag_value="$3" - - case "${tag_type}" in - tag_begin) - case "${tag_value}" in - br*) printf "\n" ;; - hr*) printf "\n-------------------------------------\n" ;; - pre*) callbacks["html_pre"]=1 ;; - p*) printf "\n" ;; - esac - ;; - - tag_end) - case "${tag_value}" in - pre*) callbacks["html_pre"]=0 ;; - esac - ;; - - tag_text) - if [ ${callbacks["html_pre"]} -eq 1 ] ; then - printf "%s" "${tag_value}" - else - # compress spaces/newlines/tabs/etc. - printf "%s" "${tag_value/+([\n\r\t\v[:space:][:blank:]])/ }" - fi - ;; - - document_start) - callbacks["html_pre"]=0 - ;; - document_end) ;; - esac -} - -function handle_rss -{ - # we can't use global variables here when multiple callbacks use the same - # callback function - but we can use the callback associative array for - # variable storage instead - nameref callbacks=${1} - tag_type="$2" - tag_value="$3" - - case "${tag_type}" in - tag_begin) - case "${tag_value}" in - item*) - item["title"]="" - item["link"]="" - item["tag"]="" - item["description"]="" - ;; - esac - callbacks["textbuf"]="" - ;; - tag_end) - case "${tag_value}" in - item*) - # note that each RSS item needs to be converted seperately from RSS to HTML to plain text - # to make sure that the state of one RSS item doesn't affect others - ( - printf $"<br />#### RSS item: title: %s ####" "${item["title"]}" - printf $"<br />## author: %s" "${item["author"]}" - printf $"<br />## link: %s" "${item["link"]}" - printf $"<br />## date: %s" "${item["pubDate"]}" - printf $"<br />## begin description:" - printf $"<br />%s<br />" "${item["description"]}" - printf $"<br />## end description<br />" - print # extra newline to make sure the sed pipeline gets flushed - ) | - html_entity_to_ascii | # convert XML entities (e.g. decode RSS content to HTML code) - xml_tok "xhtmltok_cb" | # convert HTML to plain text - html_entity_to_ascii # convert HTML entities - ;; - title*) item["title"]="${callbacks["textbuf"]}" ; callbacks["textbuf"]="" ;; - link*) item["link"]="${callbacks["textbuf"]}" ; callbacks["textbuf"]="" ;; - dc:creator* | author*) item["author"]="${callbacks["textbuf"]}" ; callbacks["textbuf"]="" ;; - dc:date* | pubDate*) item["pubDate"]="${callbacks["textbuf"]}" ; callbacks["textbuf"]="" ;; - description*) item["description"]="${callbacks["textbuf"]}" ; callbacks["textbuf"]="" ;; - esac - callbacks["textbuf"]="" - ;; - tag_text) - callbacks["textbuf"]+="${tag_value}" - ;; - document_start) ;; - document_end) ;; - esac -} - -function xml_tok -{ - typeset buf="" - typeset c="" - - nameref callbacks=${1} - - [ ! -z "${callbacks["document_start"]}" ] && ${callbacks["document_start"]} "${1}" "document_start" - - while read -N 1 c -d '\0'; do - isendtag=false - - if [ "$c" = "<" ] ; then - if [ "$buf" != "" ] ; then - [ ! -z "${callbacks["tag_text"]}" ] && ${callbacks["tag_text"]} "${1}" "tag_text" "$buf" - buf="" - fi - - read -N 1 c -d '\0' - if [ "$c" = "/" ] ; then - isendtag=true - else - buf="$c" - fi - read -d '>' c - buf+="$c" - - if ${isendtag} ; then - [ ! -z "${callbacks["tag_end"]}" ] && ${callbacks["tag_end"]} "${1}" "tag_end" "$buf" - else - [ ! -z "${callbacks["tag_begin"]}" ] && ${callbacks["tag_begin"]} "${1}" "tag_begin" "$buf" - - # handle tags like <br/> (which are start- and end-tag in one piece) - if [[ "${buf}" = ~(Er).*/ ]] ; then - [ ! -z "${callbacks["tag_end"]}" ] && ${callbacks["tag_end"]} "${1}" "tag_end" "$buf" - fi - fi - buf="" - else - buf+="$c" - fi - done - - [ ! -z "${callbacks["document_end"]}" ] && ${callbacks["document_start"]} "${1}" "document_end" "exit_success" - - print # final newline to make filters like "sed" happy -} - -# return the value of LC_MESSAGES needed for subprocesses which -# want to run in a different locale/encoding -function get_lc_messages -{ - [ "${LC_ALL}" != "" ] && { print "${LC_ALL}" ; return 0 ; } - [ "${LC_MESSAGES}" != "" ] && { print "${LC_MESSAGES}" ; return 0 ; } - [ "${LANG}" != "" ] && { print "${LANG}" ; return 0 ; } - print "C" ; return 0 -} - -function usage -{ - OPTIND=0 - getopts -a "${progname}" "${USAGE}" OPT '-?' - exit 2 -} - -# make sure we use the ksh93 builtin versions -builtin cat -builtin printf - -typeset -A rsstok_cb # callbacks for xml_tok -rsstok_cb["tag_begin"]="handle_rss" -rsstok_cb["tag_end"]="handle_rss" -rsstok_cb["tag_text"]="handle_rss" -rsstok_cb["textbuf"]="" - -typeset -A xhtmltok_cb # callbacks for xml_tok -xhtmltok_cb["tag_begin"]="handle_html" -xhtmltok_cb["tag_end"]="handle_html" -xhtmltok_cb["tag_text"]="handle_html" -xhtmltok_cb["textbuf"]="" -xhtmltok_cb["html_pre"]=0 - -typeset -A item - -typeset -A bookmark_urls - -# "ramdom" urls for testing -bookmark_urls=( - ["google_blogs_ksh"]="http://blogsearch.google.com/blogsearch_feeds?hl=en&scoring=d&q=ksh&ie=utf-8&num=100&output=rss" - ["ksh93_integration"]="http://www.opensolaris.org/rss/os/project/ksh93-integration/announcements/rss2.xml" - ["blogs_sun_com"]="http://blogs.sun.com/main/feed/entries/rss" - ["jmcp"]="http://www.jmcp.homeunix.com/roller/rss/jmcp" - ["katakai"]="http://blogs.sun.com/katakai/feed/entries/rss" - ["planetsun"]="http://www.planetsun.org/rss20.xml" - ["planetsolaris"]="http://www.planetsolaris.org/rss20.xml" - ["planetopensolaris"]="http://planet.opensolaris.org/rss20.xml" -) - -progname="${0}" - -USAGE=$' -[-? -@(#)\$Id: rssread (Roland Mainz) 2007-06-05 \$ -] -[+NAME?rssread - fetch RSS messages and convert them to plain text] -[+DESCRIPTION?\brssread\b RSS to plain text converter - which fetches RSS streams via HTTP and converts them from RSS to HTML to plain UTF-8 text.] - -[ url ] - -[+SEE ALSO?\bksh93\b(1)] -' - -while getopts -a "${progname}" "${USAGE}" OPT ; do -# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" - case ${OPT} in - *) usage ;; - esac -done -shift ${OPTIND}-1 - -url="$1" - -if [ "$url" = "" ] ; then - fatal_error $"No url given." -fi - -if [ "${bookmark_urls[${url}]}" != "" ] ; then - printmsg $"Using bookmark ${url} = ${bookmark_urls[${url}]}" - url="${bookmark_urls[${url}]}" -fi - -( - # set unicode locale since RSS is encoded in UTF-8 - # (and make sure $LC_MESSAGES is set to the parent - # process's locale that all error messages are using - # the callers locale/encoding) - export \ - LC_MESSAGES="$(get_lc_messages)" \ - LC_MONETARY="en_US.UTF-8" \ - LC_NUMERIC="en_US.UTF-8" \ - LC_COLLATE="en_US.UTF-8" \ - LC_CTYPE="en_US.UTF-8" \ - LC_TIME="en_US.UTF-8" \ - LANG="en_US.UTF-8" - - cat_http "$url" | - xml_tok "rsstok_cb" -) # | iconv -f "UTF-8" - - - -#EOF. Index: src/lib/libshell/common/fun/termclock =================================================================== --- src/lib/libshell/common/fun/termclock (revision 974) +++ src/lib/libshell/common/fun/termclock (revision 1122) @@ -1,267 +0,0 @@ -#!/bin/ksh93 - -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "@(#)termclock 1.1 07/06/27 SMI" -# - -# -# termclock - a simple analog clock for terminals -# - -# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant -export PATH=/usr/xpg4/bin:/bin:/usr/bin - -function fatal_error -{ - print -u 2 "${progname}: $@" - exit 1 -} - -# cache tput values (to avoid |fork()|'ing a "tput" child every second) -function tput_cup -{ - integer y="$1" x="$2" - nameref c=tput_cup_cache["${y}_${x}"] - - if [ "$c" == "" ] ; then - # fast path for known terminal types - if [[ ${TERM} = ~(Elr)(vt100|vt220|xterm|xterm-color|dtterm) ]] ; then - c="$(printf "\E[%d;%dH" $((y+1)) $((x+1)))" - else - c="$(tput cup $y $x)" - fi - fi - - print -n "$c" -} - -function draw_clock -{ - float angle a - float x y - - for(( angle=0.0 ; angle < 360. ; angle+=6 )) ; do - (( a=angle/360.*(2*M_PI) )) - - (( x=clock.len_x*cos(a) )) - (( y=clock.len_y*sin(a) )) - tput_cup $(( y+clock.middle_y )) $(( x+clock.middle_x )) - - # add "mark" every 30 degrees - if (( int(angle)%30 == 0 )) ; then - print -n "0" - else - print -n "x" - fi - done -} - -function draw_hand -{ - float angle="$1" a - typeset ch="$2" - float length="$3" - float x y - - (( a=angle/360.*(2*M_PI) )) - - for(( s=0.0 ; s < 10. ; s+=0.5 )) ; do - (( x=(clock.len_x*(s/10.)*(length/100.))*cos(a) )) - (( y=(clock.len_y*(s/10.)*(length/100.))*sin(a) )) - - tput_cup $(( y+clock.middle_y )) $(( x+clock.middle_x )) - print -n "${ch}" - done -} - -function draw_clock_hand -{ - nameref hand=$1 - - draw_hand $(( 360.*(hand.val/hand.scale)-90. )) "${hand.ch}" ${hand.length} -} - -function clear_clock_hand -{ - nameref hand=$1 - - draw_hand $(( 360.*(hand.val/hand.scale)-90. )) " " ${hand.length} -} - -function main_loop -{ - typeset c - - # note: we can't use subshells when writing to the double-buffer file because this - # will render the tput value cache useless - while true ; do - if ${init_screen} ; then - init_screen="false" - - # "resize" is needed because older versions of ksh93 may have - # trouble with getting the right terminal size at startup - [ -x "/usr/X11/bin/resize" ] && eval "$(/usr/X11/bin/resize -u)" || - [ -x "/usr/X11R6/bin/resize" ] && eval "$(/usr/X11R6/bin/resize -u)" || - [ -x "/usr/openwin/bin/resize" ] && eval "$(/usr/openwin/bin/resize -u)" || - fatal_error "resize not found." - - (( clock.middle_x=COLUMNS/2.-.5 )) - (( clock.middle_y=LINES/2.-.5 )) - (( clock.len_x=COLUMNS/2-2 )) - (( clock.len_y=LINES/2-2 )) - - { - clear - draw_clock - } >&6 - fi - - { - (( $(date +"hours.val=%H , minutes.val=%M , seconds.val=%S") )) - - # small trick to get a smooth "analog" flair - (( hours.val+=minutes.val/60. )) - (( minutes.val+=seconds.val/60. )) - - draw_clock_hand seconds - draw_clock_hand minutes - draw_clock_hand hours - - # move cursor to home position - tput_cup 0 0 - } >&6 - - 6<#((0)) - cat <&6 - - 6<&- ; rm -f "${scratchfile}" ; exec 6<>"${scratchfile}" - - c="" ; read -t ${update_interval} -n 1 c - if [ "$c" != "" ] ; then - case "$c" in - ~(Ei)q | $'\E') return 0 ;; - esac - fi - - { - clear_clock_hand hours - clear_clock_hand minutes - clear_clock_hand seconds - } >&6 - done -} - -function usage -{ - OPTIND=0 - getopts -a "${progname}" "${USAGE}" OPT '-?' - exit 2 -} - -# program start -progname="${0}" - -builtin date -builtin rm -builtin printf - -typeset -A tput_cup_cache - -float -r M_PI=3.14159265358979323846 - -clock=( - float middle_x - float middle_y - integer len_x - integer len_y -) - -typeset init_screen="true" - -# set clock properties -seconds=( float val - typeset ch - float scale - integer length ) -minutes=( float val - typeset ch - float scale - integer length ) -hours=( float val - typeset ch - float scale - integer length ) - -seconds.length=90 seconds.scale=60 seconds.ch="s" -minutes.length=75 minutes.scale=60 minutes.ch="m" -hours.length=50 hours.scale=12 hours.ch="h" - -float update_interval=0.9 - -USAGE=$' -[-? -@(#)\$Id: termclock (Roland Mainz) 2007-06-05 \$ -] -[+NAME?termclock - analog clock for terminals] -[+DESCRIPTION?\btermclock\b is an analog clock for terminals. - The termclock program displays the time in analog or digital - form. The time is continuously updated at a frequency which - may be specified by the user.] -[u:update?Update interval (defaults to 0.9 seconds).]:[interval] -[+SEE ALSO?\bksh93\b(1), \bxclock\b(1)] -' - -while getopts -a "${progname}" "${USAGE}" OPT ; do -# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" - case ${OPT} in - u) update_interval=${OPTARG} ;; - *) usage ;; - esac -done -shift ${OPTIND}-1 - -# prechecks -which tput >/dev/null || fatal_error "tput not found." -which mktemp >/dev/null || fatal_error "mktemp not found." -(( update_interval < 0. || update_interval > 7200. )) && fatal_error "invalid update_interval value." - -# create temporary file for double-buffering and register an EXIT trap -# to remove this file when the shell interpreter exits -scratchfile="$(mktemp /tmp/termclock.pid$$.XXXXXX)" -if [ -z "${scratchfile}" ]; then exit 1; fi -trap 'rm -f "${scratchfile}"' EXIT -rm -f "${scratchfile}" ; exec 6<>"${scratchfile}" - -# regiter trap to handle window size changes -trap 'init_screen="true"' WINCH - -main_loop - -# exiting - put cursor below clock -tput_cup $((LINES-2)) 0 - -# EOF. Index: src/lib/libshell/common/fun/mandelbrotset1 =================================================================== --- src/lib/libshell/common/fun/mandelbrotset1 (revision 974) +++ src/lib/libshell/common/fun/mandelbrotset1 (revision 1122) @@ -1,234 +0,0 @@ -#!/bin/ksh93 - -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "@(#)mandelbrotset1 1.1 07/06/27 SMI" -# - -# -# mandelbrotset1 - a simple mandelbrot set generation and -# parallel execution demo -# - -# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant -export PATH=/usr/xpg4/bin:/bin:/usr/bin:/usr/X11/bin:/usr/X11R6/bin:/usr/openwin/bin - -function printmsg -{ - print -u 2 "$@" -} - -function fatal_error -{ - print -u 2 "${progname}: $@" - exit 1 -} - -function print_color -{ - print -n "${symbollist:${1}:1}" -} - -function mandelbrot -{ - float x=$1 - float y=$2 - float xx - float yy - float x1=$3 - float y1=$4 - integer iteration=$5 - integer max_iteration=$6 - float mag - - for (( mag=0 ; mag < max_mag && iteration < max_iteration ; iteration++ )) ; do - (( xx=x*x )) - (( yy=y*y )) - (( mag=xx+yy )) - - (( y=x*y*2+y1 )) - (( x=xx-yy+x1 )) - done - - print ${iteration} - - return 0 -} - -function loop_serial -{ - for (( y=y_min ; y < y_max ; y+=stepwidth )) ; do - for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do - print_color $(mandelbrot ${x} ${y} ${x} ${y} 1 ${symbollistlen}) - done - - print - done -} - -function loop_parallel -{ - integer numjobs=0 - # the following calculation suffers from rounding errors - integer lines_per_job=$(( ((m_height+(numcpus-1)) / numcpus) )) - - printmsg "# lines_per_job=${lines_per_job}" - printmsg "# numcpus=${numcpus}" - - # "renice" worker jobs - set -o bgnice - - if [ "${TMPDIR}" = "" ] ; then - TMPDIR="/tmp" - fi - - # try to generate a job identifer prefix which is unique across multiple hosts - jobident="job_host_$(uname -n)pid_$$_ppid${PPID}" - - printmsg $"## prepare..." - for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do - rm -f "${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput" - - let numjobs++ - done - - printmsg $"## running ${numjobs} children..." - for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do - ( - for (( ; y < y_max && lines_per_job-- > 0 ; y+=stepwidth )) ; do - for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do - print_color $(mandelbrot ${x} ${y} ${x} ${y} 1 ${symbollistlen}) - done - - print - done >"${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput" - ) & - done - - printmsg $"## waiting for ${numjobs} children..." - wait - - printmsg $"## output:" - for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do - print "$(cat "${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput")" - rm "${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput" - done -} - -function usage -{ - OPTIND=0 - getopts -a "${progname}" "${USAGE}" OPT '-?' - exit 2 -} - -# main -builtin printf -builtin cat -builtin rm -builtin sleep -builtin uname # loop_parallel needs the ksh93 builtin version to generate unique job file names - -float x_max -float x_min -float y_max -float y_min -float m_width -float m_height -float max_mag -float stepwidth -integer numcpus - -# make sure ${COLUMN} and ${LINES} are set -eval $(resize -u) - -symbollist=' .:0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%#' -symbollistlen=$(( ${#symbollist} - 1)) -mode="parallel" -progname="${0}" -max_mag=400 -stepwidth=0.1 -numcpus=16 - -let m_width=COLUMNS-1 m_height=LINES-2 - -progname="${0}" - -USAGE=$' -[-? -@(#)\$Id: mandelbrotset1 (Roland Mainz) 2007-06-05 \$ -] -[+NAME?mandelbrotset1 - generate mandelbrot set fractals with ksh93] -[+DESCRIPTION?\bmandelbrotset1\b mandelbrot set fractal generator - which runs either in serial or parallel mode (using multiple worker jobs).] -[w:width?Width of fractal.]:[width] -[h:height?Height of fractal.]:[height] -[s:symbols?Symbols to build the fractal from.]:[symbolstring] -[m:mag?Magnification level.]:[magnificationlevel] -[p:stepwidth?Width per step.]:[widthperstep] -[S:serial?Run in serial mode.] -[P:parallel?Run in parallel mode.] -[M:mode?Execution mode.]:[mode] -[C:numcpus?Number of processors used for parallel execution.]:[numcpus] -[+SEE ALSO?\bjuliaset1\b(1), \bksh93\b(1)] -' - -while getopts -a "${progname}" "${USAGE}" OPT ; do -# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" - case ${OPT} in - w) m_width="${OPTARG}" ;; - h) m_height="${OPTARG}" ;; - s) symbollist="${OPTARG}" ;; - m) max_mag="${OPTARG}" ;; - p) stepwidth="${OPTARG}" ;; - S) mode="serial" ;; - P) mode="parallel" ;; - M) mode="${OPTARG}" ;; - C) numcpus="${OPTARG}" ;; - *) usage ;; - esac -done -shift ${OPTIND}-1 - -printmsg "# width=${m_width}" -printmsg "# height=${m_height}" -printmsg "# max_mag=${max_mag}" -printmsg "# stepwidth=${stepwidth}" -printmsg "# symbollist='${symbollist}'" -printmsg "# mode=${mode}" - -symbollistlen=$(( ${#symbollist} - 1)) - -let x_max=m_width*stepwidth/2. x_min=-x_max -let y_max=m_height*stepwidth/2. y_min=-y_max - -case "${mode}" in - parallel) loop_parallel ;; - serial) loop_serial ;; - *) fatal_error $"Unknown mode \"${mode}\"." -esac - -# EOF. Index: src/lib/libshell/common/fun/gnaw =================================================================== --- src/lib/libshell/common/fun/gnaw (revision 974) +++ src/lib/libshell/common/fun/gnaw (revision 1122) @@ -1,1029 +0,0 @@ -#!/bin/ksh93 - -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# - -# -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "@(#)gnaw 1.1 07/06/27 SMI" -# - -# -# gnaw - a simple ksh93 technology demo -# -# Note that this script has been written with the main idea to show -# many of ksh93's new features (comparing to ksh88/bash) and not -# as an example of efficient&&clean script code. -# - -# Solaris needs /usr/xpg4/bin/ because the tools in /usr/bin are not POSIX-conformant -export PATH=/usr/xpg4/bin:/bin:/usr/bin - -function print_setcursorpos -{ - print -n "${vtcode[cup_${1}_${2}]}" -} - -function beep -{ - ${quiet} || print -n "${vtcode["bel"]}" -} - -function fatal_error -{ - print -u 2 "${progname}: $@" - exit 1 -} - -function print_levelmap -{ - integer screen_y_offset=$1 - integer start_y_pos=$2 # start at this line in the map - integer max_numlines=$3 # maximum lines we're allowed to render - integer x - integer y - line="" - - print_setcursorpos 0 ${screen_y_offset} - - for (( y=start_y_pos; (y-start_y_pos) < max_numlines && y < levelmap["max_y"] ; y++ )) ; do - line="" - for (( x=0 ; x < levelmap["max_x"] ; x++ )) ; do - line+="${levelmap["${x}_${y}"]}" - done - - print "${line} " - done - - # print lines filled with spaces for each line not filled - # by the level map - line="${vtcode["spaceline"]:0:${levelmap["max_x"]}}" - for (( ; (y-start_y_pos) < max_numlines ; y++ )) ; do - print "${line} " - done -} - -function level_completed -{ - render_buffer="$( - print -n "${vtcode["clear"]}" - cat <<ENDOFTEXT - - # ###### # # ###### # - # # # # # # - # ##### # # ##### # - # # # # # # - # # # # # # - ###### ###### ## ###### ###### - - (Good job) - - ##### #### # # ###### - # # # # ## # # - # # # # # # # ##### - # # # # # # # # - # # # # # ## # - ##### #### # # ###### - - -ENDOFTEXT - - printf " SCORE: --> %s <--\n" "${player["score"]}" - printf " LIVES: --> %s <--\n" "${player["lives"]}" - )" - print "${render_buffer}" - - # wait five seconds and swallow any user input - for (( i=0 ; i < 50 ; i++ )) ; do - read -t 0.1 -n 1 dummy - done - - print "Press any key to continue..." - # wait five secs or for a key - read -t 5 -n 1 dummy -} - -function game_over -{ - render_buffer="$( - print -n "${vtcode["clear"]}" - cat <<ENDOFTEXT - - #### ## # # ###### - # # # # ## ## # - # # # # ## # ##### - # ### ###### # # # - # # # # # # # - #### # # # # ###### - - (LOSER!) - - #### # # ###### ##### - # # # # # # # - # # # # ##### # # - # # # # # ##### - # # # # # # # - #### ## ###### # # - -ENDOFTEXT - - printf "\n SCORE: --> %s <--\n" "${player["score"]}" - )" - print "${render_buffer}" - - # wait five seconds and swallow any user input - for (( i=0 ; i < 50 ; i++ )) ; do - read -t 0.1 -n 1 dummy - done - - print "Press any key to continue..." - # wait five secs or for a key - read -t 5 -n 1 dummy -} - -function run_logo -{ - render_buffer="$( - cat <<ENDOFTEXT - - ##### # # # # # ### -# # ## # # # # # # ### -# # # # # # # # # ### -# #### # # # # # # # # # -# # # # # ####### # # # -# # # ## # # # # # ### - ##### # # # # ## ## ### -ENDOFTEXT - )" - print "${vtcode["clear"]}${render_buffer}" - - # wait two seconds and swallow any user input - for (( i=0 ; i < 20 ; i++ )) ; do - read -t 0.1 -n 1 dummy - done - - print "\n (The KornShell 93 maze game)" - - attract_mode -} - -function attract_mode -{ -( - # Now present some info, line-by-line in an endless loop - # until the user presses a key (we turn the "magic" return - # code for that) - magic_return_code=69 - IFS="|" ; # Make sure we do not swallow whitespaces - while true ; do - ( - exec 5<&0 - - (cat <<ENDOFTEXT - - - - - - ################ - ######################## - ############################ - ####### ###### ####### - ###### ###### ######## - ####### ###### ####### - ############################## - ############################## - ############################## - ############################## - ############################## - ######### ######## ######### - # #### #### #### # - - - - - - - Written by - - Roland Mainz - (roland.mainz@nrubsig.org) - - - - - - - ############## - ######################## - #################**############ - ################################ - ############################ - ###################### - ################ - ###################### - ############################ - ################################ - ############################## - ######################## - ############## - - - - - - - - High scores: - - * 'chin' 8200 pt - * 'gisburn' 7900 pt - * 'tpenta' 5520 pt - * 'kupfer' 5510 pt - * 'noname' 5000 pt - * 'noname' 4000 pt - * 'livad' 3120 pt - * 'noname' 3000 pt - * 'noname' 2000 pt - * 'noname' 1000 pt - -ENDOFTEXT - - # clear screen, line-by-line - for (( i=0 ; i < LINES ; i++ )) ; do print "" ; done - ) | (while read line ; do - read -t 0.3 -n 1 c <&5 - [ "$c" != "" ] && exit ${magic_return_code} - print "${line}" - done) - [ $? -eq ${magic_return_code} ] && exit ${magic_return_code} - ) - [ $? -eq ${magic_return_code} ] && return 0 - - sleep 2 - done -) -} - -function run_menu -{ - integer numlevels=0 - integer selected_level=0 - - # built list of available levels based on the "function levelmap_.*" - # built into this script - typeset -f | egrep "^function.*levelmap_.*" | sed 's/^function //' | - while read l ; do - levellist[numlevels]="$l" - numlevels+=1 - done - - # swallow any queued user input (e.g. drain stdin) - read -t 0.1 -n 100 dummy - - while true ; do - # menu loop with timeout (which switches to "attract mode") - while true ; do - print -n "${vtcode["clear"]}" - - cat <<ENDOFTEXT ->======================================\ -> /-\ .--. | -> | OO| / _.-' .-. .-. .-. .-. | -> | | \ '-. '-' '-' '-' '-' | -> ^^^^^ '--' | ->======\ /================\ .-. | -> | | | '-' | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -ENDOFTEXT - print " GNAW - the ksh93 maze game" - print "\n\tMenu:" - - print "\t - [L]evels:" - for (( i=0 ; i < numlevels ; i++ )) ; do - printf "\t %s %s \n" "$([ $i -eq $selected_level ] && print -n "*" || print -n " ")" "${levellist[i]##levelmap_}" - done - - print "\t - Rendering options:" - printf "\t [%s] Use [U]nicode\n" "$([ $game_use_unicode -eq 1 ] && print -n "x" || print -n "_")" - printf "\t [%s] Use [C]olors\n" "$([ $game_use_colors -eq 1 ] && print -n "x" || print -n "_")" - - print "\t - [S]tart - [Q]uit" - - # wait 30 secs (before we switch to "attract mode") - c="" ; read -t 30 -n 1 c - case "$c" in - 'l') selected_level=$(((selected_level+numlevels+1) % numlevels)) ;; - 'L') selected_level=$(((selected_level+numlevels-1) % numlevels)) ;; - ~(Ei)s) - [ ${game_use_colors} -eq 1 ] && print "${vtcode["bg_black"]}" - case "${game_use_colors}${game_use_unicode}" in - "00") main_loop "${levellist[selected_level]}" ;; - "01") main_loop "${levellist[selected_level]}" | map_filter 0 1 ;; - "10") main_loop "${levellist[selected_level]}" | map_filter 1 0 ;; - "11") main_loop "${levellist[selected_level]}" | map_filter 1 1 ;; - esac - print "${vtcode["vtreset"]}" - ;; - ~(Ei)q|$'\E') - # make sure we do not exit on a cursor key (e.g. <esc>[A,B,C,D) - read -t 0.01 -n 1 c - if [ "$c" = "[" ] ; then - # this was a cursor key sequence, just eat the 3rd charcater - read -t 0.01 -n 1 c - else - exit 0 - fi - ;; - ~(Ei)u) game_use_unicode=$(((game_use_unicode+2+1) % 2)) ;; - ~(Ei)c) game_use_colors=$(((game_use_colors+2+1) % 2)) ;; - "") break ;; # timeout, switch to attract mode - *) beep ;; - esac - done - - print -n "${vtcode["clear"]}" - attract_mode - done -} - -function levelmap_stripes -{ -cat <<ENDOFLEVEL -################################### -#....... ............... P # -#########..#################..### # -#########..#################..### # -#....... .. ..............# # -############### ################ # -############### ################ # -#............. M ..............# # -##..##################### ###### # -##..##################### ###### # -#....... ........... .......# # -######## ############ ######### # -# #### ############ ######### # -# #.................. ......# # -# ############################### # -# # -################################### -ENDOFLEVEL -} - -function levelmap_livad -{ -cat <<ENDOFLEVEL -##################################################### -# # -# ############## ############### ################ # -# #............ P ..............# # -# .#############################################.# # -# #.#.......... ............#. # -# #.#.########## ############### ############.#.# # -# #...#........ ..........#...# # -# #...#.#####################################.#.#.# # -# #...#.#...... ........#...#.# # -# #.#.#...###### #########################.#.#.#.# # -# .#.....#.... M ......#...#.#.# # -# #.#.#...####################### ########.#.#.#.# # -# #...#.#...... ........#...#.# # -# #...#.######## ############### ##########.#.#.# # -# #...#........ ..........#...# # -# #.#.#########################################.#.# # -# #.#.......... ............#. # -# .############ ############### ##############.# # -# #............ ..............# # -# ################################################# # -# # -##################################################### -ENDOFLEVEL -} - -function levelmap_classic1 -{ -cat <<ENDOFLEVEL -######################### -#.P.........#...........# -#.####.####.#.####.####.# -#.# #.# #.#.# #.# #.# -#.# #.# #.#.# #.# #.# -#.####.####.#.####.####.# -#.......................# -#.####.#.#######.#.####.# -#.# #.#.# #.#.# #.# -#.####.#.#######.#.####.# -#......#....#....#......# -######.####.#.####.###### -###### # # ###### -###### # ## ## # ###### -###### # # # # ###### -# # M # # -###### # ####### # ###### -###### # # ###### -###### # ####### # ###### -###### # # # # ###### -######.#.#######.#.###### -#...........#...........# -#.###.###...#...###.###.# -#...#...............#...# -###.#....#######....#.### -# #.#..#.# #.#..#.# # -###....#.#######.#....### -#......#....#....#......# -#.#########.#.#########.# -#.......................# -######################### -ENDOFLEVEL -} - -function levelmap_classic2 -{ -cat <<ENDOFLEVEL -####################### -#.P...#.........#.....# -#.###.#.#######.#.###.# -#.....................# -###.#.####.#.####.#.### -###.#......#......#.### -###.###.#######.###.### -###.................### -###.###.### ###.###.### -###.#...#M #...#.### -###.#.#.#######.#.#.### -#.....#.........#.....# -###.#####..#..#####.### -###........#........### -###.###.#######.###.### -#.....................# -#.###.####.#.####.###.# -#.###.#....#....#.###.# -#.###.#.#######.#.###.# -#.....................# -####################### -ENDOFLEVEL -} - -function levelmap_easy -{ -cat <<ENDOFLEVEL -################## -# .............. # -# . ###### # -# . # M # # -# . # # # -# . ### ## # -# . # # -# . ### # -# . # -# .......... # -# .......... P # -################## -ENDOFLEVEL -} - -function levelmap_sunsolaristext -{ -cat <<ENDOFLEVEL -################################################ -# .#### . # #....# # -# # # # #....# # -# #### # # #.#..# M # -# # # # #..#.# # -# # # # # #...## # -# #### #### #....# # -# # -# #### #### # ## ##### # #### # -# # #. .# # # # #....# # # # -# #### # # # # P # #....# # #### # -# # # ### #.#### #.### # # # -# # .# #. .. # # #...# # # # # -# #### #### ###### . # ....# # ####. # -################################################ -ENDOFLEVEL -} - -function read_levelmap -{ - map="$( $1 )" - - integer y=0 - integer x=0 - integer maxx=0 - integer numdots=0 - - print "$map" | - while read line ; do - x=0 - while (( x < ${#line} )) ; do - c="${line:x:1}" - - case $c in - ".") numdots+=1 ;; - "M") - levelmap["monsterstartpos_x"]="$x" - levelmap["monsterstartpos_y"]="$y" - c=" " - ;; - "P") - levelmap["playerstartpos_x"]="$x" - levelmap["playerstartpos_y"]="$y" - c=" " - ;; - esac - - levelmap["${x}_${y}"]="$c" - let x++ - done - maxx=$x - let y++ - done - - levelmap["max_x"]=${maxx} - levelmap["max_y"]=${y} - levelmap["numdots"]=${numdots} - - if [ "${levelmap["monsterstartpos_x"]}" = "" ] ; then - fatal_error "read_levelmap: monsterstartpos_x is empty." - fi - if [ "${levelmap["playerstartpos_x"]}" = "" ] ; then - fatal_error "read_levelmap: playerstartpos_x is empty." - fi - - return 0 -} - -function player.set -{ - case "${.sh.subscript}" in - pos_y) - if [ "${levelmap["${player["pos_x"]}_${.sh.value}"]}" = "#" ] ; then - .sh.value=${player["pos_y"]} - beep - fi - ;; - - pos_x) - if [ "${levelmap["${.sh.value}_${player["pos_y"]}"]}" = "#" ] ; then - .sh.value=${player["pos_x"]} - beep - fi - ;; - esac -} - -function monster.set -{ - case "${.sh.subscript}" in - *_pos_y) - if [ "${levelmap["${monster[${currmonster}_"pos_x"]}_${.sh.value}"]}" = "#" ] ; then - .sh.value=${monster[${currmonster}_"pos_y"]} - # turn homing off when the monster hit a wall - monster[${currmonster}_"homing"]=0 - fi - ;; - - *_pos_x) - if [ "${levelmap["${.sh.value}_${monster[${currmonster}_"pos_y"]}"]}" = "#" ] ; then - .sh.value=${monster[${currmonster}_"pos_x"]} - # turn homing off when the monster hit a wall - monster[${currmonster}_"homing"]=0 - fi - ;; - esac -} - -function render_game -{ - # render_buffer is some kind of "background buffer" to "double buffer" - # all output and combine it in one write to reduce flickering in the - # terminal - render_buffer="$( - screen_y_offset=1 - start_y_pos=0 - render_num_lines=${levelmap["max_y"]} - - if (( (LINES-3) < levelmap["max_y"] )) ; then - start_y_pos=$((player["pos_y"] / 2)) - render_num_lines=$((LINES-5)) - fi - - #print -n "${vtcode["clear"]}" - print_setcursorpos 0 0 - - # print score (note the " " around "%d" are neccesary to clean up cruft - # when we overwrite the level - printf "SCORE: %05d DOTS: %.3d LIVES: %2.d " "${player["score"]}" "${levelmap["numdots"]}" "${player["lives"]}" - print_levelmap ${screen_y_offset} ${start_y_pos} ${render_num_lines} - - # render player - print_setcursorpos ${player["pos_x"]} $((player["pos_y"]+screen_y_offset-start_y_pos)) - print -n "@" - - # render monsters - for currmonster in ${monsterlist} ; do - let m_pos_x=monster[${currmonster}_"pos_x"] - let m_pos_y=monster[${currmonster}_"pos_y"]+screen_y_offset-start_y_pos - - if (( m_pos_y >= screen_y_offset && m_pos_y < render_num_lines )) ; then - print_setcursorpos ${m_pos_x} ${m_pos_y} - print -n "x" - fi - done - - # status block - print_setcursorpos 0 $((render_num_lines+screen_y_offset)) - emptyline=" " - print -n " >> ${player["message"]} <<${emptyline:0:${#emptyline}-${#player["message"]}}" - )" - print "${render_buffer}" -# print "renderbuffersize=$(print "${render_buffer}" | wc -c) " -} - -function main_loop -{ - float sleep_per_cycle=0.2 - float seconds_before_read - integer num_cycles=0 - float rs - - print -n "${vtcode["clear"]}" - - read_levelmap "$1" - - # player init - player["pos_x"]=${levelmap["playerstartpos_x"]} - player["pos_y"]=${levelmap["playerstartpos_y"]} - player["score"]=0 # player score - player["lives"]=5 # number of lives - player["invulnerable"]=10 # cycles how long the player remains invulnerable - player["message"]="Go..." - - monsterlist="maw claw jitterbug tentacle grendel" - - for currmonster in ${monsterlist} ; do - monster[${currmonster}_"pos_x"]=${levelmap["monsterstartpos_x"]} - monster[${currmonster}_"pos_y"]=${levelmap["monsterstartpos_y"]} - monster[${currmonster}_"xstep"]=0 - monster[${currmonster}_"ystep"]=0 - monster[${currmonster}_"homing"]=0 - done - - # main game cycle loop - while true ; do - num_cycles+=1 - seconds_before_read=${SECONDS} - c="" ; read -t ${sleep_per_cycle} -n 1 c - - if [ "$c" != "" ] ; then - # special case handling for cursor keys which are usually composed - # of three characters (e.g. "<ESC>[D"). If only <ESC> is hit we - # quicky exit - if [ "$c" = $'\E' ] ; then - read -t 0.1 -n 1 c - if [ "$c" != "[" ] ; then - return 0 - fi - - # we assume the user is using the cursor keys, this |read| - # should fetch the 3rd byte of the three-character sequence - # for the cursor keys - read -t 0.1 -n 1 c - fi - - # if the user hit a key the "read" above was interrupted - # and didn't wait exactly |sleep_per_cycle| seconds. - # We wait here some moments (|rs|="remaining seconds") to - # avoid that the game gets "faster" when more user input - # is given. - rs=$((sleep_per_cycle-(SECONDS-seconds_before_read))) - (( rs > 0.001 )) && sleep ${rs} - - player["message"]="" - - case "$c" in - j|D|4) let player["pos_x"]-=1 ;; - k|C|6) let player["pos_x"]+=1 ;; - i|A|8) let player["pos_y"]-=1 ;; - m|B|2) let player["pos_y"]+=1 ;; - - q) return 0 ;; - esac - - if [ "${levelmap["${player["pos_x"]}_${player["pos_y"]}"]}" = "." ] ; then - levelmap["${player["pos_x"]}_${player["pos_y"]}"]=" " - let levelmap["numdots"]-=1 - - let player["score"]+=10 - player["message"]='GNAW!!' - - if [ ${levelmap["numdots"]} -le 0 ] ; then - level_completed - return 0 - fi - fi - fi - - # generic player status change - if [ ${player["invulnerable"]} -gt 0 ] ; then - let player["invulnerable"]-=1 - fi - if [ ${player["lives"]} -le 0 ] ; then - game_over - return 0 - fi - - # move monsters - for currmonster in ${monsterlist} ; do - # make monster as half as slow then the others when it is following the user - if [ ${monster[${currmonster}_"homing"]} -gt 0 ] ; then - [ $((num_cycles % 2)) -gt 0 ] && continue - fi - - if [ ${monster[${currmonster}_"pos_x"]} = ${player["pos_x"]} ] ; then - if [ $((monster[${currmonster}_"pos_y"]-player["pos_y"])) -gt 0 ] ; then - let monster[${currmonster}_"xstep"]=+0 monster[${currmonster}_"ystep"]=-1 - else - let monster[${currmonster}_"xstep"]=+0 monster[${currmonster}_"ystep"]=+1 - fi - monster[${currmonster}_"homing"]=1 - if [ ${player["invulnerable"]} -le 0 ] ; then - player["message"]="Attention: ${currmonster} is chasing you" - fi - elif [ ${monster[${currmonster}_"pos_y"]} = ${player["pos_y"]} ] ; then - if [ $((monster[${currmonster}_"pos_x"]-player["pos_x"])) -gt 0 ] ; then - let monster[${currmonster}_"xstep"]=-1 monster[${currmonster}_"ystep"]=-0 - else - let monster[${currmonster}_"xstep"]=+1 monster[${currmonster}_"ystep"]=+0 - fi - monster[${currmonster}_"homing"]=1 - if [ ${player["invulnerable"]} -le 0 ] ; then - player["message"]="Attention: ${currmonster} is chasing you" - fi - else - if [ ${monster[${currmonster}_"homing"]} -eq 0 ] ; then - case $((SECONDS % 6 + RANDOM % 4)) in - 0) let monster[${currmonster}_"xstep"]=+0 monster[${currmonster}_"ystep"]=+0 ;; - 2) let monster[${currmonster}_"xstep"]=+0 monster[${currmonster}_"ystep"]=+1 ;; - 3) let monster[${currmonster}_"xstep"]=+1 monster[${currmonster}_"ystep"]=+0 ;; - 5) let monster[${currmonster}_"xstep"]=+0 monster[${currmonster}_"ystep"]=-1 ;; - 6) let monster[${currmonster}_"xstep"]=-1 monster[${currmonster}_"ystep"]=+0 ;; - esac - fi - fi - - let monster[${currmonster}_"pos_x"]=monster[${currmonster}_"pos_x"]+monster[${currmonster}_"xstep"] - let monster[${currmonster}_"pos_y"]=monster[${currmonster}_"pos_y"]+monster[${currmonster}_"ystep"] - - # check if a monster hit the player - if [ ${player["invulnerable"]} -le 0 ] ; then - if [ ${monster[${currmonster}_"pos_x"]} -eq ${player["pos_x"]} -a \ - ${monster[${currmonster}_"pos_y"]} -eq ${player["pos_y"]} ] ; then - # if player was hit by a monster take one life and - # make him invulnerable for 10 cycles to avoid that - # the next cycle steals more lives - player["message"]="Ouuuchhhh" - player["invulnerable"]=10 - let player["lives"]-=1 - - beep ; beep ; sleep 0.3 ; beep ; beep - fi - fi - done - - render_game - done -} - -# program start -function map_filter -{ -# Choose between the old "sed"-based codepath and the new ksh93-native one -# The old codepath no longer used except for the unicode mode because -# we do not have control over the point where "sed" flushes it's buffer -# which completely defeats the doube-buffering code. Unfortunately the new -# codepath has problems in UTF-8 mode (bug in ksh93 ?) which forces us to -# use the old codepath in this case. -if [ $2 -eq 1 ] ; then -( - filter1="" - filter2="" - - # should we add the color map ? - if [ $1 -eq 1 ] ; then - filter1="s/#/${vtcode["fg_blue"]}#/g;\ - s/x/${vtcode["fg_red"]}x/g;\ - s/@/${vtcode["fg_yellow"]}@/g;\ - s/ /${vtcode["fg_grey"]} /g;\ - s/\./${vtcode["fg_lightred"]}./g;" - fi - - # should we add the unicode map ? - if [ $2 -eq 1 ] ; then - filter2="s/@/$(printf '\u[24d2]')/g;s/x/$(printf '\u[2605]')/g;s/#/$(printf '\u[25a6]')/g" - fi - - sed -e "${filter1}" -e "${filter2}" -) -else -( - if [ $1 -eq 1 ] ; then - ch_player="${vtcode["fg_yellow"]}" - ch_monster="${vtcode["fg_red"]}" - ch_wall="${vtcode["fg_blue"]}" - else - ch_player="" - ch_monster="" - ch_wall="" - fi - - if [ $2 -eq 1 ] ; then - # unicode map - ch_player+="$(printf '\u[24d2]')" - ch_monster+="$(printf '\u[2605]')" - ch_wall+="$(printf '\u[25a6]')" - else - # ascii map - ch_player+="@" - ch_monster+="x" - ch_wall+="#" - fi - - IFS="|" # make sure we don't swallow spaces/tabs - while read var ; do - var="${var// /${vtcode["fg_grey"]} }" - var="${var//\./${vtcode["fg_lightred"]}.}" - var="${var//@/${ch_player}}" - var="${var//x/${ch_monster}}" - var="${var//#/${ch_wall}}" - - print "${var}" - done -) -fi -} - -function exit_trap -{ - # restore stty settings - stty ${SAVED_STTY} - - print "bye." -} - -function usage -{ - OPTIND=0 - getopts -a "${progname}" "${USAGE}" OPT '-?' - exit 2 -} - -# program start -progname="${0}" -quiet=false - -# make sure we use the ksh93 "cat" builtin which supports the "-u" option -builtin cat -builtin wc -builtin printf # we need this for positional parameters ('printf "%2\$s %1\$s" hello world' = "world hello") -builtin sleep - -# global variables -typeset -A levelmap -typeset -A player -typeset -A monster -# global rendering options -integer game_use_colors=0 -integer game_use_unicode=0 - -USAGE=$' -[-? -@(#)\$Id: gnaw (Roland Mainz) 2007-06-05 \$ -] -[+NAME?gnaw - maze game written in ksh93] -[+DESCRIPTION?\bgnaw\b is a maze game. - The player maneuvers a yellow '@' sign to navigate a maze while eating - small dots. A level is finished when all the dots are eaten. Five monsters - (maw, claw, jitterbug, tentacle and grendel) also wander the maze in an attempt - to catch the '@'. Each level begins with all ghosts in their home, and '@' near - the bottom of the maze. The monsters are released from the home one by one at the - start of each level and start their rentless hunt after the player.] -[q:quiet?Disable use of terminal bell.] -[+SEE ALSO?\bksh93\b(1)] -' - -while getopts -a "${progname}" "${USAGE}" OPT ; do -# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" - case ${OPT} in - q) quiet=true ;; - *) usage ;; - esac -done -shift ${OPTIND}-1 - -# save stty values and register the exit trap which restores these values on exit -SAVED_STTY="$(stty -g)" -trap exit_trap EXIT - -print "Loading..." - -# set stty values, "-icanon min 1 time 0 -inpck" should improve input latency, -# "-echo" turns the terminal echo off -stty -icanon min 1 time 0 -inpck -echo - -# "resize" cannot fetch the terminal width/height for some terminals -case ${TERM} in - sun | sun-color) - export COLUMNS=80 LINES=25 - ;; - vt52) - export COLUMNS=80 LINES=24 - ;; - *) - # get width/height from current terminal - [ -x "/usr/X11/bin/resize" ] && eval "$(/usr/X11/bin/resize -u)" || - [ -x "/usr/X11R6/bin/resize" ] && eval "$(/usr/X11R6/bin/resize -u)" || - [ -x "/usr/openwin/bin/resize" ] && eval "$(/usr/openwin/bin/resize -u)" || - fatal_error "resize not found." - ;; -esac - -# prechecks -(( COLUMNS < 60 )) && fatal_error "Terminal width must be larger than 60 columns (currently ${COLUMNS})." - -typeset -A vtcode -# color values taken from http://frexx.de/xterm-256-notes/, other -# codes from http://vt100.net/docs/vt100-tm/ -vtcode=( - ["bg_black"]="$(print -n "\E[40m")" - ["fg_black"]="$(print -n "\E[30m")" - ["fg_red"]="$(print -n "\E[31m")" - ["fg_lightred"]="$(print -n "\E[1;31m")" - ["fg_green"]="$(print -n "\E[32m")" - ["fg_lightgreen"]="$(print -n "\E[1;32m")" - ["fg_yellow"]="$(print -n "\E[33m")" - ["fg_lightyellow"]="$(print -n "\E[1;33m")" - ["fg_blue"]="$(print -n "\E[34m")" - ["fg_lightblue"]="$(print -n "\E[1;34m")" - ["fg_grey"]="$(print -n "\E[1;37m")" - ["fg_white"]="$(print -n "\E[37m")" - - # misc other vt stuff - ["vtreset"]="$(tput reset)" - ["clear"]="$(tput clear)" - ["bel"]="$(tput bel)" - ["spaceline"]="$(for (( i=0 ; i < COLUMNS ; i++ )) ; do print -n " " ; done)" -) - -# get terminal sequence to move cursor to position x,y -# (see http://vt100.net/docs/vt100-ug/chapter3.html#CPR) -case ${TERM} in - xterm | xterm-color | vt100 | vt220 | dtterm | sun | sun-color) - cup="$(infocmp -1 | \ - egrep '^[[:space:]]*cup=' | \ - sed -e 's/.*cup=//' \ - -e 's/%[%id]*p1[%id]*/%2\\\$d/g' \ - -e 's/%[%id]*p2[%id]*/%1\\\$d/g' \ - -e 's/,$//')" - for (( x=0 ; x < COLUMNS ; x++ )) ; do - for (( y=0 ; y < LINES ; y++ )) ; do - vtcode[cup_${x}_${y}]="$(printf "${cup}" $((x + 1)) $((y + 1)) )" - done - done - ;; - *) - printf "# Unrecognised terminal type '%s', fetching %dx%d items from terminfo database, please wait...\n" "${TERM}" "${COLUMNS}" "${LINES}" - for (( x=0 ; x < COLUMNS ; x++ )) ; do - for (( y=0 ; y < LINES ; y++ )) ; do - vtcode[cup_${x}_${y}]="$(tput cup ${y} ${x})" - done - done - ;; -esac - -print "${vtcode["vtreset"]}" - -run_logo -run_menu - -# EOF. - Index: src/lib/libshell/common/bltins/shopen.c =================================================================== --- src/lib/libshell/common/bltins/shopen.c (revision 974) +++ src/lib/libshell/common/bltins/shopen.c (revision 1122) @@ -1,533 +0,0 @@ -/*********************************************************************** -* * -* This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * -* and is licensed under the * -* Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * -* * -* A copy of the License is available at * -* http://www.opensource.org/licenses/cpl1.0.txt * -* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * -* * -* Information and Software Systems Research * -* AT&T Research * -* Florham Park NJ * -* * -* David Korn <dgk@research.att.com> * -* * -***********************************************************************/ -#pragma prototyped - -static const char id[] = "\n@(#)$Id: open (AT&T Research) 1998-07-07 $\0\n"; - -#include <shell.h> -#include <option.h> -#include <stk.h> -#include <tm.h> -#ifndef SH_DICT -# define SH_DICT "libshell" -#endif - -/* - * time formatting related -*/ -struct dctime -{ - Namfun_t fun; - Namval_t *format; -}; - -static char *get_time(Namval_t* np, Namfun_t* nfp) -{ - static char buff[256]; - struct dctime *dp = (struct dctime*)nfp; - time_t t = nv_getn(np,nfp); - char *format = nv_getval(dp->format); - tmfmt(buff,sizeof(buff),format,(time_t*)0); - return(buff); -} - -static void put_time(Namval_t* np, const char* val, int flag, Namfun_t* nfp) -{ - struct dctime *dp = (struct dctime*)nfp; - char *last; - if(val) - { - int32_t t; - if(flag&NV_INTEGER) - { - if(flag&NV_LONG) - t = *(Sfdouble_t*)val; - else - t = *(double*)val; - } - else - { - t = tmdate(val, &last, (time_t*)0); - if(*last) - errormsg(SH_DICT,ERROR_exit(1),"%s: invalid date/time string",val); - } - nv_putv(np,(char*)&t,NV_INTEGER,nfp); - } - else - { - nv_unset(dp->format); - free((void*)dp->format); - nv_putv(np,val,flag,nfp); - } -} - -static Namval_t *create_time(Namval_t *np, const char *name, int flags, Namfun_t *nfp) -{ - struct dctime *dp = (struct dctime*)nfp; - if(strcmp(name,"format")) - return((Namval_t*)0); - return(dp->format); -} - -static const Namdisc_t timedisc = -{ - sizeof(struct dctime), - put_time, - get_time, - 0, - 0, - create_time, -}; - - -static Namval_t *make_time(Namval_t* np) -{ - int offset = stktell(stkstd); - char *name = nv_name(np); - struct dctime *dp = newof(NULL,struct dctime,1,0); - if(!dp) - return((Namval_t*)0); - sfprintf(stkstd,"%s.format\0",name); - sfputc(stkstd,0); - dp->format = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD); - dp->fun.disc = &timedisc; - nv_stack(np,&dp->fun); - return(np); -} - -/* - * mode formatting related -*/ -static char *get_mode(Namval_t* np, Namfun_t* nfp) -{ - mode_t mode = nv_getn(np,nfp); - return(fmtperm(mode)); -} - -static void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp) -{ - if(val) - { - int32_t mode; - char *last; - if(flag&NV_INTEGER) - { - if(flag&NV_LONG) - mode = *(Sfdouble_t*)val; - else - mode = *(double*)val; - } - else - { - mode = strperm(val, &last,0); - if(*last) - errormsg(SH_DICT,ERROR_exit(1),"%s: invalid mode string",val); - } - nv_putv(np,(char*)&mode,NV_INTEGER,nfp); - } - else - nv_putv(np,val,flag,nfp); -} - -static const Namdisc_t modedisc = -{ - 0, - put_mode, - get_mode, -}; - -static Namval_t *make_mode(Namval_t* np) -{ - char *name = nv_name(np); - Namfun_t *nfp = newof(NULL,Namfun_t,1,0); - if(!nfp) - return((Namval_t*)0); - nfp->disc = &modedisc; - nv_stack(np,nfp); - return(np); -} - -/* - * field related typese and functions - */ -typedef struct _field_ -{ - char *name; /* field name */ - int flags; /* flags */ - short offset; /* offset of field into data */ - short size; /* size of field */ - Namval_t *(*make)(Namval_t*); /* discipline constructor */ -} Shfield_t; - -/* - * lookup field in field table - */ -static Shfield_t *sh_findfield(Shfield_t *ftable, int nelem, const char *name) -{ - Shfield_t *fp = ftable; - register int i,n; - register const char *cp; - for(cp=name; *cp; cp++) - { - if(*cp=='.') - break; - } - n = cp-name; - for(i=0; i < nelem; i++,fp++) - { - if(memcmp(fp->name,name,n)==0 && fp->name[n]==0) - return(fp); - } - return(0); -} - -/* - * class types and functions - */ - -typedef struct _class_ -{ - int nelem; /* number of elements */ - int dsize; /* size for data structure */ - Shfield_t *fields; /* field description table */ -} Shclass_t; - -struct dcclass -{ - Namfun_t fun; - Shclass_t sclass; -}; - -static Namval_t *sh_newnode(register Shfield_t *fp, Namval_t *np) -{ - char *val = np->nvalue + fp->offset; - char *name = nv_name(np); - register Namval_t *nq; - int offset = stktell(stkstd); - sfprintf(stkstd,"%s.%s\0",name,fp->name); - sfputc(stkstd,0); - nq = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD); - if(fp->size<0) - val = *(char**)val; - nv_putval(nq,val,fp->flags|NV_NOFREE); - if(fp->make) - (*fp->make)(nq); - return(nq); -} - -static Namval_t *fieldcreate(Namval_t *np, const char *name, int flags, Namfun_t *nfp) -{ - struct dcclass *dcp = (struct dcclass*)nfp; - Shclass_t *sp = &dcp->sclass; - Shfield_t *fp = sh_findfield(sp->fields,sp->nelem,name); - Namval_t *nq,**nodes = (Namval_t**)(dcp+1); - int n = fp-sp->fields; - int len = strlen(fp->name); - void *data = (void*)np->nvalue; - if(!(nq=nodes[n])) - { - nodes[n] = nq = sh_newnode(fp,np); - nfp->last = ""; - } - if(name[len]==0) - return(nq); - return(nq); -} - -static void genvalue(Sfio_t *out, Shclass_t *sp, int indent, Namval_t *npar) -{ - Shfield_t *fp = sp->fields; - Namval_t *np, **nodes= (Namval_t**)(sp+1); - register int i,isarray; - if(out) - { - sfwrite(out,"(\n",2); - indent++; - } - for(i=0; i < sp->nelem; i++,fp++) - { -#if 0 - /* handle recursive case */ -#endif - if(!(np=nodes[i]) && out) - np = sh_newnode(fp,npar); - if(np) - { - isarray=0; - if(nv_isattr(np,NV_ARRAY)) - { - isarray=1; - if(array_elem(nv_arrayptr(np))==0) - isarray=2; - else - nv_putsub(np,(char*)0,ARRAY_SCAN); - } - sfnputc(out,'\t',indent); - sfputr(out,fp->name,(isarray==2?'\n':'=')); - if(isarray) - { - if(isarray==2) - continue; - sfwrite(out,"(\n",2); - sfnputc(out,'\t',++indent); - } - while(1) - { - char *fmtq; - if(isarray) - { - sfprintf(out,"[%s]",sh_fmtq(nv_getsub(np))); - sfputc(out,'='); - } - if(!(fmtq=nv_getval(np)) || !(fmtq=sh_fmtq(fmtq))) - fmtq = ""; - sfputr(out,fmtq,'\n'); - if(!nv_nextsub(np)) - break; - sfnputc(out,'\t',indent); - } - if(isarray) - { - sfnputc(out,'\t',--indent); - sfwrite(out,")\n",2); - } - } - } - if(out) - { - if(indent>1) - sfnputc(out,'\t',indent-1); - sfputc(out,')'); - } -} - -static char *walk_class(register Namval_t *np, int dlete, struct dcclass *dcp) -{ - static Sfio_t *out; - Sfio_t *outfile; - int savtop = stktell(stkstd); - char *savptr = stkfreeze(stkstd,0); - if(dlete) - outfile = 0; - else if(!(outfile=out)) - outfile = out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING); - else - sfseek(outfile,0L,SEEK_SET); - genvalue(outfile,&dcp->sclass,0,np); - stkset(stkstd,savptr,savtop); - if(!outfile) - return((char*)0); - sfputc(out,0); - return((char*)out->_data); -} - -static char *get_classval(Namval_t* np, Namfun_t* nfp) -{ - return(walk_class(np,0,(struct dcclass *)nfp)); -} - -static void put_classval(Namval_t* np, const char* val, int flag, Namfun_t* nfp) -{ - walk_class(np,1,(struct dcclass *)nfp); - if(nfp = nv_stack(np,(Namfun_t*)0)) - { - free((void*)nfp); - if(np->nvalue && !nv_isattr(np,NV_NOFREE)) - free((void*)np->nvalue); - } - if(val) - nv_putval(np,val,flag); -} - -static const Namdisc_t classdisc = -{ - sizeof(struct dcclass), - put_classval, - get_classval, - 0, - 0, - fieldcreate -}; - -static int mkclass(Namval_t *np, Shclass_t *sp) -{ - struct dcclass *tcp = newof(NULL,struct dcclass,1,sp->nelem*sizeof(Namval_t*)); - if(!tcp) - return(0); - memset((void*)(tcp+1),0,sp->nelem*sizeof(Namval_t*)); - tcp->fun.disc = &classdisc; - tcp->sclass = *sp; - np->nvalue = (char*)calloc(sp->dsize,1); - nv_stack(np,&tcp->fun); - return(1); -} - -/* - * ====================from here down is file class specific - */ -static struct stat *Sp; - -struct filedata -{ - struct stat statb; - int fd; - char *name; -}; - -static Shfield_t filefield[] = -{ - { "atime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_atime), sizeof(Sp->st_atime), make_time}, - { "ctime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ctime), sizeof(Sp->st_ctime), make_time}, - { "dev", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_dev),sizeof(Sp->st_dev)}, - { "fd", NV_INTEGER|NV_RDONLY, offsetof(struct filedata,fd), sizeof(int)}, - { "gid", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_gid), sizeof(Sp->st_gid)}, - { "ino", NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_ino), sizeof(Sp->st_ino)}, - { "mode", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mode), sizeof(Sp->st_mode), make_mode}, - { "mtime", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_mtime), sizeof(Sp->st_mtime), make_time}, - { "name", NV_RDONLY, offsetof(struct filedata,name), -1 }, - { "nlink", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_nlink), sizeof(Sp->st_nlink)}, - { "size", NV_LONG|NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_size), sizeof(Sp->st_size)}, - { "uid", NV_INTEGER|NV_RDONLY, offsetof(struct stat,st_uid), sizeof(Sp->st_uid)} -}; - -static Shclass_t Fileclass = -{ - sizeof(filefield)/sizeof(*filefield), - sizeof(struct filedata), - filefield -}; - - -#define letterbit(bit) (1<<((bit)-'a')) - -static const char sh_optopen[] = -"[-?\n@(#)$Id: open (AT&T Labs Research) 2007-03-11 $\n]" -"[-author?David Korn <dgk@research.att.com>]" -"[-license?http://www.opensource.org/licenses/cpl1.0.txt]" -"[+NAME? open - create a shell variable correspnding to a file]" -"[+DESCRIPTION?\bopen\b creates the compound variable \avar\a correspinding " - "to the file given by the pathname \afile\a. The elements of \avar\a " - "are the names of elements in the \astat\a structure with the \bst_\b " - "prefix removed.]" -"[+?If the \b-r\b and/or \b-w\b mode is specified, then \afile\a is opened and " - "the variable \avar\a\b.fd\b is the file descriptor.]" -"[a:append?Open for append.]" -"[b:binary?Open in binary mode.]" -"[c:create?Open for create.]" -"[i:inherit?Open without the close-on-exec bit set.]" -"[r:read?Open with read access.]" -"[w:write?Open with write access.]" -"[m:mode]:[mode:=rwrwrw?Open with access mode \amode\a.]" -"[x:exclusive?Open exclusive.]" -"\n" -"\nvar file\n" -"\n" -"[+EXIT STATUS?]{" - "[+0?Success.]" - "[+>0?An error occurred.]" -"}" -"[+SEE ALSO?\bstat\b(2)]" -; - - -extern int b_open(int argc, char *argv[], void *extra) -{ - register Namval_t *np; - register int n,oflag=0; - Shell_t *shp = (Shell_t*)extra; - struct filedata *fdp; - struct stat statb; - mode_t mode = 0666; - long flags = 0; - int fd = -1; - while (n = optget(argv, sh_optopen)) switch (n) - { - case 'r': - case 'i': - case 'w': - flags |= letterbit(n); - break; - case 'b': -#ifdef O_BINARY - oflag |= O_BINARY; -#endif - break; - case 't': -#ifdef O_TEXT - oflag |= O_TEXT; -#endif - break; - case 'x': - oflag |= O_EXCL; - break; - case 'c': - oflag |= O_CREAT; - break; - case 'a': - oflag |= O_APPEND; - break; - case 'm': - break; - case ':': - errormsg(SH_DICT,2, "%s", opt_info.arg); - break; - case '?': - errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); - break; - } - argc -= opt_info.index; - argv += opt_info.index; - if(argc!=2) - errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0)); - if(!(flags&(letterbit('r')|letterbit('w')))) - { - if(stat(argv[1],&statb)<0) - errormsg(SH_DICT,ERROR_system(1),"%s: open failed",argv[1]); - } - else - { - if(flags&letterbit('r')) - { - if(flags&letterbit('w')) - oflag |= O_RDWR; - else - oflag |= O_RDONLY; - } - else if(flags&letterbit('w')) - oflag |= O_WRONLY; - fd = open(argv[1],oflag,mode); - if(fd<0) - errormsg(SH_DICT,ERROR_system(1),"%s: open failed",argv[1]); - } - if(!(flags&letterbit('i'))) - fcntl(fd,F_SETFL,0); - np = nv_open(argv[0],shp->var_tree,NV_ARRAY|NV_VARNAME|NV_NOASSIGN); - if(!nv_isnull(np)) - nv_unset(np); - mkclass(np,&Fileclass); - fdp = (struct filedata*)np->nvalue; - if(!(flags&(letterbit('r')|letterbit('w')))) - fdp->statb = statb; - else - fstat(fd,&fdp->statb); - fdp->fd = fd; - fdp->name = strdup(argv[1]); - return(0); -} Index: src/lib/libshell/common/bltins/cd_pwd.c =================================================================== --- src/lib/libshell/common/bltins/cd_pwd.c (revision 974) +++ src/lib/libshell/common/bltins/cd_pwd.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -39,7 +39,6 @@ #include <ls.h> #include <ctype.h> -#ifdef PATH_BFPATH /* * Invalidate path name bindings to relative paths */ @@ -50,18 +49,13 @@ if(pp && *pp->name!='/') nv_unset(np); } -#endif int b_cd(int argc, char *argv[],void *extra) { -#ifdef PATH_BFPATH register char *dir; Pathcomp_t *cdpath = 0; -#else - register char *dir, *cdpath=""; -#endif register const char *dp; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; int saverrno=0; int rval,flag=0; char *oldpwd; @@ -105,7 +99,6 @@ if(*dir != '/') #endif /* _WINIX */ { -#ifdef PATH_BFPATH if(!(cdpath = (Pathcomp_t*)shp->cdpathlist) && (dp=(CDPNOD)->nvalue.cp)) { if(cdpath=path_addpath((Pathcomp_t*)0,dp,PATH_CDPATH)) @@ -114,38 +107,22 @@ cdpath->shp = shp; } } -#else - cdpath = nv_getval(nv_scoped(CDPNOD)); -#endif if(!oldpwd) oldpwd = path_pwd(1); } -#ifndef PATH_BFPATH - if(!cdpath) - cdpath = ""; -#endif if(*dir=='.') { /* test for pathname . ./ .. or ../ */ if(*(dp=dir+1) == '.') dp++; if(*dp==0 || *dp=='/') -#ifdef PATH_BFPATH cdpath = 0; -#else - cdpath = ""; -#endif } rval = -1; do { -#ifdef PATH_BFPATH dp = cdpath?cdpath->name:""; cdpath = path_nextcomp(cdpath,dir,0); -#else - dp = cdpath; - cdpath=path_join(cdpath,dir); -#endif #if _WINIX if(*stakptr(PATH_OFFSET+1)==':' && isalpha(*stakptr(PATH_OFFSET))) { @@ -210,11 +187,7 @@ stakseek(dir-stakptr(0)); } dir = (char*)stakfreeze(1)+PATH_OFFSET; -#ifdef PATH_BFPATH if(*dp && (*dp!='.'||dp[1]) && strchr(dir,'/')) -#else - if(*dp && *dp!= ':' && strchr(dir,'/')) -#endif sfputr(sfstdout,dir,'\n'); if(*dir != '/') return(0); @@ -228,11 +201,9 @@ nv_putval(pwdnod,dir,NV_RDONLY); nv_onattr(pwdnod,NV_NOFREE|NV_EXPORT); shp->pwd = pwdnod->nvalue.cp; -#ifdef PATH_BFPATH nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED); path_newdir(shp->pathlist); path_newdir(shp->cdpathlist); -#endif return(0); } @@ -240,7 +211,7 @@ { register int n, flag = 0; register char *cp; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; NOT_USED(argc); while((n = optget(argv,sh_optpwd))) switch(n) { Index: src/lib/libshell/common/bltins/ulimit.c =================================================================== --- src/lib/libshell/common/bltins/ulimit.c (revision 974) +++ src/lib/libshell/common/bltins/ulimit.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -70,13 +70,13 @@ register char *limit; register int mode=0, n; register unsigned long hit = 0; - Shell_t *shp = (Shell_t*)extra; + Shell_t *shp = ((Shbltin_t*)extra)->shp; #ifdef _lib_getrlimit struct rlimit rlp; #endif /* _lib_getrlimit */ const Limit_t* tp; char* conf; - int label, unit, noargs, nosupport; + int label, unit, nosupport; rlim_t i; char tmp[32]; Optdisc_t disc; @@ -109,9 +109,9 @@ break; } opt_info.disc = 0; - limit = argv[opt_info.index]; /* default to -f */ - if(noargs=(hit==0)) + limit = argv[opt_info.index]; + if(hit==0) for(n=0; shtab_limits[n].option; n++) if(shtab_limits[n].index == RLIMIT_FSIZE) { @@ -196,10 +196,9 @@ conf = (char*)e_nosupport; sfputr(sfstdout,conf,'\n'); } - else if(i!=INFINITY || noargs) + else if(i!=INFINITY) { - if(!noargs) - i += (unit-1); + i += (unit-1); sfprintf(sfstdout,"%I*d\n",sizeof(i),i/unit); } else Index: src/lib/libshell/common/bltins/enum.c =================================================================== --- src/lib/libshell/common/bltins/enum.c (revision 0) +++ src/lib/libshell/common/bltins/enum.c (revision 1122) @@ -0,0 +1,276 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2008 AT&T Intellectual Property * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn <dgk@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +#include <shell.h> + +static const char enum_usage[] = +"[-?@(#)$Id: enum (AT&T Research) 2008-01-08 $\n]" +USAGE_LICENSE +"[+NAME?enum - create an enumeration type]" +"[+DESCRIPTION?\benum\b is a declaration command that creates an enumeration " + "type \atypename\a that can only store any one of the values in the indexed " + "array variable \atypename\a.]" +"[+?If the list of \avalue\as is ommitted, then \atypename\a must name an " + "indexed array variable with at least two elements.]" +"[i:ignorecase?The values are case insensitive.]" +"\n" +"\n\atypename\a[\b=(\b \avalue\a ... \b)\b]\n" +"\n" +"[+EXIT STATUS]" + "{" + "[+0?Successful completion.]" + "[+>0?An error occurred.]" + "}" +"[+SEE ALSO?\bksh\b(1), \btypeset\b(1).]" +; + +static const char enum_type[] = +"[-1c?\n@(#)$Id: type (AT&T Labs Research) 2008-01-08 $\n]" +USAGE_LICENSE +"[+NAME?\f?\f - create an instance of type \b\f?\f\b]" +"[+DESCRIPTION?\b\f?\f\b creates a variable for each \aname\a with " + "enumeration type \b\f?\f\b where \b\f?\f\b is a type that has been " + "created with the \benum\b(1) command.]" +"[+?The variable can have one of the following values\fvalues\f. " + "The the values are \fcase\fcase sensitive.]" +"[+?If \b=\b\avalue\a is omitted, the default is \fdefault\f.]" +"[+?If no \aname\as are specified then the names and values of all " + "variables of this type are written to standard output.]" +"[+?\b\f?\f\b is built-in to the shell as a declaration command so that " + "field splitting and pathname expansion are not performed on " + "the arguments. Tilde expansion occurs on \avalue\a.]" +"[r?Enables readonly. Once enabled, the value cannot be changed or unset.]" +"[a?index array. Each \aname\a will converted to an index " + "array of type \b\f?\f\b. If a variable already exists, the current " + "value will become index \b0\b.]" +"[A?Associative array. Each \aname\a will converted to an associate " + "array of type \b\f?\f\b. If a variable already exists, the current " + "value will become subscript \b0\b.]" +#if 0 +"[p?Causes the output to be in a form of \b\f?\f\b commands that can be " + "used as input to the shell to recreate the current type of " + "these variables.]" +#endif +"\n" +"\n[name[=value]...]\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?Successful completion.]" + "[+>0?An error occurred.]" +"}" + +"[+SEE ALSO?\benum\b(1), \btypeset\b(1)]" +; + +struct Enum +{ + Namfun_t hdr; + short nelem; + short iflag; + const char *values[1]; +}; + +static int enuminfo(Opt_t* op, Sfio_t *out, const char *str, Optdisc_t *fp) +{ + Namval_t *np; + struct Enum *ep; + int n=0; + const char *v; + np = *(Namval_t**)(fp+1); + ep = (struct Enum*)np->nvfun; + if(strcmp(str,"default")==0) +#if 0 + sfprintf(out,"\b%s\b%c",ep->values[0],0); +#else + sfprintf(out,"\b%s\b",ep->values[0]); +#endif + else if(strcmp(str,"case")==0) + { + if(ep->iflag) + sfprintf(out,"not "); + } + else while(v=ep->values[n++]) + { + sfprintf(out,", \b%s\b",v); + } + return(0); +} + +static Namfun_t *clone_enum(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp) +{ + struct Enum *ep, *pp=(struct Enum*)fp; + ep = newof(0,struct Enum,1,pp->nelem*sizeof(char*)); + memcpy((void*)ep,(void*)pp,sizeof(struct Enum)+pp->nelem*sizeof(char*)); + return(&ep->hdr); +} + +static void put_enum(Namval_t* np,const char *val,int flags,Namfun_t *fp) +{ + struct Enum *ep = (struct Enum*)fp; + register const char *v; + unsigned short i=0, n; + if(!val) + { + nv_disc(np,&ep->hdr,NV_POP); + if(!ep->hdr.nofree) + free((void*)ep); + nv_putv(np, val, flags,fp); + return; + } + if(flags&NV_INTEGER) + { + nv_putv(np,val,flags,fp); + return; + } + while(v=ep->values[i]) + { + if(ep->iflag) + n = strcasecmp(v,val); + else + n = strcmp(v,val); + if(n==0) + { + nv_putv(np, (char*)&i, NV_UINT16, fp); + return; + } + i++; + } + error(ERROR_exit(1), "%s: invalid value %s",nv_name(np),val); +} + +static char* get_enum(register Namval_t* np, Namfun_t *fp) +{ + static char buff[6]; + struct Enum *ep = (struct Enum*)fp; + long n = nv_getn(np,fp); + if(n < ep->nelem) + return((char*)ep->values[n]); + sfsprintf(buff,sizeof(buff),"%u%c",n,0); + return(buff); +} + +static Sfdouble_t get_nenum(register Namval_t* np, Namfun_t *fp) +{ + return(nv_getn(np,fp)); +} + +static const Namdisc_t Enum_disc = { 0, put_enum, get_enum, get_nenum, 0,0,clone_enum }; + +#ifdef STANDALONE +static int enum_create(int argc, char** argv, void* context) +#else +int b_enum(int argc, char** argv, void* context) +#endif +{ + int sz,i,n,iflag = 0; + Namval_t *np, *tp; + Namarr_t *ap; + char *cp,*sp; + struct Enum *ep; + Shell_t *shp = ((Shbltin_t*)context)->shp; + struct { + Optdisc_t opt; + Namval_t *np; + } optdisc; + + cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY); + for (;;) + { + switch (optget(argv, enum_usage)) + { + case 'i': + iflag = 'i'; + continue; + case '?': + error(ERROR_USAGE|4, "%s", opt_info.arg); + break; + case ':': + error(2, "%s", opt_info.arg); + break; + } + break; + } + argv += opt_info.index; + if (error_info.errors || !*argv || *(argv + 1)) + { + error(ERROR_USAGE|2, "%s", optusage(NiL)); + return 1; + } + while(cp = *argv++) + { + if(!(np = nv_open(cp, (void*)0, NV_VARNAME|NV_NOADD)) || !(ap=nv_arrayptr(np)) || ap->fun || (sz=ap->nelem&(((1L<<ARRAY_BITS)-1))) < 2) + error(ERROR_exit(1), "%s must name an array containing at least two elements",cp); + n = staktell(); + sfprintf(stkstd,"%s.%s%c",NV_CLASS,np->nvname,0); + tp = nv_open(stakptr(n), shp->var_tree, NV_VARNAME); + stakseek(n); + n = sz; + i = 0; + nv_onattr(tp, NV_UINT16); + nv_putval(tp, (char*)&i, NV_INTEGER); + nv_putsub(np, (char*)0, ARRAY_SCAN); + do + { + sz += strlen(nv_getval(np)); + } + while(nv_nextsub(np)); + sz += n*sizeof(char*); + if(!(ep = newof(0,struct Enum,1,sz))) + error(ERROR_system(1), "out of space"); + ep->iflag = iflag; + ep->nelem = n; + cp = (char*)&ep->values[n+1]; + nv_putsub(np, (char*)0, ARRAY_SCAN); + ep->values[n] = 0; + i = 0; + do + { + ep->values[i++] = cp; + sp = nv_getval(np); + n = strlen(sp); + memcpy(cp,sp,n+1); + cp += n+1; + } + while(nv_nextsub(np)); + ep->hdr.dsize = sizeof(struct Enum)+sz; + ep->hdr.disc = &Enum_disc; + ep->hdr.type = tp; + nv_onattr(tp, NV_RDONLY); + nv_disc(tp, &ep->hdr,NV_FIRST); + memset(&optdisc,0,sizeof(optdisc)); + optdisc.opt.infof = enuminfo; + optdisc.np = tp; + nv_addtype(tp, enum_type, &optdisc.opt, sizeof(optdisc)); + } + return error_info.errors != 0; +} + +#ifdef STANDALONE +void lib_init(int flag, void* context) +{ + Shell_t *shp = ((Shbltin_t*)context)->shp; + Namval_t *mp,*bp; + if(flag) + return; + bp = sh_addbuiltin("Enum", enum_create, (void*)0); + mp = nv_search("typeset",shp->bltin_tree,0); + nv_onattr(bp,nv_isattr(mp,NV_PUBLIC)); +} +#endif Index: src/lib/libshell/common/bltins/trap.c =================================================================== --- src/lib/libshell/common/bltins/trap.c (revision 974) +++ src/lib/libshell/common/bltins/trap.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -45,8 +45,8 @@ int b_trap(int argc,char *argv[],void *extra) { register char *arg = argv[1]; - register int sig, pflag = 0; - register Shell_t *shp = (Shell_t*)extra; + register int sig, clear = 0, dflag = 0, pflag = 0; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; NOT_USED(argc); while (sig = optget(argv, sh_opttrap)) switch (sig) { @@ -66,9 +66,8 @@ errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0)); if(arg = *argv) { - register int clear; char *action = arg; - if(!pflag) + if(!dflag && !pflag) { /* first argument all digits or - means clear */ while(isdigit(*arg)) @@ -79,8 +78,18 @@ ++argv; if(*action=='-' && action[1]==0) clear++; + /* + * NOTE: 2007-11-26: workaround for tests/signal.sh + * if function semantics can be worked out then it + * may merit a -d,--default option + */ + else if(*action=='+' && action[1]==0 && sh.st.self == &sh.global) + { + clear++; + dflag++; + } } - while(!argv[0]) + if(!argv[0]) errormsg(SH_DICT,ERROR_exit(1),e_condition); } while(arg = *argv++) @@ -132,7 +141,11 @@ sfputr(sfstdout,arg,'\n'); } else if(clear) + { sh_sigclear(sig); + if(dflag) + signal(sig,SIG_DFL); + } else { if(sig >= shp->st.trapmax) @@ -153,7 +166,7 @@ { register char *signame; register int sig=SIGTERM, flag=0, n; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; NOT_USED(argc); while((n = optget(argv,sh_optkill))) switch(n) { @@ -222,8 +235,8 @@ static int sig_number(const char *string) { const Shtable_t *tp; - register int n,sig=0; - char *last; + register int n,o,sig=0; + char *last, *name; if(isdigit(*string)) { n = strtol(string,&last,10); @@ -233,7 +246,7 @@ else { register int c; - n = staktell(); + o = staktell(); do { c = *string++; @@ -242,30 +255,92 @@ stakputc(c); } while(c); - stakseek(n); - if(memcmp(stakptr(n),"SIG",3)==0) + stakseek(o); + if(memcmp(stakptr(o),"SIG",3)==0) { sig = 1; - n += 3; + o += 3; } - tp = sh_locate(stakptr(n),(const Shtable_t*)shtab_signals,sizeof(*shtab_signals)); + tp = sh_locate(stakptr(o),(const Shtable_t*)shtab_signals,sizeof(*shtab_signals)); n = tp->sh_number; if(sig==1 && (n>=(SH_TRAP-1) && n < (1<<SH_SIGBITS))) { /* sig prefix cannot match internal traps */ n = 0; tp = (Shtable_t*)((char*)tp + sizeof(*shtab_signals)); - if(strcmp(stakptr(n),tp->sh_name)==0) + if(strcmp(stakptr(o),tp->sh_name)==0) n = tp->sh_number; } - n &= (1<<SH_SIGBITS)-1; - if(n < SH_TRAP) - n--; + if((n>>SH_SIGBITS)&SH_SIGRUNTIME) + n = sh.sigruntime[(n&((1<<SH_SIGBITS)-1))-1]; + else + { + n &= (1<<SH_SIGBITS)-1; + if(n < SH_TRAP) + n--; + } + if(n<0 && (name=stakptr(o)) && *name++=='R' && *name++=='T') + { + if(name[0]=='M' && name[1]=='I' && name[2]=='N' && name[3]=='+') + { + if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name) + n = sh.sigruntime[SH_SIGRTMIN] + sig; + } + else if(name[0]=='M' && name[1]=='A' && name[2]=='X' && name[3]=='-') + { + if((sig=(int)strtol(name+4,&name,10)) >= 0 && !*name) + n = sh.sigruntime[SH_SIGRTMAX] - sig; + } + else if((sig=(int)strtol(name,&name,10)) > 0 && !*name) + n = sh.sigruntime[SH_SIGRTMIN] + sig - 1; + if(n<sh.sigruntime[SH_SIGRTMIN] || n>sh.sigruntime[SH_SIGRTMAX]) + n = -1; + } } return(n); } /* + * synthesize signal name for sig in buf + * pfx!=0 prepends SIG to default signal number + */ +static char* sig_name(int sig, char* buf, int pfx) +{ + register int i; + + i = 0; + if(sig>sh.sigruntime[SH_SIGRTMIN] && sig<sh.sigruntime[SH_SIGRTMAX]) + { + buf[i++] = 'R'; + buf[i++] = 'T'; + buf[i++] = 'M'; + if(sig>sh.sigruntime[SH_SIGRTMIN]+(sh.sigruntime[SH_SIGRTMAX]-sh.sigruntime[SH_SIGRTMIN])/2) + { + buf[i++] = 'A'; + buf[i++] = 'X'; + buf[i++] = '-'; + sig = sh.sigruntime[SH_SIGRTMAX]-sig; + } + else + { + buf[i++] = 'I'; + buf[i++] = 'N'; + buf[i++] = '+'; + sig = sig-sh.sigruntime[SH_SIGRTMIN]; + } + } + else if(pfx) + { + buf[i++] = 'S'; + buf[i++] = 'I'; + buf[i++] = 'G'; + } + i += sfsprintf(buf+i, 8, "%d", sig); + buf[i] = 0; + return buf; +} + +/* * if <flag> is positive, then print signal name corresponding to <flag> * if <flag> is zero, then print all signal names * if <flag> is negative, then print all traps @@ -274,10 +349,12 @@ { register const struct shtable2 *tp; register int sig = shp->sigmax+1; + register char *sname; + char name[10]; const char *names[SH_TRAP]; const char *traps[SH_DEBUGTRAP+1]; tp=shtab_signals; - if(flag==0) + if(flag<=0) { /* not all signals may be defined, so initialize */ while(--sig >= 0) @@ -287,8 +364,9 @@ } while(*tp->sh_name) { - sig = tp->sh_number; - sig &= ((1<<SH_SIGBITS)-1); + sig = tp->sh_number&((1<<SH_SIGBITS)-1); + if ((tp->sh_number>>SH_SIGBITS) & SH_SIGRUNTIME) + sig = sh.sigruntime[sig-1]+1; if(sig==flag) { sfprintf(sfstdout,"%s\n",tp->sh_name); @@ -301,12 +379,11 @@ tp++; } if(flag > 0) - sfprintf(sfstdout,"%d\n",flag-1); + sfputr(sfstdout, sig_name(flag-1,name,0), '\n'); else if(flag<0) { /* print the traps */ - register char *trap,*sname,**trapcom; - char name[6]; + register char *trap,**trapcom; sig = shp->st.trapmax; /* use parent traps if otrapcom is set (for $(trap) */ trapcom = (shp->st.otrapcom?shp->st.otrapcom:shp->st.trapcom); @@ -315,14 +392,7 @@ if(!(trap=trapcom[sig])) continue; if(!(sname=(char*)names[sig+1])) - { - sname = name; - sname[0] = 'S'; - sname[1] = 'I'; - sname[2] = 'G'; - sname[3] = (sig/10)+'0'; - sname[4] = (sig%10)+'0'; - } + sname = sig_name(sig,name,1); sfprintf(sfstdout,trapfmt,sh_fmtq(trap),sname); } for(sig=SH_DEBUGTRAP; sig>=0; sig--) @@ -337,11 +407,9 @@ /* print all the signal names */ for(sig=2; sig <= shp->sigmax; sig++) { - if(names[sig]) - sfputr(sfstdout,names[sig],'\n'); - else - sfprintf(sfstdout,"SIG%d\n",sig-1); + if(!(sname=(char*)names[sig+1])) + sname = sig_name(sig,name,1); + sfputr(sfstdout,sname,'\n'); } } } - Index: src/lib/libshell/common/bltins/hist.c =================================================================== --- src/lib/libshell/common/bltins/hist.c (revision 974) +++ src/lib/libshell/common/bltins/hist.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -45,7 +45,7 @@ register History_t *hp; register char *arg; register int flag,fdo; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; Sfio_t *outfile; char *fname; int range[2], incr, index2, indx= -1; @@ -57,7 +57,7 @@ #endif Histloc_t location; NOT_USED(argc); - if(!sh_histinit()) + if(!sh_histinit((void*)shp)) errormsg(SH_DICT,ERROR_system(1),e_histopen); hp = shp->hist_ptr; while((flag = optget(argv,sh_opthist))) switch(flag) @@ -215,7 +215,7 @@ sfclose(outfile); hist_eof(hp); arg = edit; - if(!arg && !(arg=nv_getval(nv_scoped(HISTEDIT))) && !(arg=nv_getval(nv_scoped(FCEDNOD)))) + if(!arg && !(arg=nv_getval(sh_scoped(shp,HISTEDIT))) && !(arg=nv_getval(sh_scoped(shp,FCEDNOD)))) arg = (char*)e_defedit; #ifdef apollo /* Index: src/lib/libshell/common/bltins/sleep.c =================================================================== --- src/lib/libshell/common/bltins/sleep.c (revision 974) +++ src/lib/libshell/common/bltins/sleep.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -46,8 +46,9 @@ { register char *cp; register double d; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; time_t tloc = 0; + char *last; while((argc = optget(argv,sh_optsleep))) switch(argc) { case ':': @@ -58,11 +59,10 @@ break; } argv += opt_info.index; - if(error_info.errors || !(cp= *argv) || !(strmatch(cp,e_numeric))) + if(error_info.errors || !(cp= *argv) || ((d=strtod(cp, (char**)&last)),*last)) errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); - if((d=strtod(cp, (char**)0)) > .10) + if(d > .10) { - sfsync(shp->outpool); time(&tloc); tloc += (time_t)(d+.5); } @@ -92,22 +92,23 @@ unsigned int sleep(unsigned int sec) { + Shell_t *shp = &sh; pid_t newpid, curpid=getpid(); void *tp; char expired = 0; - sh.lastsig = 0; + shp->lastsig = 0; tp = (void*)sh_timeradd(1000*sec, 0, completed, (void*)&expired); do { - if(!sh.waitevent || (*sh.waitevent)(-1,-1L,0)==0) + if(!shp->waitevent || (*shp->waitevent)(-1,-1L,0)==0) pause(); - if(sh.sigflag[SIGALRM]&SH_SIGTRAP) + if(shp->sigflag[SIGALRM]&SH_SIGTRAP) sh_timetraps(); if((newpid=getpid()) != curpid) { curpid = newpid; - sh.lastsig = 0; - sh.trapnote &= ~SH_SIGSET; + shp->lastsig = 0; + shp->trapnote &= ~SH_SIGSET; if(expired) expired = 0; else @@ -115,7 +116,7 @@ tp = (void*)sh_timeradd(1000*sec, 0, completed, (void*)&expired); } } - while(!expired && sh.lastsig==0); + while(!expired && shp->lastsig==0); if(!expired) timerdel(tp); sh_sigcheck(); @@ -129,6 +130,7 @@ void sh_delay(double t) { register int n = (int)t; + Shell_t *shp = &sh; #ifdef _lib_poll struct pollfd fd; if(t<=0) @@ -140,7 +142,7 @@ } if(n=(int)(1000*t)) { - if(!sh.waitevent || (*sh.waitevent)(-1,(long)n,0)==0) + if(!shp->waitevent || (*shp->waitevent)(-1,(long)n,0)==0) poll(&fd,0,n); } #else @@ -148,7 +150,7 @@ struct timeval timeloc; if(t<=0) return; - if(n=(int)(1000*t) && sh.waitevent && (*sh.waitevent)(-1,(long)n,0)) + if(n=(int)(1000*t) && shp->waitevent && (*shp->waitevent)(-1,(long)n,0)) return; n = (int)t; timeloc.tv_sec = n; @@ -166,7 +168,7 @@ } if(n=(int)(1000*t)) { - if(!sh.waitevent || (*sh.waitevent)(-1,(long)n,0)==0) + if(!shp->waitevent || (*shp->waitevent)(-1,(long)n,0)==0) select(0,(fd_set*)0,(fd_set*)0,n); } # else @@ -180,7 +182,7 @@ clock_t begin = times(&tt); if(begin==0) return; - t *= sh.lim.clk_tck; + t *= shp->lim.clk_tck; n += (t+.5); while((times(&tt)-begin) < n); } Index: src/lib/libshell/common/bltins/whence.c =================================================================== --- src/lib/libshell/common/bltins/whence.c (revision 974) +++ src/lib/libshell/common/bltins/whence.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -40,6 +40,7 @@ #define A_FLAG 4 #define F_FLAG 010 #define X_FLAG 020 +#define Q_FLAG 040 static int whence(Shell_t *,char**, int); @@ -51,7 +52,7 @@ int b_command(register int argc,char *argv[],void *extra) { register int n, flags=0; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; opt_info.index = opt_info.offset = 0; while((n = optget(argv,sh_optcommand))) switch(n) { @@ -94,7 +95,7 @@ int b_whence(int argc,char *argv[],void *extra) { register int flags=0, n; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; NOT_USED(argc); if(*argv[0]=='t') flags = V_FLAG; @@ -111,7 +112,11 @@ break; case 'p': flags |= P_FLAG; + flags &= ~V_FLAG; break; + case 'q': + flags |= Q_FLAG; + break; case ':': errormsg(SH_DICT,2, "%s", opt_info.arg); break; @@ -136,21 +141,20 @@ Dt_t *root; Namval_t *nq; char *notused; -#ifdef PATH_BFPATH - Pathcomp_t *pp; -#endif + Pathcomp_t *pp=0; int notrack = 1; + if(flags&Q_FLAG) + flags &= ~A_FLAG; while(name= *argv++) { tofree=0; aflag = ((flags&A_FLAG)!=0); cp = 0; np = 0; -#ifdef PATH_BFPATH - pp = 0; -#endif if(flags&P_FLAG) goto search; + if(flags&Q_FLAG) + goto bltins; /* reserved words first */ if(sh_lookup(name,shtab_reserved)) { @@ -179,6 +183,7 @@ aflag++; } /* built-ins and functions next */ + bltins: root = (flags&F_FLAG)?shp->bltin_tree:shp->fun_tree; if(np= nv_bfsearch(name, root, &nq, ¬used)) { @@ -194,6 +199,8 @@ else cp = sh_translate(is_function); } + if(flags&Q_FLAG) + continue; sfprintf(sfstdout,"%s%s\n",name,cp); if(!aflag) continue; @@ -206,67 +213,69 @@ cp=0; notrack=1; } -#ifdef PATH_BFPATH - if(path_search(name,pp,2)) - cp = name; - else + do { - cp = stakptr(PATH_OFFSET); - if(*cp==0) - cp = 0; - else if(*cp!='/') + if(path_search(name,&pp,2+(aflag>1))) + cp = name; + else { - cp = path_fullname(cp); - tofree=1; + cp = stakptr(PATH_OFFSET); + if(*cp==0) + cp = 0; + else if(*cp!='/') + { + cp = path_fullname(cp); + tofree=1; + } } - } -#else - if(path_search(name,cp,2)) - cp = name; - else - cp = shp->lastpath; - shp->lastpath = 0; -#endif - if(cp) - { - if(flags&V_FLAG) + if(flags&Q_FLAG) + r |= !cp; + else if(cp) { - if(*cp!= '/') + if(flags&V_FLAG) { -#ifdef PATH_BFPATH - if(!np && (np=nv_search(name,shp->track_tree,0))) - sfprintf(sfstdout,"%s %s %s/%s\n",name,sh_translate(is_talias),path_pwd(0),cp); - else if(!np || nv_isnull(np)) -#else - if(!np || nv_isnull(np)) -#endif - sfprintf(sfstdout,"%s%s\n",name,sh_translate(is_ufunction)); - continue; + if(*cp!= '/') + { + if(!np && (np=nv_search(name,shp->track_tree,0))) + sfprintf(sfstdout,"%s %s %s/%s\n",name,sh_translate(is_talias),path_pwd(0),cp); + else if(!np || nv_isnull(np)) + sfprintf(sfstdout,"%s%s\n",name,sh_translate(is_ufunction)); + continue; + } + sfputr(sfstdout,sh_fmtq(name),' '); + /* built-in version of program */ + if(*cp=='/' && (np=nv_search(cp,shp->bltin_tree,0))) + msg = sh_translate(is_builtver); + /* tracked aliases next */ + else if(aflag>1 || !notrack || strchr(name,'/')) + msg = sh_translate("is"); + else + msg = sh_translate(is_talias); + sfputr(sfstdout,msg,' '); } - sfputr(sfstdout,sh_fmtq(name),' '); - /* built-in version of program */ - if(*cp=='/' && (np=nv_search(cp,shp->bltin_tree,0))) - msg = sh_translate(is_builtver); - /* tracked aliases next */ - else if(!notrack || strchr(name,'/')) - msg = sh_translate("is"); + sfputr(sfstdout,sh_fmtq(cp),'\n'); + if(aflag) + { + if(aflag<=1) + aflag++; + if (pp) + pp = pp->next; + } else - msg = sh_translate(is_talias); - sfputr(sfstdout,msg,' '); + pp = 0; + if(tofree) + free((char*)cp); } - sfputr(sfstdout,sh_fmtq(cp),'\n'); - if(tofree) - free((char*)cp); - } - else if(aflag<=1) - { - r |= 1; - if(flags&V_FLAG) + else if(aflag<=1) { - sfprintf(sfstdout,sh_translate(e_found),sh_fmtq(name)); - sfputc(sfstdout,'\n'); + r |= 1; + if(flags&V_FLAG) + { + sfprintf(sfstdout,sh_translate(e_found),sh_fmtq(name)); + sfputc(sfstdout,'\n'); + } } - } + } while(pp); } return(r); } Index: src/lib/libshell/common/bltins/cflow.c =================================================================== --- src/lib/libshell/common/bltins/cflow.c (revision 974) +++ src/lib/libshell/common/bltins/cflow.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -47,7 +47,7 @@ int b_return(register int n, register char *argv[],void *extra) { register char *arg; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; struct checkpt *pp = (struct checkpt*)shp->jmplist; const char *options = (**argv=='r'?sh_optreturn:sh_optexit); while((n = optget(argv,options))) switch(n) @@ -85,7 +85,7 @@ { char *arg; register int cont= **argv=='c'; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; while((n = optget(argv,cont?sh_optcont:sh_optbreak))) switch(n) { case ':': Index: src/lib/libshell/common/bltins/read.c =================================================================== --- src/lib/libshell/common/bltins/read.c (revision 974) +++ src/lib/libshell/common/bltins/read.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -19,7 +19,7 @@ ***********************************************************************/ #pragma prototyped /* - * read [-Aprs] [-d delim] [-u filenum] [-t timeout] [-n n] [-N n] [name...] + * read [-ACprs] [-d delim] [-u filenum] [-t timeout] [-n n] [-N n] [name...] * * David Korn * AT&T Labs @@ -45,23 +45,64 @@ #define N_FLAG 8 /* fixed size read at most */ #define NN_FLAG 0x10 /* fixed size read exact */ #define V_FLAG 0x20 /* use default value */ +#define C_FLAG 0x40 /* read into compound variable */ #define D_FLAG 8 /* must be number of bits for all flags */ +struct read_save +{ + int argc; + char **avin; + char **argv; + int fd; + int flags; + long timeout; +}; + int b_read(int argc,char *argv[], void *extra) { Sfdouble_t sec; register char *name; - register int r, flags=0, fd=0; - register Shell_t *shp = (Shell_t*)extra; + register int r=(argc+1)*sizeof(char*), flags=0, fd=0; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; long timeout = 1000*shp->st.tmout; int save_prompt; + struct read_save *rp; static char default_prompt[3] = {ESC,ESC}; - NOT_USED(argc); + if(rp = (struct read_save*)(((Shbltin_t*)extra)->data)) + { + if(argc==rp->argc && memcmp(argv,rp->avin,r)==0) + { + flags = rp->flags; + timeout = rp->timeout; + fd = rp->fd; + argv = rp->argv; + goto bypass; + } + free((void*)rp); + rp = 0; + ((Shbltin_t*)extra)->data = 0; + if(argc==0) + return(0); + } +#if 0 + if(rp = newof(NIL(struct read_save*),struct read_save,1,r=(argc+1)*sizeof(char*))) +#else + if(rp = newof(NIL(struct read_save*),struct read_save,1,r)) +#endif + { + rp->argc = argc; + rp->avin = (char**)(rp+1); + memcpy(rp->avin, argv, r); + ((Shbltin_t*)extra)->data = (void*)rp; + } while((r = optget(argv,sh_optread))) switch(r) { case 'A': flags |= A_FLAG; break; + case 'C': + flags |= C_FLAG; + break; case 't': sec = sh_strnum(opt_info.arg, (char**)0,1); timeout = sec ? 1000*sec : 1; @@ -112,7 +153,7 @@ if(error_info.errors) errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0)); if(!((r=shp->fdstatus[fd])&IOREAD) || !(r&(IOSEEK|IONOSEEK))) - r = sh_iocheckfd(fd); + r = sh_iocheckfd(shp,fd); if(fd<0 || !(r&IOREAD)) errormsg(SH_DICT,ERROR_system(1),e_file+4); /* look for prompt */ @@ -126,6 +167,11 @@ sfwrite(sfstderr,shp->prompt,r-1); } } + rp->fd = fd; + rp->flags = flags; + rp->timeout = timeout; + rp->argv = argv; +bypass: shp->timeout = 0; save_prompt = shp->nextprompt; shp->nextprompt = 0; @@ -166,14 +212,15 @@ register unsigned char *cp; register Namval_t *np; register char *name, *val; - register Sfio_t *iop; + register Sfio_t *iop; + Namfun_t *nfp; char *ifs; unsigned char *cpmax; unsigned char *del; char was_escape = 0; char use_stak = 0; - char was_write = 0; - char was_share = 1; + volatile char was_write = 0; + volatile char was_share = 1; int rel, wrd; long array_index = 0; void *timeslot=0; @@ -181,13 +228,13 @@ int jmpval=0; int size = 0; struct checkpt buff; - if(!(iop=shp->sftable[fd]) && !(iop=sh_iostream(fd))) + if(!(iop=shp->sftable[fd]) && !(iop=sh_iostream(shp,fd))) return(1); if(names && (name = *names)) { if(val= strchr(name,'?')) *val = 0; - np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME|NV_ARRAY); + np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME); if((flags&V_FLAG) && shp->ed_context) ((struct edit*)shp->ed_context)->e_default = np; if(flags&A_FLAG) @@ -197,6 +244,12 @@ nv_unset(np); nv_putsub(np,NIL(char*),0L); } + else if(flags&C_FLAG) + { + delim = -1; + nv_unset(np); + nv_setvtree(np); + } else name = *++names; if(val) @@ -219,11 +272,15 @@ if(shp->fdstatus[fd]&IOTTY) tty_raw(fd,1); } +#if 1 + if(!nv_isattr(np,NV_BINARY) && !(flags&(N_FLAG|NN_FLAG))) +#else if(!(flags&(N_FLAG|NN_FLAG))) +#endif { Namval_t *mp; /* set up state table based on IFS */ - ifs = nv_getval(mp=nv_scoped(IFSNOD)); + ifs = nv_getval(mp=sh_scoped(shp,IFSNOD)); if((flags&R_FLAG) && shp->ifstable['\\']==S_ESC) shp->ifstable['\\'] = 0; else if(!(flags&R_FLAG) && shp->ifstable['\\']==0) @@ -237,8 +294,21 @@ shp->ifstable[0] = S_EOF; } sfclrerr(iop); - if(np->nvfun && np->nvfun->disc->readf) - return((* np->nvfun->disc->readf)(np,iop,delim,np->nvfun)); + for(nfp=np->nvfun; nfp; nfp = nfp->next) + { + if(nfp->disc && nfp->disc->readf) + { + if((c=(*nfp->disc->readf)(np,iop,delim,nfp))>=0) + return(c); + } + } +#if 1 + if(nv_isattr(np,NV_BINARY) && !(flags&(N_FLAG|NN_FLAG))) + { + flags |= NN_FLAG; + size = nv_size(np); + } +#endif was_write = (sfset(iop,SF_WRITE,0)&SF_WRITE)!=0; if(fd==0) was_share = (sfset(iop,SF_SHARE,1)&SF_SHARE)!=0; @@ -292,10 +362,15 @@ timerdel(timeslot); if(nv_isattr(np,NV_BINARY)) { - if(c<sizeof(buf)) - var = memdup(var,c); - nv_putval(np,var, NV_RAW); - nv_setsize(np,c); + if(c==nv_size(np)) + memcpy((char*)np->nvalue.cp,var,c); + else + { + if(c<sizeof(buf)) + var = memdup(var,c); + nv_putval(np,var, NV_RAW); + nv_setsize(np,c); + } } else { @@ -313,7 +388,7 @@ timerdel(timeslot); if((flags&S_FLAG) && !shp->hist_ptr) { - sh_histinit(); + sh_histinit((void*)shp); if(!shp->hist_ptr) flags &= ~S_FLAG; } Index: src/lib/libshell/common/bltins/test.c =================================================================== --- src/lib/libshell/common/bltins/test.c (revision 974) +++ src/lib/libshell/common/bltins/test.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -113,7 +113,7 @@ struct test tdata; register char *cp = argv[0]; register int not; - tdata.sh = (Shell_t*)extra; + tdata.sh = ((Shbltin_t*)extra)->shp; tdata.av = argv; tdata.ap = 1; if(c_eq(cp,'[')) @@ -125,6 +125,11 @@ if(argc <= 1) return(1); cp = argv[1]; + if(c_eq(cp,'(') && argc<=6 && c_eq(argv[argc-1],')')) + { + cp = (++argv)[1]; + argc -= 2; + } not = c_eq(cp,'!'); /* posix portion for test */ switch(argc) @@ -173,8 +178,6 @@ case 2: return(*cp==0); } - if(argc==5) - argv--; tdata.ac = argc; return(!expr(&tdata,0)); } Index: src/lib/libshell/common/bltins/umask.c =================================================================== --- src/lib/libshell/common/bltins/umask.c (revision 974) +++ src/lib/libshell/common/bltins/umask.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -75,7 +75,7 @@ { char *cp = mask; flag = umask(0); - c = strperm(cp,&cp,~flag); + c = strperm(cp,&cp,~flag&0777); if(*cp) { umask(flag); Index: src/lib/libshell/common/bltins/shiocmd_solaris.c =================================================================== --- src/lib/libshell/common/bltins/shiocmd_solaris.c (revision 974) +++ src/lib/libshell/common/bltins/shiocmd_solaris.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2007 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -21,6 +21,7 @@ #include <shell.h> #include <stdio.h> +#include <stdbool.h> #include <option.h> #include <stk.h> #include <tm.h> @@ -31,6 +32,9 @@ #endif #include <poll.h> +#define sh_contexttoshb(context) ((Shbltin_t*)(context)) +#define sh_contexttoshell(context) ((context)?(sh_contexttoshb(context)->shp):(NULL)) + /* * time formatting related */ @@ -487,7 +491,7 @@ { register Namval_t *np; register int n,oflag=0; - Shell_t *shp = (Shell_t*)extra; + Shell_t *shp = sh_contexttoshell(extra); struct filedata *fdp; mode_t mode = 0666; long flags = 0; @@ -658,18 +662,18 @@ { register Namval_t *np; register int n; - Shell_t *shp = (Shell_t*)extra; + Shell_t *shp = sh_contexttoshell(extra); struct filedata *fdp; - int inherit = 0; + bool inherit = false; FILE *file = NULL; int ffd, fd = -1; while (n = optget(argv, sh_opttmpfile)) switch (n) { case 'i': - inherit = 1; + inherit = true; break; case 'I': - inherit = 0; + inherit = false; break; case ':': errormsg(SH_DICT, 2, "%s", opt_info.arg); @@ -734,17 +738,17 @@ { register Namval_t *np; register int n; - Shell_t *shp = (Shell_t*)extra; + Shell_t *shp = sh_contexttoshell(extra); struct filedata *fdp; - int inherit = 0; + bool inherit = false; int ffd, fd = -1; while (n = optget(argv, sh_optdup)) switch (n) { case 'i': - inherit = 1; + inherit = true; break; case 'I': - inherit = 0; + inherit = false; break; case ':': errormsg(SH_DICT, 2, "%s", opt_info.arg); @@ -809,7 +813,7 @@ { register Namval_t *np; register int n; - Shell_t *shp = (Shell_t*)extra; + Shell_t *shp = sh_contexttoshell(extra); struct filedata *fdp; long flags = 0; struct stat statb; @@ -854,7 +858,7 @@ } static const char sh_optpoll[] = -"[-?\n@(#)$Id: poll (AT&T Labs Research) 2007-05-07 $\n]" +"[-?\n@(#)$Id: poll (AT&T Labs Research) 2007-12-20 $\n]" "[-author?Roland Mainz <roland.mainz@nrubsig.org]" "[-license?http://www.opensource.org/licenses/cpl1.0.txt]" "[+NAME? poll - input/output multiplexing]" @@ -957,10 +961,20 @@ "[+?Regular files always poll TRUE for reading and writing.]" -"[t:timeout]:[milliseconds?Timeout in milliseconds. If the value timeout is 0, " +"[c:fdcount]:[fdcount?Upon successful completion, a non-negative value is " + "returned. A positive value indicates the total number of " + "file descriptors that has been selected (that is, file " + "descriptors for which the revents member is non-zero). A " + "value of 0 indicates that the call timed out and no file " + "descriptors have been selected. Upon failure, -1 is returned.]" +"[t:timeout]:[seconds?Timeout in seconds. If the value timeout is 0, " "poll returns immediately. If the value of timeout is -1, poll " "blocks until a requested event occurs or until the call is " "interrupted.]" +"[T:mtimeout]:[milliseconds?Timeout in milliseconds. If the value timeout is 0, " + "poll returns immediately. If the value of timeout is -1, poll " + "blocks until a requested event occurs or until the call is " + "interrupted.]" "\n" "\nvar\n" "\n" @@ -1041,33 +1055,49 @@ if(*s=='|') *s='\0'; } + +#undef getconf +#define getconf(x) strtol(astconf(x,NiL,NiL),NiL,0) extern int b_poll(int argc, char *argv[], void *extra) { register Namval_t *np; register int n; - Shell_t *shp = (Shell_t*)extra; + Shell_t *shp = sh_contexttoshell(extra); char *varname; int fd; -/* |BPOLL_MAX| needs to be larger than |OPEN_MAX| to make sure we - * can listen to different sets of events per fd. - */ -#define BPOLL_MAX 512 - struct pollfd pollfd[BPOLL_MAX]; unsigned int numpollfd = 0; int i; char *s; - long timeout = -1; + double timeout = -1.; char buff[256]; - + char *pollfdcountvarname = NULL; + long open_max, + bpoll_max; + + if ((open_max = getconf("OPEN_MAX")) <= 0) + open_max = OPEN_MAX; + /* |bpoll_max| needs to be larger than |OPEN_MAX| to make sure we + * can listen to different sets of events per fd. + */ + bpoll_max = open_max*2L; + while (n = optget(argv, sh_optpoll)) switch (n) { case 't': + case 'T': errno = 0; - timeout = strtol(opt_info.arg, (char **)NULL, 0); + timeout = strtod(opt_info.arg, (char **)NULL); if (errno != 0) errormsg(SH_DICT, ERROR_system(1), "%s: invalid timeout", opt_info.arg); + + /* -t uses seconds, -T milliseconds */ + if (n == 't') + timeout *= 1000.; break; + case 'c': + pollfdcountvarname = opt_info.arg; + break; case ':': errormsg(SH_DICT, 2, "%s", opt_info.arg); break; @@ -1081,25 +1111,27 @@ errormsg(SH_DICT, ERROR_usage(2), optusage((char*)0)); varname = argv[0]; + + struct pollfd pollfd[bpoll_max]; - for(i=0 ; i < BPOLL_MAX ; i++) + for(i=0 ; i < bpoll_max ; i++) { - np = nv_open_fmt(shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN|NV_NOFAIL|NV_NOADD, "%s[%d].fd", varname, i); + np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD, "%s[%d].fd", varname, i); if (!np) break; fd = (int)nv_getnum(np); if (fd < 0 || fd > OPEN_MAX) - errormsg(SH_DICT, ERROR_system(1), "poll: invalid pollfd fd"); + errormsg(SH_DICT, ERROR_system(1), "invalid pollfd fd"); nv_close(np); pollfd[i].fd = fd; - np = nv_open_fmt(shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN|NV_NOFAIL|NV_NOADD, "%s[%d].events", varname, i); - if (!s) - errormsg(SH_DICT, ERROR_system(1), "poll: missing pollfd events"); + np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD, "%s[%d].events", varname, i); + if (!np) + errormsg(SH_DICT, ERROR_system(1), "missing pollfd events"); s = nv_getval(np); if (!s) - errormsg(SH_DICT, ERROR_system(1), "poll: missing pollfd events value"); + errormsg(SH_DICT, ERROR_system(1), "missing pollfd events value"); pollfd[i].events = poll_strtoevents(s); nv_close(np); @@ -1108,19 +1140,30 @@ numpollfd++; } - if (i == BPOLL_MAX) - errormsg(SH_DICT, ERROR_system(1), "poll: cannot handle more than %d entries.", BPOLL_MAX); + if (i == bpoll_max) + errormsg(SH_DICT, ERROR_system(1), "cannot handle more than %d entries.", bpoll_max); n = poll(pollfd, numpollfd, timeout); /* FixMe: EGAIN and EINTR may require extra handling */ if (n < 0) - errormsg(SH_DICT, ERROR_system(1), "poll: failure"); + errormsg(SH_DICT, ERROR_system(1), "failure"); + if (pollfdcountvarname) + { + int32_t v = n; + + np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL, "%s", pollfdcountvarname); + if (!np) + errormsg(SH_DICT, ERROR_system(1), "couldn't create poll count variable %s", pollfdcountvarname); + nv_putval(np, (char *)&v, NV_INTEGER); + nv_close(np); + } + for(i=0 ; i < numpollfd ; i++) { - np = nv_open_fmt(shp->var_tree, NV_ARRAY|NV_VARNAME|NV_NOASSIGN|NV_NOFAIL, "%s[%d].revents", varname, i); + np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL, "%s[%d].revents", varname, i); if (!np) - errormsg(SH_DICT, ERROR_system(1), "poll: couldn't create pollfd %s[%d].revents", varname, i); + errormsg(SH_DICT, ERROR_system(1), "couldn't create pollfd %s[%d].revents", varname, i); poll_eventstostr(buff, pollfd[i].revents); @@ -1150,7 +1193,7 @@ extern int b_rewind(int argc, char *argv[], void *extra) { - Shell_t *shp = (Shell_t*)extra; + Shell_t *shp = sh_contexttoshell(extra); int fd = -1; register int n; while (n = optget(argv, sh_optrewind)) switch (n) @@ -1177,4 +1220,3 @@ return(0); } - Index: src/lib/libshell/common/bltins/getopts.c =================================================================== --- src/lib/libshell/common/bltins/getopts.c (revision 974) +++ src/lib/libshell/common/bltins/getopts.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -35,16 +35,17 @@ static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp) { + Shell_t *shp = *(Shell_t**)(dp+1); + Stk_t *stkp = shp->stk; if(nv_search(s,sh.fun_tree,0)) { - int savtop = staktell(); - char *savptr = stakfreeze(0); - stakputc('$'); - stakputc('('); - stakputs(s); - stakputc(')'); - sfputr(sp,sh_mactry(stakfreeze(1)),-1); - stakset(savptr,savtop); + int savtop = stktell(stkp); + char *savptr = stkfreeze(stkp,0); + sfputc(stkp,'$'); + sfputc(stkp,'('); + sfputr(stkp,s,')'); + sfputr(sp,sh_mactry(shp,stkfreeze(stkp,1)),-1); + stkset(stkp,savptr,savtop); } return(1); } @@ -54,14 +55,18 @@ register char *options=error_info.context->id; register Namval_t *np; register int flag, mode, r=0; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; char value[2], key[2]; - int jmpval; + int jmpval,extended; struct checkpt buff, *pp; - Optdisc_t disc; + struct { + Optdisc_t hdr; + Shell_t *sh; + } disc; memset(&disc, 0, sizeof(disc)); - disc.version = OPT_VERSION; - disc.infof = infof; + disc.hdr.version = OPT_VERSION; + disc.hdr.infof = infof; + disc.sh = shp; value[1] = 0; key[1] = 0; while((flag = optget(argv,sh_optgetopts))) switch(flag) @@ -98,6 +103,7 @@ opt_info.offset = shp->st.optchar; if(mode= (*options==':')) options++; + extended = *options=='\n' && *(options+1)=='[' || *options=='[' && *(options+1)=='-'; sh_pushcontext(&buff,1); jmpval = sigsetjmp(buff.buff,0); if(jmpval) @@ -107,7 +113,7 @@ pp->mode = SH_JMPERREXIT; sh_exit(2); } - opt_info.disc = &disc; + opt_info.disc = &disc.hdr; switch(opt_info.index>=0 && opt_info.index<=argc?(opt_info.num= LONG_MIN,flag=optget(argv,options)):0) { case '?': @@ -165,18 +171,20 @@ np = nv_open(nv_name(OPTARGNOD),shp->var_tree,NV_NOSCOPE); if(opt_info.num == LONG_MIN) nv_putval(np, opt_info.arg, NV_RDONLY); - else if (opt_info.num > 0 && opt_info.arg && opt_info.arg[0] == (char)opt_info.num) + else if (opt_info.arg && opt_info.num > 0 && isalpha((char)opt_info.num) && !isdigit(opt_info.arg[0]) && opt_info.arg[0] != '-' && opt_info.arg[0] != '+') { key[0] = (char)opt_info.num; key[1] = 0; nv_putval(np, key, NV_RDONLY); } - else + else if(extended) { Sfdouble_t d; d = opt_info.number; nv_putval(np, (char*)&d, NV_LDOUBLE|NV_RDONLY); } + else + nv_putval(np, opt_info.arg, NV_RDONLY); nv_close(np); sh_popcontext(&buff); opt_info.disc = 0; Index: src/lib/libshell/common/bltins/mkservice.c =================================================================== --- src/lib/libshell/common/bltins/mkservice.c (revision 974) +++ src/lib/libshell/common/bltins/mkservice.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/bltins/misc.c =================================================================== --- src/lib/libshell/common/bltins/misc.c (revision 974) +++ src/lib/libshell/common/bltins/misc.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -63,7 +63,7 @@ register int n; logdata.clear = 0; logdata.arg0 = 0; - logdata.sh = (Shell_t*)extra; + logdata.sh = ((Shbltin_t*)extra)->shp; logdata.sh->st.ioset = 0; while (n = optget(argv, sh_optexec)) switch (n) { @@ -102,7 +102,7 @@ register Shell_t *shp; const char *pname; if(argc) - shp = (Shell_t*)extra; + shp = ((Shbltin_t*)extra)->shp; else { logp = (struct login*)extra; @@ -143,15 +143,15 @@ if(logp && logp->arg0) argv[0] = logp->arg0; #ifdef JOBS - if(job_close() < 0) + if(job_close(shp) < 0) return(1); #endif /* JOBS */ /* force bad exec to terminate shell */ pp->mode = SH_JMPEXIT; sh_sigreset(2); - sh_freeup(); + sh_freeup(shp); path_exec(pname,argv,NIL(struct argnod*)); - sh_done(0); + sh_done(shp,0); } return(1); } @@ -182,7 +182,7 @@ int b_eval(int argc,char *argv[], void *extra) { register int r; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; NOT_USED(argc); while (r = optget(argv,sh_opteval)) switch (r) { @@ -209,14 +209,13 @@ register char *script; register Namval_t *np; register int jmpval; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; struct sh_scoped savst, *prevscope = shp->st.self; char *filename=0; int fd; struct dolnod *argsave=0, *saveargfor; struct checkpt buff; Sfio_t *iop=0; - NOT_USED(extra); while (n = optget(argv,sh_optdot)) switch (n) { case ':': @@ -241,11 +240,7 @@ { if(!np->nvalue.ip) { -#ifdef PATH_BFPATH - path_search(script,NIL(Pathcomp_t*),0); -#else - path_search(script,NIL(char*),0); -#endif + path_search(script,NIL(Pathcomp_t**),0); if(np->nvalue.ip) { if(nv_isattr(np,NV_FPOSIX)) @@ -261,7 +256,7 @@ { if((fd=path_open(script,path_get(script))) < 0) errormsg(SH_DICT,ERROR_system(1),e_open,script); - filename = path_fullname(stakptr(PATH_OFFSET)); + filename = path_fullname(stkptr(shp->stk,PATH_OFFSET)); } } *prevscope = shp->st; @@ -277,7 +272,7 @@ nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE); shp->posix_fun = 0; if(np || argv[1]) - argsave = sh_argnew(argv,&saveargfor); + argsave = sh_argnew(shp,argv,&saveargfor); sh_pushcontext(&buff,SH_JMPDOT); jmpval = sigsetjmp(buff.buff,0); if(jmpval == 0) @@ -296,7 +291,7 @@ free((void*)shp->st.filename); shp->dot_depth--; if((np || argv[1]) && jmpval!=SH_JMPSCRIPT) - sh_argreset(argsave,saveargfor); + sh_argreset(shp,argsave,saveargfor); else { prevscope->dolc = shp->st.dolc; @@ -340,7 +335,7 @@ int b_shift(register int n, register char *argv[], void *extra) { register char *arg; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; while((n = optget(argv,sh_optshift))) switch(n) { case ':': @@ -366,7 +361,7 @@ int b_wait(int n,register char *argv[],void *extra) { - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; while((n = optget(argv,sh_optwait))) switch(n) { case ':': @@ -392,7 +387,7 @@ int b_bg(register int n,register char *argv[],void *extra) { register int flag = **argv; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; register const char *optstr = sh_optbg; if(*argv[0]=='f') optstr = sh_optfg; @@ -426,7 +421,7 @@ int b_jobs(register int n,char *argv[],void *extra) { register int flag = 0; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; while((n = optget(argv,sh_optjobs))) switch(n) { case 'l': @@ -506,7 +501,7 @@ register int flag, n; register const char *optstr; register char *vend; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; if(argv[0][1]=='p') { optstr = sh_optvpath; @@ -539,7 +534,7 @@ flag |= FS3D_GET; if((n = mount(*argv,(char*)0,flag,0)) >= 0) { - vend = stakalloc(++n); + vend = stkalloc(shp->stk,++n); n = mount(*argv,vend,flag|FS3D_SIZE(n),0); } if(n < 0) Index: src/lib/libshell/common/bltins/print.c =================================================================== --- src/lib/libshell/common/bltins/print.c (revision 974) +++ src/lib/libshell/common/bltins/print.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -60,6 +60,7 @@ int argsize; int intvar; char **nextarg; + char *lastarg; char cescape; char err; Shell_t *sh; @@ -69,6 +70,7 @@ static const char preformat[] = ""; static char *genformat(char*); static int fmtvecho(const char*, struct printf*); +static ssize_t fmtbase64(Sfio_t*, char*); struct print { @@ -105,7 +107,7 @@ struct print prdata; prdata.options = sh_optecho+5; prdata.raw = prdata.echon = 0; - prdata.sh = (Shell_t*)extra; + prdata.sh = ((Shbltin_t*)extra)->shp; NOT_USED(argc); /* This mess is because /bin/echo on BSD is different */ if(!prdata.sh->universe) @@ -145,7 +147,7 @@ struct print prdata; NOT_USED(argc); memset(&prdata,0,sizeof(prdata)); - prdata.sh = (Shell_t*)extra; + prdata.sh = ((Shbltin_t*)extra)->shp; prdata.options = sh_optprintf; return(b_print(-1,argv,&prdata)); } @@ -159,10 +161,10 @@ { register Sfio_t *outfile; register int exitval=0,n, fd = 1; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; const char *options, *msg = e_file+4; char *format = 0; - int sflag = 0, nflag=0, rflag=0; + int sflag = 0, nflag=0, rflag=0, vflag=0; if(argc>0) { options = sh_optprint; @@ -196,7 +198,7 @@ break; case 's': /* print to history file */ - if(!sh_histinit()) + if(!sh_histinit((void*)shp)) errormsg(SH_DICT,ERROR_system(1),e_history); fd = sffileno(shp->hist_ptr->histfp); sh_onstate(SH_HISTORY); @@ -218,6 +220,9 @@ fd = -1; break; + case 'v': + vflag=1; + break; case ':': /* The following is for backward compatibility */ #if OPT_VERSION >= 19990123 @@ -252,6 +257,8 @@ argv += opt_info.index; if(error_info.errors || (argc<0 && !(format = *argv++))) errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); + if(vflag && format) + errormsg(SH_DICT,ERROR_usage(2),"-v and -f are mutually exclusive"); skip: if(format) format = genformat(format); @@ -265,7 +272,7 @@ n = 0; } else if(!(n=shp->fdstatus[fd])) - n = sh_iocheckfd(fd); + n = sh_iocheckfd(shp,fd); if(!(n&IOWRITE)) { /* don't print error message for stdout for compatibility */ @@ -316,6 +323,11 @@ sfpool(sfstderr,pool,SF_WRITE); exitval = pdata.err; } + else if(vflag) + { + while(*argv) + fmtbase64(outfile,*argv++); + } else { /* echo style print */ @@ -454,15 +466,23 @@ return(stakptr(offset)); } +#if 1 +static ssize_t fmtbase64(Sfio_t *iop, char *string) +#else static void *fmtbase64(char *string, ssize_t *sz) +#endif { char *cp; Sfdouble_t d; - size_t size; + ssize_t size,n; Namval_t *np = nv_open(string, NiL, NV_VARNAME|NV_NOASSIGN|NV_NOADD); static union types_t number; if(!np) +#if 1 + return(0); +#else return(""); +#endif if(nv_isattr(np,NV_INTEGER)) { d = nv_getnum(np); @@ -502,11 +522,43 @@ number.i = (int)d; } } +#if 1 + return(sfwrite(iop, (void*)&number, size)); +#else if(sz) *sz = size; return((void*)&number); +#endif } if(nv_isattr(np,NV_BINARY)) +#if 1 + { + Namfun_t *fp; + for(fp=np->nvfun; fp && !fp->disc && !fp->disc->writef;fp=fp->next); + for(fp=np->nvfun; fp;fp=fp->next) + { + if(fp->disc && fp->disc->writef) + break; + } + if(fp) + return (*fp->disc->writef)(np, iop, 0, fp); + else + { + int n = nv_size(np); + cp = (char*)np->nvalue.cp; + if((size = n)==0) + size = strlen(cp); + size = sfwrite(iop, cp, size); + return(n?n:size); + } + } + else + { + cp = nv_getval(np); + size = strlen(cp); + return(sfwrite(iop,cp,size)); + } +#else nv_onattr(np,NV_RAW); cp = nv_getval(np); if(nv_isattr(np,NV_BINARY)) @@ -516,8 +568,35 @@ if(sz) *sz = size; return((void*)cp); +#endif } +static int varname(const char *str, int n) +{ + register int c,dot=1,len=1; + if(n < 0) + { + if(*str=='.') + str++; + n = strlen(str); + } + for(;n > 0; n-=len) + { +#ifdef SHOPT_MULTIBYTE + len = mbsize(str); + c = mbchar(str); +#else + c = *(unsigned char*)str++; +#endif + if(dot && !(isalpha(c)||c=='_')) + break; + else if(dot==0 && !(isalnum(c) || c=='_' || c == '.')) + break; + dot = (c=='.'); + } + return(n==0); +} + static int extend(Sfio_t* sp, void* v, Sffmt_t* fe) { char* lastchar = ""; @@ -532,6 +611,20 @@ struct printf* pp = (struct printf*)fe; register char* argp = *pp->nextarg; + if(fe->n_str>0 && varname(fe->t_str,fe->n_str) && (!argp || varname(argp,-1))) + { + if(argp) + pp->lastarg = argp; + else + argp = pp->lastarg; + if(argp) + { + sfprintf(pp->sh->strbuf,"%s.%.*s%c",argp,fe->n_str,fe->t_str,0); + argp = sfstruse(pp->sh->strbuf); + } + } + else + pp->lastarg = 0; fe->flags |= SFFMT_VALUE; if(!argp || format=='Z') { @@ -662,6 +755,11 @@ case '\'': case '"': value->ll = ((unsigned char*)argp)[1]; + if(argp[2] && (argp[2] != argp[0] || argp[3])) + { + errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp); + pp->err = 1; + } break; default: d = sh_strnum(argp,&lastchar,0); @@ -698,6 +796,21 @@ case 'F': case 'G': d = sh_strnum(*pp->nextarg,&lastchar,0); + switch(*argp) + { + case '\'': + case '"': + d = ((unsigned char*)argp)[1]; + if(argp[2] && (argp[2] != argp[0] || argp[3])) + { + errormsg(SH_DICT,ERROR_warn(0),e_charconst,argp); + pp->err = 1; + } + break; + default: + d = sh_strnum(*pp->nextarg,&lastchar,0); + break; + } if(SFFMT_LDOUBLE) { value->ld = d; @@ -750,7 +863,9 @@ } break; case 'B': - value->s = (char*)fmtbase64(value->s, &fe->size); + fe->size = fmtbase64(sh.strbuf,value->s); + value->s = sfstruse(sh.strbuf); + fe->flags |= SFFMT_SHORT; break; case 'H': value->s = fmthtml(value->s); Index: src/lib/libshell/common/bltins/alarm.c =================================================================== --- src/lib/libshell/common/bltins/alarm.c (revision 974) +++ src/lib/libshell/common/bltins/alarm.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -235,7 +235,7 @@ register int n,rflag=0; register Namval_t *np; register struct tevent *tp; - register Shell_t *shp = (Shell_t*)extra; + register Shell_t *shp = ((Shbltin_t*)extra)->shp; while (n = optget(argv, sh_optalarm)) switch (n) { case 'r': @@ -262,7 +262,7 @@ np = nv_open(argv[0],shp->var_tree,NV_NOARRAY|NV_VARNAME|NV_NOASSIGN); if(!nv_isnull(np)) nv_unset(np); - nv_setattr(np, NV_INTEGER|NV_DOUBLE); + nv_setattr(np, NV_DOUBLE); if(!(tp = newof(NIL(struct tevent*),struct tevent,1,0))) errormsg(SH_DICT,ERROR_exit(1),e_nospace); tp->fun.disc = &alarmdisc; Index: src/lib/libshell/common/bltins/typeset.c =================================================================== --- src/lib/libshell/common/bltins/typeset.c (revision 974) +++ src/lib/libshell/common/bltins/typeset.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -48,6 +48,8 @@ Namval_t *tp; Sfio_t *outfile; char *prefix; + char *tname; + char *help; int aflag; int argnum; int scanmask; @@ -59,7 +61,7 @@ static int print_namval(Sfio_t*, Namval_t*, int, struct tdata*); static void print_attribute(Namval_t*,void*); static void print_all(Sfio_t*, Dt_t*, struct tdata*); -static void print_scan(Sfio_t*, int, Dt_t*, int, struct tdata*t); +static void print_scan(Sfio_t*, int, Dt_t*, int, struct tdata*); static int b_unall(int, char**, Dt_t*, Shell_t*); static int b_common(char**, int, Dt_t*, struct tdata*); static void pushname(Namval_t*,void*); @@ -85,7 +87,7 @@ struct tdata tdata; NOT_USED(argc); memset((void*)&tdata,0,sizeof(tdata)); - tdata.sh = (Shell_t*)extra; + tdata.sh = ((Shbltin_t*)extra)->shp; tdata.aflag = '-'; while((flag = optget(argv,*command=='e'?sh_optexport:sh_optreadonly))) switch(flag) { @@ -120,8 +122,8 @@ else { flag = (NV_ASSIGN|NV_EXPORT|NV_IDENT); - if(!sh.prefix) - sh.prefix = ""; + if(!tdata.sh->prefix) + tdata.sh->prefix = ""; } return(b_common(argv,flag,tdata.sh->var_tree, &tdata)); } @@ -135,7 +137,7 @@ struct tdata tdata; NOT_USED(argc); memset((void*)&tdata,0,sizeof(tdata)); - tdata.sh = (Shell_t*)extra; + tdata.sh = ((Shbltin_t*)extra)->shp; troot = tdata.sh->alias_tree; if(*argv[0]=='h') flag = NV_TAGGED; @@ -169,11 +171,23 @@ argv += (opt_info.index-1); if(flag&NV_TAGGED) { - if(argv[1] && strcmp(argv[1],"-r")==0) + /* hacks to handle hash -r | -- */ + if(argv[1] && argv[1][0]=='-') { - /* hack to handle hash -r */ - nv_putval(PATHNOD,nv_getval(PATHNOD),NV_RDONLY); - return(0); + if(argv[1][1]=='r' && argv[1][2]==0) + { + nv_putval(PATHNOD,nv_getval(PATHNOD),NV_RDONLY); + argv++; + if(!argv[1]) + return(0); + } + if(argv[1][0]=='-') + { + if(argv[1][1]=='-' && argv[1][2]==0) + argv++; + else + errormsg(SH_DICT, ERROR_exit(1), e_option, argv[1]); + } } troot = tdata.sh->track_tree; } @@ -188,28 +202,41 @@ #endif int b_typeset(int argc,register char *argv[],void *extra) { - register int flag = NV_VARNAME|NV_ASSIGN; - register int n; - struct tdata tdata; - Namtype_t *ntp = (Namtype_t*)extra; - Dt_t *troot; - int isfloat=0, shortint=0; + register int n, flag = NV_VARNAME|NV_ASSIGN; + struct tdata tdata; + const char *optstring = sh_opttypeset; + Namdecl_t *ntp = (Namdecl_t*)((Shbltin_t*)extra)->ptr; + Dt_t *troot; + int isfloat=0, shortint=0, sflag=0; NOT_USED(argc); memset((void*)&tdata,0,sizeof(tdata)); - tdata.sh = ntp->shp; - tdata.tp = ntp->np; + tdata.sh = ((Shbltin_t*)extra)->shp; + if(ntp) + { + tdata.tp = ntp->tp; + opt_info.disc = (Optdisc_t*)ntp->optinfof; + optstring = ntp->optstring; + } troot = tdata.sh->var_tree; - opt_info.disc = (Optdisc_t*)ntp->optinfof; - while((n = optget(argv,ntp->optstring))) + while((n = optget(argv,optstring))) { switch(n) { case 'a': flag |= NV_IARRAY; + if(opt_info.arg && *opt_info.arg!='[') + { + opt_info.index--; + goto endargs; + } + tdata.tname = opt_info.arg; break; case 'A': flag |= NV_ARRAY; break; + case 'C': + flag |= NV_COMVAR; + break; case 'E': /* The following is for ksh88 compatibility */ if(opt_info.offset && !strchr(argv[opt_info.index],'E')) @@ -218,11 +245,20 @@ break; } case 'F': + case 'X': if(!opt_info.arg || (tdata.argnum = opt_info.num) <0) tdata.argnum = 10; isfloat = 1; if(n=='E') + { + flag &= ~NV_HEXFLOAT; flag |= NV_EXPNOTE; + } + else if(n=='X') + { + flag &= ~NV_EXPNOTE; + flag |= NV_HEXFLOAT; + } break; case 'b': flag |= NV_BINARY; @@ -238,25 +274,19 @@ flag |= NV_TYPE; tdata.prefix = opt_info.arg; break; - case 'L': + case 'L': case 'Z': case 'R': if(tdata.argnum==0) tdata.argnum = (int)opt_info.num; if(tdata.argnum < 0) errormsg(SH_DICT,ERROR_exit(1), e_badfield, tdata.argnum); - flag &= ~NV_RJUST; - flag |= NV_LJUST; + if(n=='Z') + flag |= NV_ZFILL; + else + { + flag &= ~(NV_LJUST|NV_RJUST); + flag |= (n=='L'?NV_LJUST:NV_RJUST); + } break; - case 'Z': - flag |= NV_ZFILL; - /* FALL THRU*/ - case 'R': - if(tdata.argnum==0) - tdata.argnum = (int)opt_info.num; - if(tdata.argnum < 0) - errormsg(SH_DICT,ERROR_exit(1), e_badfield, tdata.argnum); - flag &= ~NV_LJUST; - flag |= NV_RJUST; - break; case 'f': flag &= ~(NV_VARNAME|NV_ASSIGN); troot = tdata.sh->fun_tree; @@ -275,6 +305,14 @@ case 'r': flag |= NV_RDONLY; break; +#ifdef SHOPT_TYPEDEF + case 'S': + sflag=1; + break; + case 'h': + tdata.help = opt_info.arg; + break; +#endif /*SHOPT_TYPEDEF*/ case 's': shortint=1; break; @@ -299,6 +337,7 @@ if(tdata.aflag==0) tdata.aflag = *opt_info.option; } +endargs: argv += opt_info.index; opt_info.disc = 0; /* handle argument of + and - specially */ @@ -306,6 +345,8 @@ tdata.aflag = *argv[0]; else argv--; + if((flag&NV_ZFILL) && !(flag&NV_LJUST)) + flag |= NV_RJUST; if((flag&NV_INTEGER) && (flag&(NV_LJUST|NV_RJUST|NV_ZFILL))) error_info.errors++; if((flag&NV_BINARY) && (flag&(NV_LJUST|NV_UTOL|NV_LTOU))) @@ -315,27 +356,37 @@ if(error_info.errors) errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*))); if(isfloat) - flag |= NV_INTEGER|NV_DOUBLE; + flag |= NV_DOUBLE; if(shortint) flag |= NV_SHORT|NV_INTEGER; + if(sflag) + { + if(tdata.sh->mktype) + flag |= NV_REF|NV_TAGGED; + else + flag |= NV_STATIC|NV_IDENT; + } if(tdata.sh->fn_depth) flag |= NV_NOSCOPE; if(flag&NV_TYPE) { - int offset = staktell(); - stakputs(NV_CLASS); + Stk_t *stkp = tdata.sh->stk; + int offset = stktell(stkp); + sfputr(stkp,NV_CLASS,-1); if(NV_CLASS[sizeof(NV_CLASS)-2]!='.') - stakputc('.'); - stakputs(tdata.prefix); - stakputc(0); - tdata.tp = nv_open(stakptr(offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN); - stakseek(offset); + sfputc(stkp,'.'); + sfputr(stkp,tdata.prefix,0); + tdata.tp = nv_open(stkptr(stkp,offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN); + stkseek(stkp,offset); if(!tdata.tp) errormsg(SH_DICT,ERROR_exit(1),"%s: unknown type",tdata.prefix); + tdata.tp->nvenv = tdata.help; flag &= ~NV_TYPE; } - else if(tdata.aflag==0 && ntp->np) + else if(tdata.aflag==0 && ntp && ntp->tp) tdata.aflag = '-'; + if(!tdata.sh->mktype) + tdata.help = 0; return(b_common(argv,flag,troot,&tdata)); } @@ -343,14 +394,14 @@ { register char *name; char *last = 0; - int nvflags=(flag&(NV_ARRAY|NV_NOARRAY|NV_VARNAME|NV_IDENT|NV_ASSIGN)); - int r=0, ref=0; + int nvflags=(flag&(NV_ARRAY|NV_NOARRAY|NV_VARNAME|NV_IDENT|NV_ASSIGN|NV_STATIC)); + int r=0, ref=0, comvar=(flag&NV_COMVAR),iarray=(flag&NV_IARRAY); Shell_t *shp =tp->sh; - if(!sh.prefix) + if(!shp->prefix) nvflags |= NV_NOSCOPE; - else if(*sh.prefix==0) - sh.prefix = 0; - flag &= ~(NV_NOARRAY|NV_NOSCOPE|NV_VARNAME|NV_IDENT); + else if(*shp->prefix==0) + shp->prefix = 0; + flag &= ~(NV_NOARRAY|NV_NOSCOPE|NV_VARNAME|NV_IDENT|NV_STATIC|NV_COMVAR|NV_IARRAY); if(argv[1]) { if(flag&NV_REF) @@ -377,10 +428,10 @@ /* Function names cannot be special builtin */ if((np=nv_search(name,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC)) errormsg(SH_DICT,ERROR_exit(1),e_badfun,name); - np = nv_open(name,shp->fun_tree,NV_NOARRAY|NV_IDENT|NV_NOSCOPE); + np = nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE); } - else - np = nv_search(name,shp->fun_tree,HASH_NOSCOPE); + else if((np=nv_search(name,troot,0)) && !is_afunction(np)) + np = 0; if(np && ((flag&NV_LTOU) || !nv_isnull(np) || nv_isattr(np,NV_LTOU))) { if(flag==0) @@ -397,20 +448,25 @@ } else r++; + if(tp->help) + { + int offset = stktell(shp->stk); + sfputr(shp->stk,shp->prefix,'.'); + sfputr(shp->stk,name,0); + if((np=nv_search(stkptr(shp->stk,offset),troot,0)) && np->nvalue.cp) + np->nvalue.rp->help = tp->help; + stkseek(shp->stk,offset); + } continue; } - np = nv_open(name,troot,nvflags); /* tracked alias */ if(troot==shp->track_tree && tp->aflag=='-') { -#ifdef PATH_BFPATH + np = nv_search(name,troot,NV_ADD); path_alias(np,path_absolute(nv_name(np),NIL(Pathcomp_t*))); -#else - nv_onattr(np,NV_NOALIAS); - path_alias(np,path_absolute(nv_name(np),NIL(char*))); -#endif continue; } + np = nv_open(name,troot,nvflags); if(flag==NV_ASSIGN && !ref && tp->aflag!='-' && !strchr(name,'=')) { if(troot!=shp->var_tree && (nv_isnull(np) || !print_namval(sfstdout,np,0,tp))) @@ -418,23 +474,33 @@ sfprintf(sfstderr,sh_translate(e_noalias),name); r++; } - continue; + if(!comvar && !iarray) + continue; } - if(tp->tp) + if(troot==shp->var_tree && ((tp->tp && !nv_isarray(np)) || !shp->st.real_fun && (nvflags&NV_STATIC)) && (!shp->envlist || !nv_onlist(shp->envlist,name))) + _nv_unset(np,0); + if((troot==shp->var_tree) && comvar) { - nv_settype(np,tp->tp,tp->aflag=='-'?0:NV_APPEND); - flag = (np->nvflag&NV_NOCHANGE); + if(!nv_isnull(np) && !nv_isvtree(np)) + nv_unset(np); + nv_setvtree(np); } - if(troot==shp->var_tree && (flag&NV_IARRAY)) + if((troot==shp->var_tree) && iarray) { - flag &= ~NV_IARRAY; - if(nv_isnull(np)) + if(tp->tname) + nv_atypeindex(np,tp->tname+1); + else if(nv_isnull(np)) nv_onattr(np,NV_ARRAY); else nv_putsub(np, (char*)0, 0); } if(troot==shp->var_tree && (nvflags&NV_ARRAY)) nv_setarray(np,nv_associative); + if(tp->tp) + { + nv_settype(np,tp->tp,tp->aflag=='-'?0:NV_APPEND); + flag = (np->nvflag&NV_NOCHANGE); + } curflag = np->nvflag; flag &= ~NV_ASSIGN; if(last=strchr(name,'=')) @@ -459,10 +525,13 @@ else if(!(flag&NV_LJUST)) newflag &= ~NV_LJUST; } - if (flag & NV_UTOL) - newflag &= ~NV_LTOU; - else if (flag & NV_LTOU) - newflag &= ~NV_UTOL; + if(!(flag&NV_INTEGER)) + { + if (flag & NV_UTOL) + newflag &= ~NV_LTOU; + else if (flag & NV_LTOU) + newflag &= ~NV_UTOL; + } } else { @@ -479,6 +548,7 @@ else { char *oldname=0; + int len=strlen(name); if(tp->argnum==1 && newflag==NV_INTEGER && nv_isattr(np,NV_INTEGER)) tp->argnum = 10; /* use reference name for export */ @@ -487,11 +557,18 @@ oldname = np->nvname; np->nvname = name; } + if(np->nvfun && !nv_isarray(np) && name[len-1]=='.') + newflag |= NV_NODISC; nv_newattr (np, newflag&~NV_ASSIGN,tp->argnum); if(oldname) np->nvname = oldname; } } + if(tp->help && !nv_isattr(np,NV_MINIMAL|NV_EXPORT)) + { + np->nvenv = tp->help; + nv_onattr(np,NV_EXPORT); + } if(last) *last = '='; /* set or unset references */ @@ -505,7 +582,10 @@ if(!(hp=(Dt_t*)shp->st.prevst->save_tree)) hp = dtvnext(shp->var_tree); } - nv_setref(np,hp,NV_VARNAME); + if(tp->sh->mktype) + nv_onattr(np,NV_REF|NV_FUNCT); + else + nv_setref(np,hp,NV_VARNAME); } else nv_unref(np); @@ -513,7 +593,7 @@ nv_close(np); } } - else if(!sh.envlist) + else if(!tp->sh->envlist) { if(tp->aflag) { @@ -523,7 +603,11 @@ tp->prefix = 0; } else if(troot==shp->var_tree) + { flag |= (nvflags&NV_ARRAY); + if(flag&NV_IARRAY) + flag |= NV_ARRAY; + } print_scan(sfstdout,flag,troot,tp->aflag=='+',tp); } else if(troot==shp->alias_tree) @@ -535,14 +619,15 @@ return(r); } -typedef void (*Iptr_t)(int); +typedef void (*Iptr_t)(int,void*); typedef int (*Fptr_t)(int, char*[], void*); #define GROWLIB 4 -static void** liblist; -static int nlib; -static int maxlib; +static void **liblist; +static unsigned short *libattr; +static int nlib; +static int maxlib; /* * This allows external routines to load from the same library */ @@ -562,26 +647,38 @@ register int n; register int r; Iptr_t initfn; + Shbltin_t *sp = &sh.bltindata; + sp->nosfio = 0; for (n = r = 0; n < nlib; n++) { if (r) + { liblist[n-1] = liblist[n]; + libattr[n-1] = libattr[n]; + } else if (liblist[n] == library) r++; } if (r) nlib--; else if ((initfn = (Iptr_t)dlllook(library, "lib_init"))) - (*initfn)(0); + (*initfn)(0,sp); if (nlib >= maxlib) { maxlib += GROWLIB; if (liblist) + { liblist = (void**)realloc((void*)liblist, (maxlib+1)*sizeof(void**)); + libattr = (unsigned short*)realloc((void*)liblist, (maxlib+1)*sizeof(unsigned short*)); + } else + { liblist = (void**)malloc((maxlib+1)*sizeof(void**)); + libattr = (unsigned short*)malloc((maxlib+1)*sizeof(unsigned short*)); + } } + libattr[nlib] = (sp->nosfio?BLT_NOSFIO:0); liblist[nlib++] = library; liblist[nlib] = 0; return !r; @@ -599,10 +696,13 @@ long dlete=0; struct tdata tdata; Fptr_t addr; + Stk_t *stkp; void *library=0; char *errmsg; NOT_USED(argc); - tdata.sh = (Shell_t*)extra; + memset(&tdata,0,sizeof(tdata)); + tdata.sh = ((Shbltin_t*)extra)->shp; + stkp = tdata.sh->stk; while (n = optget(argv,sh_optbuiltin)) switch (n) { case 's': @@ -661,23 +761,25 @@ return(0); } r = 0; - flag = staktell(); + flag = stktell(stkp); while(arg = *argv) { name = path_basename(arg); - stakputs("b_"); - stakputs(name); + sfwrite(stkp,"b_",2); + sfputr(stkp,name,0); errmsg = 0; addr = 0; for(n=(nlib?nlib:dlete); --n>=0;) { /* (char*) added for some sgi-mips compilers */ - if(dlete || (addr = (Fptr_t)dlllook(liblist[n],stakptr(flag)))) + if(dlete || (addr = (Fptr_t)dlllook(liblist[n],stkptr(stkp,flag)))) { if(np = sh_addbuiltin(arg, addr,pointerof(dlete))) { if(dlete || nv_isattr(np,BLT_SPC)) errmsg = "restricted name"; + else + nv_onattr(np,libattr[n]); } break; } @@ -695,7 +797,7 @@ errormsg(SH_DICT,ERROR_exit(0),"%s: %s",*argv,errmsg); r = 1; } - stakseek(flag); + stkseek(stkp,flag); argv++; } return(r); @@ -705,11 +807,11 @@ { struct tdata tdata; memset(&tdata,0,sizeof(tdata)); - tdata.sh = (Shell_t*)extra; + tdata.sh = ((Shbltin_t*)extra)->shp; tdata.prefix=0; if(argv[1]) { - if(sh_argopts(argc,argv) < 0) + if(sh_argopts(argc,argv,tdata.sh) < 0) return(2); if(sh_isoption(SH_VERBOSE)) sh_onstate(SH_VERBOSE); @@ -735,13 +837,13 @@ int b_unalias(int argc,register char *argv[],void *extra) { - Shell_t *shp = (Shell_t*)extra; + Shell_t *shp = ((Shbltin_t*)extra)->shp; return(b_unall(argc,argv,shp->alias_tree,shp)); } int b_unset(int argc,register char *argv[],void *extra) { - Shell_t *shp = (Shell_t*)extra; + Shell_t *shp = ((Shbltin_t*)extra)->shp; return(b_unall(argc,argv,shp->var_tree,shp)); } @@ -750,6 +852,7 @@ register Namval_t *np; register const char *name; register int r; + Dt_t *dp; int nflag=0,all=0,isfun; NOT_USED(argc); if(troot==shp->alias_tree) @@ -763,7 +866,7 @@ while(r = optget(argv,name)) switch(r) { case 'f': - troot = sh_subfuntree(0); + troot = sh_subfuntree(1); break; case 'a': all=1; @@ -794,7 +897,7 @@ dtclear(troot); else while(name = *argv++) { - if(np=nv_open(name,troot,NV_NOADD|nflag)) + if(np=nv_open(name,troot,NV_NOADD|NV_NOFAIL|nflag)) { if(is_abuiltin(np)) { @@ -802,11 +905,22 @@ continue; } isfun = is_afunction(np); - if(shp->subshell && troot==shp->var_tree) - np=sh_assignok(np,0); + if(troot==shp->var_tree) + { + if(nv_isarray(np) && name[strlen(name)-1]==']' && !nv_getsub(np)) + { + r=1; + continue; + } + + if(shp->subshell) + np=sh_assignok(np,0); + } nv_unset(np); nv_close(np); - if(isfun) + if(troot==shp->var_tree && shp->st.real_fun && (dp=shp->var_tree->walk) && dp==shp->st.real_fun->sdict) + dtdelete(dp,np); + else if(isfun) dtdelete(troot,np); } else @@ -825,7 +939,7 @@ sh_sigcheck(); if(flag) flag = '\n'; - if(nv_isattr(np,NV_NOPRINT)==NV_NOPRINT) + if(nv_isattr(np,NV_NOPRINT|NV_INTEGER)==NV_NOPRINT) { if(is_abuiltin(np)) sfputr(file,nv_name(np),'\n'); @@ -893,7 +1007,11 @@ sfprintf(file,"[%s]\n", sh_fmtq(nv_refsub(np))); } else +#if SHOPT_TYPEDEF + sfputr(file,nv_isvtree(np)?cp:sh_fmtq(cp),'\n'); +#else sfputr(file,sh_fmtq(cp),'\n'); +#endif /* SHOPT_TYPEDEF */ } return(1); } @@ -931,16 +1049,20 @@ register Namval_t *np; register int namec; Namval_t *onp = 0; - sh.last_table=0; + tp->sh->last_table=0; flag &= ~NV_ASSIGN; tp->scanmask = flag&~NV_NOSCOPE; tp->scanroot = root; tp->outfile = file; +#if SHOPT_TYPEDEF + if(!tp->prefix && tp->tp) + tp->prefix = nv_name(tp->tp); +#endif /* SHOPT_TYPEDEF */ if(flag&NV_INTEGER) tp->scanmask |= (NV_DOUBLE|NV_EXPNOTE); namec = nv_scan(root,nullscan,(void*)tp,tp->scanmask,flag); - argv = tp->argnam = (char**)stakalloc((namec+1)*sizeof(char*)); - namec = nv_scan(root, pushname, (void*)tp, tp->scanmask, flag); + argv = tp->argnam = (char**)stkalloc(tp->sh->stk,(namec+1)*sizeof(char*)); + namec = nv_scan(root, pushname, (void*)tp, tp->scanmask, flag&~NV_IARRAY); if(mbcoll()) strsort(argv,namec,strcoll); while(namec--) @@ -948,8 +1070,17 @@ if((np=nv_search(*argv++,root,0)) && np!=onp && (!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))) { onp = np; - if((flag&NV_ARRAY) && nv_aindex(np)>=0) - continue; + if(flag&NV_ARRAY) + { + if(nv_aindex(np)>=0) + { + if(!(flag&NV_IARRAY)) + continue; + } + else if((flag&NV_IARRAY)) + continue; + + } if(!flag && nv_isattr(np,NV_ARRAY)) { if(array_elem(nv_arrayptr(np))==0) Index: src/lib/libshell/common/nval.3 =================================================================== --- src/lib/libshell/common/nval.3 (revision 974) +++ src/lib/libshell/common/nval.3 (revision 1122) @@ -28,6 +28,7 @@ .ft 5 Namval_t *nv_open(const char *\fIname\fP, Dt_t *\fIdict\fP, int \fIflags\fP); Namval_t *nv_create(const char *\fIname\fP, Dt_t *\fIdict\fP, int \fIflags\fP, Namfun_t *\fIfp\fP); +Namval_t *nv_namptr(void *\fIptr\fP, int \fIindx\fP); void nv_close(Namval_t *\fInp\fP); .ft R .fi @@ -60,6 +61,7 @@ .ft 5 unsigned nv_isarray(Namval_t *\fInp\fP); Namarr_t *nv_setarray(Namval_t *\fInp\fP,void*(*\fIfun\fP)(Namval_t*,const char*,int)); +Namarr_t *nv_arrayptr(Namval_t *\fInp\fP); Namval_t *nv_putsub(Namval_t *\fInp\fP, char *\fIname\fP, long \fImode\fP); Namval_t *nv_opensub(Namval_t *\fInp\fP); void nv_setvec(Namval_t *\fInp\fP, int \fIappend\fP, int \fIargc\fP, char *\fIargv\fP[]); @@ -81,11 +83,20 @@ const Namdisc_t *nv_discfun(int \fIwhich\fP); .ft R .fi +.SS "TYPES" +.nf +.ft 5 +Namval_t *nv_type(Namval_t *\fInp\fP); +int *nv_settype(Namval_t *\fInp\fP, Namval_t *\fItp\fP, int \fIflags\fP); +Namval_t *nv_mkinttype(char *\fIname\fP, size_t \fIsz\fP, int \fIus\fP, const char *\fIstr\fP, Namdisc_t *\fIdp\fP); +void nv_addtype(Namval_t *\fInp\fP, const char *\fIstr\fP, Optdisc_t* *\fIop\fP, size_t \fIsz\fP); +.ft R +.fi .SS "MISCELLANEOUS FUNCTIONS" .nf .ft 5 int nv_scan(Dt_t *\fIdict\fP, void(*\fIfn\fP)(Namval_t*,void*), void *\fIdata\fP, int \fImask\fP, int \fIflags\fP); -Dt_t nv_dict(Namval_t *\fInp\fP); +Dt_t *nv_dict(Namval_t *\fInp\fP); void nv_setvtree(Namval_t *\fInp\fP); void nv_setref(Namval_t *\fInp\fP, Dt_t *\fIdp\fP, int \fIflags\fP); Namval_t *nv_lastdict(void); @@ -179,6 +190,16 @@ name-value pair that contains the last dictionary searched on the previous \f5nv_open()\fP. .PP +Name-value pairs can also be allocated without belonging to +a dictionary. They will typically be looked by a a \fIcreate\fP +discipline associated with a parent node. In this case the +node size will by \f5NV_MINSZ\fP and \fIn\fP nodes can be allocated +vial \f5calloc(5NV_MINSZ,\fIn\fP)\fP(3). +The \f5nv_namptr\fP function can be used on the pointer returned by +\f5calloc\fP along with the element number to return the +corresponding node. +Each of these nodes must be given the \f5NV_MINIMAL\fP attributes. +.PP The \f5nv_close()\fP indicates that the pointer returned by \f5nv_open()\fP or \f5nv_opensub()\fP will not be referenced again. If the name-value pair is unset, and not referenced elsewhere, @@ -282,6 +303,11 @@ This attribute has an associated number that defines the the precision of the mantissa. .IP +\f5NV_HEXFLOAT\fP: +Used in conjunction with \f5NV_INTEGER\fP and \f5NV_DOUBLE\fP to +cause the value to be represented in C99 %a format when expanded as +a string. +.IP \f5NV_BINARY\fP: The name-value pair contains a buffer of binary data and \f5nv_size()\fP is the number of bytes for this data. By default the value @@ -292,6 +318,10 @@ \f5NV_REF\fP: The name-value pair is a name reference variable. .IP +\f5NV_MINIMAL\fP: +The name-value pair node is not embedded in a dictionary +and is minimal size, \f5NV_MINSZ\fP. +.IP \f5NV_NODISC\fP: All discipline functions are ignored when performing assignments and lookups. @@ -558,8 +588,17 @@ Returns a pointer to a name-value pair corresponding to the current subscript, or \f5NULL\fP if this array type doesn't create represent each element as a name-value pair. +.IP +\f5NV_ASETSUB\fP: +Set the current subscript to the name-value pair passed in +as the second argument. .PP If \fInp\fP refers to an array, +\f5nv_arrayptr()\fP returns a pointer to +the array discipline structure \f5Namarr_t\fP. +Otherwise \f5nv_arrayptr()\fP returns \f5NULL\fP. +.PP +If \fInp\fP refers to an array, the \f5nv_getsub()\fP returns a pointer to the name of the current subscript. Otherwise, \f5nv_getsub()\fP @@ -612,8 +651,31 @@ children nodes in a format that can be used in a shell compound assignment. .PP +The \f5nv_type()\fP function returns a name_value pair pointer +that contains the type definition for the specified name-value pair. +The \fInvname\fP field contains the name for the type. +.PP +The \f5nv_settype()\fP function converts the name-value pair +given by \fInp\fP into the type given by \fItp\fP. +.PP +The \f5nv_addtype()\fP function adds the name of the type given by +\fInp\fP to the list of declaration built-ins. The \fIstr\fP +argument contains the string used by \f5optget\fP(3) to generate +the man page and process the options. The \fIop\fP argument +specifies the callback discipline used by \f5optget\fP(3) and +\fIsz\fP specifies the size of the callback information so +that the discipline \fBoptget\fP(3) can be extended with private +data used by the callback function. +.P +The \f5nv_mkinttype()\fP function creates named integer types +of the specified \fIname\fP. The \fIsize\fP parameter is the size +in bytes of the integer variable and \fIus\fP is non-zero +for unsigned integer types. If \fIdp\fP is specified then integer +variables of this type will all use this discipline. .SH SEE ALSO +calloc(3) cdt(3) shell(3) +optget(3) .SH AUTHOR David G. Korn (dgk@research.att.com). Index: src/lib/libshell/common/tests/sun_solaris_getconf.sh =================================================================== --- src/lib/libshell/common/tests/sun_solaris_getconf.sh (revision 974) +++ src/lib/libshell/common/tests/sun_solaris_getconf.sh (revision 1122) @@ -1,4 +1,4 @@ -#!/bin/ksh93 +#!/usr/bin/ksh93 # # CDDL HEADER START @@ -22,10 +22,10 @@ # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "@(#)sun_solaris_getconf.sh 1.1 07/07/17 SMI" +# ident "%Z%%M% %I% %E% SMI" # # @@ -38,7 +38,7 @@ { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - let Errors+=1 + (( Errors++ )) } alias err_exit='err_exit $LINENO' @@ -52,24 +52,29 @@ export PATH=/usr/bin:/bin # prechecks -[ ! -f "/bin/getconf" ] && err_exit '/bin/getconf not found.' -[ ! -x "/bin/getconf" ] && err_exit '/bin/getconf not executable.' +[[ ! -f "/bin/getconf" ]] && err_exit '/bin/getconf not found.' +[[ ! -x "/bin/getconf" ]] && err_exit '/bin/getconf not executable.' +# Define test functions and store them in a string for repeated usagae +# (we can't use "functions" (alias "typeset -f") since this does not +# work in compiled shell scripts) +typeset -r getconf_test_functions="$( +cat <<EOF # compare builtin getconf output with /usr/bin/getconf function compare_normal { mismach=0 getconf_keys=0 /usr/bin/getconf -a | while read i ; do - let getconf_keys++ + (( getconf_keys++ )) t="${i%:*}" a="$(getconf "$t" 2>/dev/null)" b="$(/usr/bin/getconf "$t" 2>/dev/null)" - if [ "$a" != "$b" ] ; then + if [[ "$a" != "$b" ]] ; then print -u2 "getconf/normal built mismatch: |$t|:|$a| != |$b|" - let mismatch++ + (( mismatch++ )) fi done } @@ -80,49 +85,54 @@ mismach=0 getconf_keys=0 /usr/bin/getconf -a | while read i ; do - let getconf_keys++ + (( getconf_keys++ )) t="${i%:*}" a="$(getconf "$t" "/tmp" 2>/dev/null)" b="$(/usr/bin/getconf "$t" "/tmp" 2>/dev/null)" - if [ "$a" != "$b" ] ; then + if [[ "$a" != "$b" ]] ; then print -u2 "getconf/path built mismatch: |$t|:|$a| != |$b|" - let mismatch++ + (( mismatch++ )) fi done } +EOF +)" +print -r -- "$getconf_test_functions" | source /dev/stdin + # future versions of this test should test the following ${PATH}s, too: # "/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin" \ #"/usr/xpg4/bin:/bin:/usr/bin" \ for i in \ + "/usr/bin:/bin" \ "/bin:/usr/bin" do export PATH="${i}" ## test whether the getconf builtin is available - if [ "$(builtin | fgrep "/bin/getconf")" = "" ] ; then + if [[ "$(builtin | fgrep "/bin/getconf")" = "" ]] ; then err_exit '/bin/getconf not found in the list of builtins.' fi ## compare "getconf -a" output - if [ "$(getconf -a)" != "$(/usr/bin/getconf -a)" ] ; then + if [[ "$(getconf -a)" != "$(/usr/bin/getconf -a)" ]] ; then err_exit 'getconf -a output mismatch.' fi ## check for a key which is only supported by the AST builtin version of getconf: - if [ "$(getconf LIBPREFIX)" != "lib" ] ; then + if [[ "$(getconf LIBPREFIX)" != "lib" ]] ; then err_exit 'getconf LIBPREFIX did not return "lib".' fi ## run normal test compare_normal - [ ${getconf_keys} -eq 0 ] && err_exit "getconf/normal not working (PATH=${PATH})." - [ ${mismatch} -gt 0 ] && err_exit "getconf/normal test found ${mismatch} differences (PATH=${PATH})." + (( getconf_keys == 0 )) && err_exit "getconf/normal not working (PATH=${PATH})." + (( mismatch > 0 )) && err_exit "getconf/normal test found ${mismatch} differences (PATH=${PATH})." # run the same test in a seperate shell # (we explicitly test this because ast-ksh.2007-01-11 picks up /usr/xpg6/bin/getconf @@ -130,31 +140,30 @@ # contains /usr/xpg6/bin before ksh93 is started)). ${SHELL} -c "integer mismatch ; \ integer getconf_keys ; \ - $(functions) ; \ + ${getconf_test_functions} ; \ compare_normal ; - [ \${getconf_keys} -eq 0 ] && err_exit \"getconf/normal not working (PATH=\${PATH}).\" ; \ - [ \${mismatch} -gt 0 ] && err_exit \"getconf/normal test found \${mismatch} differences (PATH=\${PATH}).\" ; \ + (( getconf_keys == 0 )) && err_exit \"getconf/normal not working (PATH=\${PATH}).\" ; \ + (( mismatch > 0 )) && err_exit \"getconf/normal test found \${mismatch} differences (PATH=\${PATH}).\" ; \ exit $((Errors))" - let Errors+=$? + (( Errors+=$? )) ## run test with path argument compare_path - [ ${getconf_keys} -eq 0 ] && err_exit "getconf/path not working." - [ ${mismatch} -gt 0 ] && err_exit "getconf/path test found ${mismatch} differences." + (( getconf_keys == 0 )) && err_exit "getconf/path not working." + (( mismatch > 0 )) && err_exit "getconf/path test found ${mismatch} differences." # run the same test in a seperate shell # (see comment above) ${SHELL} -c "integer mismatch ; \ integer getconf_keys ; \ - $(functions) ; \ + ${getconf_test_functions} ; \ compare_path ; - [ \${getconf_keys} -eq 0 ] && err_exit \"getconf/normal not working (PATH=\${PATH}).\" ; \ - [ \${mismatch} -gt 0 ] && err_exit \"getconf/normal test found \${mismatch} differences (PATH=\${PATH}).\" ; \ + (( getconf_keys == 0 )) && err_exit \"getconf/normal not working (PATH=\${PATH}).\" ; \ + (( mismatch > 0 )) && err_exit \"getconf/normal test found \${mismatch} differences (PATH=\${PATH}).\" ; \ exit $((Errors))" - let Errors+=$? + (( Errors+=$? )) done # test done exit $((Errors)) - Index: src/lib/libshell/common/tests/append.sh =================================================================== --- src/lib/libshell/common/tests/append.sh (revision 974) +++ src/lib/libshell/common/tests/append.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -63,10 +63,18 @@ if [[ ${point.y} != 3 ]] then err_exit 'compound append fails' fi +if [[ ${point.x} != 1 ]] +then err_exit 'compound append to compound variable unsets existing variables' +fi unset foo foo=one foo+=(two) if [[ ${foo[@]} != 'one two' ]] then err_exit 'array append to non array variable fails' fi +unset foo +foo[0]=(x=3) +foo+=(x=4) +[[ ${foo[1].x} == 4 ]] || err_exit 'compound append to index array not working' +[[ ${foo[0].x} == 3 ]] || err_exit 'compound append to index array unsets existing variables' exit $((Errors)) Index: src/lib/libshell/common/tests/arith.sh =================================================================== --- src/lib/libshell/common/tests/arith.sh (revision 974) +++ src/lib/libshell/common/tests/arith.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -308,7 +308,6 @@ then err_exit 'display of unsigned integers in non-decimal bases wrong' fi $SHELL -c 'i=0;(( ofiles[i] != -1 && (ofiles[i] < mins || mins == -1) ));exit 0' 2> /dev/null || err_exit 'lexical error with arithemtic expression' -rm -f core $SHELL -c '(( +1 == 1))' 2> /dev/null || err_exit 'unary + not working' typeset -E20 val=123.01234567890 [[ $val == 123.0123456789 ]] || err_exit "rounding error val=$val" @@ -328,7 +327,7 @@ done (( x == n )) || err_exit 'let with zero filled fields not working' (( y == n )) || err_exit '((...)) with zero filled fields not working' -typeset -LZ3 x=10 +typeset -RZ3 x=10 [[ $(($x)) == 10 && $((1$x)) == 1010 ]] || err_exit 'zero filled fields not preserving leading zeros' unset y [[ $(let y=$x;print $y) == 10 && $(let y=1$x;print $y) == 1010 ]] || err_exit 'zero filled fields not preserving leading zeros with let' @@ -357,7 +356,7 @@ (( ${x:0:1} == 0 )) || err_exit 'leading zero should not be stripped for x:a:b' c010=3 (( c$x == 3 )) || err_exit 'leading zero with variable should not be stripped' -[[ $( ($SHELL -c '((++1))' 2>&1)2>/dev/null ) == *lvalue* ]] || err_exit "((--1)) not generating error message" +[[ $( ($SHELL -c '((++1))' 2>&1)2>/dev/null ) == *lvalue* ]] || err_exit "((++1)) not generating error message" i=2 (( "22" == 22 )) || err_exit "double quoted constants fail" (( "2$i" == 22 )) || err_exit "double quoted variables fail" @@ -442,20 +441,30 @@ [[ $x == "$((x))" ]] || err_exit '$x !- $((x)) when x is pi' $SHELL -c "[[ ${x//./} == {14,100}(\d) ]]" 2> /dev/null || err_exit 'pi has less than 14 significant places' if (( Inf+1 == Inf )) -then [[ $(printf "%g\n" $((Inf))) == inf ]] || err_exit 'printf "%g\n" $((Inf)) fails' -# [[ $(printf "%g\n" $((Nan))) == inf ]] || err_exit 'printf "%g\n" $((Nan)) fails' - [[ $(printf "%g\n" Inf) == inf ]] || err_exit 'printf "%g\n" Inf fails' - [[ $(printf "%g\n" NaN) == nan ]] || err_exit 'printf "%g\n" NaN fails' - [[ $(print -- $((Inf))) == inf ]] || err_exit 'print -- $((Inf)) fails' +then set \ + Inf inf \ + -Inf -inf \ + Nan nan \ + -Nan -nan \ + 1.0/0.0 inf + while (( $# >= 2 )) + do x=$(printf "%g\n" $(($1))) + [[ $x == $2 ]] || err_exit "printf '%g\\n' \$(($1)) failed -- got $x, expected $2" + x=$(printf "%g\n" $1) + [[ $x == $2 ]] || err_exit "printf '%g\\n' $1 failed -- got $x, expected $2" + x=$(printf -- $(($1))) + [[ $x == $2 ]] || err_exit "print -- \$(($1)) failed -- got $x, expected $2" + shift 2 + done (( 1.0/0.0 == Inf )) || err_exit '1.0/0.0 != Inf' - [[ $(print -- $((0.0/0.0))) == nan ]] || err_exit '0.0/0.0 != NaN' + [[ $(print -- $((0.0/0.0))) == ?(-)nan ]] || err_exit '0.0/0.0 != NaN' (( Inf*Inf == Inf )) || err_exit 'Inf*Inf != Inf' (( NaN != NaN )) || err_exit 'NaN == NaN' (( -5*Inf == -Inf )) || err_exit '-5*Inf != -Inf' - [[ $(print -- $((sqrt(-1.0)))) == nan ]]|| err_exit 'sqrt(-1.0) != NaN' + [[ $(print -- $((sqrt(-1.0)))) == ?(-)nan ]]|| err_exit 'sqrt(-1.0) != NaN' (( pow(1.0,Inf) == 1.0 )) || err_exit 'pow(1.0,Inf) != 1.0' (( pow(Inf,0.0) == 1.0 )) || err_exit 'pow(Inf,0.0) != 1.0' - [[ $(print -- $((NaN/Inf))) == nan ]] || err_exit 'NaN/Inf != NaN' + [[ $(print -- $((NaN/Inf))) == ?(-)nan ]] || err_exit 'NaN/Inf != NaN' (( 4.0/Inf == 0.0 )) || err_exit '4.0/Inf != 0.0' else err_exit 'Inf and NaN not working' fi @@ -463,4 +472,12 @@ float x=14.555 y y=$(printf "%a" x) (( x == y )) || err_exit "output of printf %a not self preserving -- expected $x, got $y" +unset x y r +x=-0 +y=$(printf "%g %g %g %g %g %g\n" -0. -0 $((-0)) x $x $((x))) +r="-0 -0 -0 -0 -0 -0" +[[ $y == "$r" ]] || err_exit "-0 vs -0.0 inconsistency -- expected '$r', got '$y'" +$SHELL -c '(( x=));:' 2> /dev/null && err_exit '((x=)) should be an error' +$SHELL -c '(( x+=));:' 2> /dev/null && err_exit '((x+=)) should be an error' +$SHELL -c '(( x=+));:' 2> /dev/null && err_exit '((x=+)) should be an error' exit $((Errors)) Index: src/lib/libshell/common/tests/quoting2.sh =================================================================== --- src/lib/libshell/common/tests/quoting2.sh (revision 974) +++ src/lib/libshell/common/tests/quoting2.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -197,4 +197,11 @@ [[ "$" == '$' ]] || err_exit '"$" != $' [[ "${foo}$" == 'foo$' ]] || err_exit 'foo=foo;"${foo}$" != foo$' [[ "${foo}${foo}$" == 'foofoo$' ]] || err_exit 'foo=foo;"${foo}${foo}$" != foofoo$' +foo='$ ' +[[ "$foo" == ~(Elr)(\\\$|#)\ ]] || err_exit $'\'$ \' not matching RE \\\\\\$|#\'' +[[ "$foo" == ~(Elr)('\$'|#)\ ]] || err_exit $'\'$ \' not matching RE \'\\$\'|#\'' +foo='# ' +[[ "$foo" == ~(Elr)(\\\$|#)\ ]] || err_exit $'\'# \' not matching RE \\'\$|#\'' +[[ "$foo" == ~(Elr)('\$'|#)\ ]] || err_exit $'\'# \' not matching RE \'\\$\'|#\'' +[[ '\$' == '\$'* ]] || err_exit $'\'\\$\' not matching \'\\$\'*' exit $((Errors)) Index: src/lib/libshell/common/tests/functions.sh =================================================================== --- src/lib/libshell/common/tests/functions.sh (revision 974) +++ src/lib/libshell/common/tests/functions.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -27,6 +27,14 @@ integer Errors=0 Command=${0##*/} + +tmp=/tmp/kshtf$$ +function cleanup +{ + rm -rf $tmp +} +mkdir $tmp || err_exit "mkdir $tmp failed" + integer foo=33 bar=bye # check for global variables and $0 @@ -81,11 +89,11 @@ { (return 0) } -> /tmp/shtests$$.1 +> $tmp/shtests$$.1 { foobar -if [ -r /tmp/shtests$$.1 ] -then rm -r /tmp/shtests$$.1 +if [ -r $tmp/shtests$$.1 ] +then rm -r $tmp/shtests$$.1 else err_exit 'return within subshell inside function error' fi } @@ -111,7 +119,7 @@ x=2 ( x=3 - cd /tmp + cd $tmp print bar ) if [[ $x != 2 ]] @@ -130,19 +138,19 @@ if [[ $(fun) != hello ]] then err_exit one line functions not working fi -trap 'rm -f /tmp/script$$ /tmp/data$$.[12]' EXIT -cat > /tmp/script$$ <<-\! +trap cleanup EXIT +cat > $tmp/script$$ <<-\! print -r -- "$1" ! -chmod +x /tmp/script$$ +chmod +x $tmp/script$$ function passargs { - /tmp/script$$ "$@" + $tmp/script$$ "$@" } if [[ $(passargs one) != one ]] then err_exit 'passing args from functions to scripts not working' fi -cat > /tmp/script$$ <<-\! +cat > $tmp/script$$ <<-\! trap 'exit 0' EXIT function foo { @@ -150,17 +158,17 @@ } foo ! -if ! /tmp/script$$ +if ! $tmp/script$$ then err_exit 'exit trap incorrectly triggered' fi -if ! $SHELL -c /tmp/script$$ +if ! $SHELL -c $tmp/script$$ then err_exit 'exit trap incorrectly triggered when invoked with -c' fi -$SHELL -c "trap 'rm /tmp/script$$' EXIT" -if [[ -f /tmp/script$$ ]] +$SHELL -c "trap 'rm $tmp/script$$' EXIT" +if [[ -f $tmp/script$$ ]] then err_exit 'exit trap not triggered when invoked with -c' fi -cat > /tmp/script$$ <<- \EOF +cat > $tmp/script$$ <<- \EOF foobar() { return @@ -169,8 +177,8 @@ foobar print -r -- "$1" EOF -chmod +x /tmp/script$$ -if [[ $( $SHELL /tmp/script$$ arg1 arg2) != arg2 ]] +chmod +x $tmp/script$$ +if [[ $( $SHELL $tmp/script$$ arg1 arg2) != arg2 ]] then err_exit 'arguments not restored by posix functions' fi function foo @@ -205,15 +213,15 @@ then err_exit 'variable assignment list not using parent scope' fi unset -f foo$$ -trap "rm -f /tmp/foo$$" EXIT INT -cat > /tmp/foo$$ <<! +#trap "rm -f $tmp/foo$$" EXIT INT +cat > $tmp/foo$$ <<! function foo$$ { print foo } ! -chmod +x /tmp/foo$$ -FPATH=/tmp +chmod +x $tmp/foo$$ +FPATH=$tmp autoload foo$$ if [[ $(foo$$ 2>/dev/null) != foo ]] then err_exit 'autoload not working' @@ -368,8 +376,8 @@ return $r } closure 0 || err_exit -u2 'for loop function optimization bug2' -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +mkdir $tmp/ksh$$ || err_exit "mkdir $tmp/ksh$$ failed" +cd $tmp/ksh$$ || err_exit "cd $tmp/ksh$$ failed" print 'false' > try chmod +x try cat > tst <<- EOF @@ -384,9 +392,9 @@ if [[ $($SHELL < tst) == error ]] then err_exit 'ERR trap not cleared' fi -FPATH=/tmp/ksh$$ -print ': This does nothing' > /tmp/ksh$$/foobar -chmod +x /tmp/ksh$$/foobar +FPATH=$tmp/ksh$$ +print ': This does nothing' > $tmp/ksh$$/foobar +chmod +x $tmp/ksh$$/foobar unset -f foobar { foobar;} 2> /dev/null if [[ $? != 126 ]] @@ -395,7 +403,7 @@ print 'set a b c' > dotscript [[ $(PATH=$PATH: $SHELL -c '. dotscript;print $#') == 3 ]] || err_exit 'positional parameters not preserved with . script without arguments' cd ~- || err_exit "cd back failed" -cd /; rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" +cd /; rm -r $tmp/ksh$$ || err_exit "rm -r $tmp/ksh$$ failed" function errcheck { trap 'print ERR; return 1' ERR @@ -423,7 +431,7 @@ b() { : ;} [[ $(a) == a ]] || err_exit '.sh.fun not set correctly in a function' print $'a(){\ndate\n}' | $SHELL 2> /dev/null || err_exit 'parser error in a(){;date;}' -cat > /tmp/data$$.1 << '++EOF' +cat > $tmp/data$$.1 << '++EOF' 1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 3 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -445,7 +453,7 @@ 19 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 20 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ++EOF -cat > /tmp/script$$ << '++EOF' +cat > $tmp/script$$ << '++EOF' # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -711,11 +719,10 @@ { cat <<\M ++EOF -cat /tmp/data$$.1 >> /tmp/script$$ -printf 'M\n}\n\nf\n\n' >> /tmp/script$$ -$SHELL -c /tmp/script$$ > /tmp/data$$.2 -cmp -s /tmp/data$$.[12] || err_exit 'error with long functions' -rm -f /tmp/script$$ /tmp/data$$.[12] +cat $tmp/data$$.1 >> $tmp/script$$ +printf 'M\n}\n\nf\n\n' >> $tmp/script$$ +$SHELL -c $tmp/script$$ > $tmp/data$$.2 +cmp -s $tmp/data$$.[12] || err_exit 'error with long functions' v=1 function f { @@ -755,4 +762,136 @@ done } [[ $(foo 'NUMBERED RECORDSIZE') == ok ]] || err_exit 'optimization error with undefined variable' +unset x +x=$( + set -e + integer count=0 + function err_f + { + if ((count++==3)) + then print failed + else false + fi + } + trap 'err_f' ERR + false +) +[[ $x == failed ]] && err_exit 'ERR trap executed multiple times' +trap cleanup EXIT +export environment +typeset global +function f +{ + typeset i t local + + for i + do case $i in + [-+]*) set "$@" + continue + ;; + local) local=f + t=$(typeset +f $local) + ;; + global) global=f + t=$(typeset +f $global) + ;; + environment) + environment=f + t=$(typeset +f $environment) + ;; + literal)t=$(typeset +f f) + ;; + positional) + set -- f + t=$(typeset +f $1) + ;; + esac + [[ $t ]] || err_exit "typeset +f \$$i failed" + done +} +f local global environment literal positional +$SHELL -c ' + print exit 0 > '$tmp'/script$$ + chmod +x '$tmp'/script$$ + unset var + var=( ident=1 ) + function fun + { + PATH='$tmp' script$$ + } + fun +' || err_exit "compound variable cleanup before script exec failed" +( $SHELL << \++EOF++ +function main +{ + typeset key + typeset -A entry + entry[a]=( value=aaa ) +} +main +++EOF++ +) 2> /dev/null || err_exit 'function main fails' +optind=$OPTIND +sub() +{ + ( + OPTIND=1 + while getopts :abc OPTION "$@" + do print OPTIND=$OPTIND + done + ) +} +[[ $(sub -a) == OPTIND=2 ]] || err_exit 'OPTIND should be 2' +[[ $(sub -a) == OPTIND=2 ]] || err_exit 'OPTIND should be 2 again' +[[ $OPTIND == "$optind" ]] || err_exit 'OPTIND should be 1' + +function bar +{ + [[ -o nounset ]] && err_exit 'nounset option should not be inherited' +} +function foo +{ + set -o nounset + bar +} +set +o nounset +foo +function red +{ + integer -S d=0 + printf 'red_one %d\n' d + (( d++ )) + return 0 +} +[[ ${ red } != 'red_one 0' ]] && err_exit 'expected red_one 0' +[[ ${ red } != 'red_one 1' ]] && err_exit 'expected red_one 1' +xyz=$0 +function traceback +{ + integer .level=.sh.level + while((--.level>=0)) + do + ((.sh.level = .level)) + [[ $xyz == "$0" ]] || err_exit "\$xyz=$xyz does not match $0 on level ${.level}" + [[ ${.sh.lineno} == "$1" ]] || err_exit "\${.sh.lineno}=${.sh.lineno} does not match $0 on level ${.level}" + done +} + +function foo +{ + typeset xyz=foo + set -- $((LINENO+1)) + bar $LINENO "$1" +} + +function bar +{ + typeset xyz=bar + set -- $((LINENO+2)) + trap 'traceback $LINENO' DEBUG + : $LINENO "$1" +} + +set -- $((LINENO+1)) +foo $LINENO exit $((Errors)) Index: src/lib/libshell/common/tests/bracket.sh =================================================================== --- src/lib/libshell/common/tests/bracket.sh (revision 974) +++ src/lib/libshell/common/tests/bracket.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -176,6 +176,8 @@ if [[ '!' != ! ]] then err_exit 'quoting unary operator not working' fi +test \( -n x \) -o \( -n y \) 2> /dev/null || err_exit 'test ( -n x ) -o ( -n y) not working' +test \( -n x \) -o -n y 2> /dev/null || err_exit 'test ( -n x ) -o -n y not working' chmod 600 $file exec 4> $file print -u4 foobar @@ -230,4 +232,9 @@ $SHELL -xc '[[ abc =~ \babc\b ]]' 2> /dev/null || err_exit '[[ abc =~ \babc\b ]] fails' [[ abc == ~(E)\babc\b ]] || err_exit '\b not preserved for ere when not in ()' [[ abc == ~(iEi)\babc\b ]] || err_exit '\b not preserved for ~(iEi) when not in ()' + +e=$($SHELL -c '[ -z "" -a -z "" ]' 2>&1) +[[ $e ]] && err_exit "[ ... ] compatibility check failed -- $e" +i=hell +[[ hell0 == $i[0] ]] || err_exit 'pattern $i[0] interpreded as array ref' exit $((Errors)) Index: src/lib/libshell/common/tests/case.sh =================================================================== --- src/lib/libshell/common/tests/case.sh (revision 974) +++ src/lib/libshell/common/tests/case.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # Index: src/lib/libshell/common/tests/sun_solaris_vartree002.sh =================================================================== --- src/lib/libshell/common/tests/sun_solaris_vartree002.sh (revision 0) +++ src/lib/libshell/common/tests/sun_solaris_vartree002.sh (revision 1122) @@ -0,0 +1,355 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# variable tree test #002 +# Purpose of this test is whether ksh93 handles global variable trees +# and function-local variable trees the same way, including "nameref" +# and "unset" handling. +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +integer Errors=0 + +# "built_tree1" and "built_tree2" are identical except the way how they test +# whether a variable exists: +# - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable +# as non-zero length content +# - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell +function build_tree1 +{ +#set -o errexit -o xtrace + typeset index + typeset s + typeset i + typeset dummy + typeset a b c d e f + + nameref dest_tree="$1" # destination tree + nameref srcdata="$2" # source data + typeset tree_mode="$3" # mode to define the type of leads + + typeset -A dest_tree.l1 + + for index in "${!srcdata.hashnodes[@]}" ; do + nameref node=srcdata.hashnodes["${index}"] + + for i in "${node.xlfd[@]}" ; do + IFS='-' read dummy a b c d e f <<<"$i" + + if [[ "$a" == "" ]] ; then + a="$dummy" + fi + + [[ "$a" == "" ]] && a='-' + [[ "$b" == "" ]] && b='-' + [[ "$c" == "" ]] && c='-' + + if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then + #if ! (unset dest_tree.l1["$a"]) ; then + typeset -A dest_tree.l1["$a"].l2 + fi + + if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then + #if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3 + fi + + if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries + fi + + typeset new_index + if [[ "${tree_mode}" == "leaf_name" ]] ; then + new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) + else + new_index="${node.name}" + + # skip if the leaf node already exists + if [[ "${dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}]}" != "" ]] ; then + continue + fi + fi + + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" + done + done + + return 0 +} + +# "built_tree1" and "built_tree2" are identical except the way how they test +# whether a variable exists: +# - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable +# as non-zero length content +# - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell +function build_tree2 +{ +#set -o errexit -o xtrace + typeset index + typeset s + typeset i + typeset dummy + typeset a b c d e f + + nameref dest_tree="$1" # destination tree + nameref srcdata="$2" # source data + typeset tree_mode="$3" # mode to define the type of leads + + typeset -A dest_tree.l1 + + for index in "${!srcdata.hashnodes[@]}" ; do + nameref node=srcdata.hashnodes["${index}"] + + for i in "${node.xlfd[@]}" ; do + IFS='-' read dummy a b c d e f <<<"$i" + + if [[ "$a" == "" ]] ; then + a="$dummy" + fi + + [[ "$a" == "" ]] && a='-' + [[ "$b" == "" ]] && b='-' + [[ "$c" == "" ]] && c='-' + + #if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then + if ! (unset dest_tree.l1["$a"]) ; then + typeset -A dest_tree.l1["$a"].l2 + fi + + #if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then + if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3 + fi + + if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries + fi + + typeset new_index + if [[ "${tree_mode}" == "leaf_name" ]] ; then + new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) + else + new_index="${node.name}" + + # skip if the leaf node already exists + if [[ "${dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}]}" != "" ]] ; then + continue + fi + fi + + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" + done + done + + return 0 +} + + +function add_tree_leaf +{ + nameref tree_leafnode="$1" + nameref data_node=srcdata.hashnodes["$2"] + typeset add_mode="$3" + + case "${add_mode}" in + "leaf_name") + tree_leafnode="${data_node.name}" + return 0 + ;; + "leaf_compound") + tree_leafnode=( + typeset name="${data_node.name}" + typeset -a filenames=( "${data_node.filenames[@]}" ) + typeset -a comments=( "${data_node.comments[@]}" ) + typeset -a xlfd=( "${data_node.xlfd[@]}" ) + ) + return 0 + ;; + *) + print -u2 -f "ERROR: Unknown mode %s in add_tree_leaf\n" "${add_mode}" + return 1 + ;; + esac + + # not reached + return 1 +} + +# "mysrcdata_local" and "mysrcdata_global" must be identical +typeset mysrcdata_global=( + typeset -A hashnodes=( + [abcd]=( + name='abcd' + typeset -a xlfd=( + '-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific' + ) + typeset -a comments=( + 'comment 1' + 'comment 2' + 'comment 3' + ) + typeset -a filenames=( + '/home/foo/abcd_1' + '/home/foo/abcd_2' + '/home/foo/abcd_3' + ) + ) + ) +) + +mytree_global1=() +mytree_global2=() + +function main +{ + # "mysrcdata_local" and "mysrcdata_global" must be identical + typeset mysrcdata_local=( + typeset -A hashnodes=( + [abcd]=( + name='abcd' + typeset -a xlfd=( + '-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific' + ) + typeset -a comments=( + 'comment 1' + 'comment 2' + 'comment 3' + ) + typeset -a filenames=( + '/home/foo/abcd_1' + '/home/foo/abcd_2' + '/home/foo/abcd_3' + ) + ) + ) + ) + + #### Build tree using global tree variables + build_tree1 mytree_global1 mysrcdata_global leaf_compound || \ + err_exit 'build_tree1 mytree_global1 mysrcdata_global leaf_compound returned an error' + (( $(print -r -- "${mytree_global1}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_global1' too small." + + build_tree2 mytree_global2 mysrcdata_global leaf_compound || \ + err_exit 'build_tree2 mytree_global2 mysrcdata_global leaf_compound returned an error' + (( $(print -r -- "${mytree_global2}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_global2' too small." + + + #### build tree using local tree variables + mytree_local1=() + mytree_local2=() + + build_tree1 mytree_local1 mysrcdata_local leaf_compound || \ + err_exit 'build_tree1 mytree_local1 mysrcdata_local leaf_compound returned an error' + (( $(print -r -- "${mytree_local1}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_local1' too small." + + build_tree2 mytree_local2 mysrcdata_local leaf_compound || \ + err_exit 'build_tree2 mytree_local2 mysrcdata_local leaf_compound returned an error' + (( $(print -r -- "${mytree_local2}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_local2' too small." + + + #### Compare treess + if [[ "${mytree_global1}" != "${mytree_local1}" ]] ; then + err_exit "Compound trees 'mytree_global1' and 'mytree_local1' not identical" + diff -u <( printf "%s\n" "${mytree_global1}" ) <( printf "%s\n" "${mytree_local1}" ) + fi + + if [[ "${mytree_global1}" != "${mytree_global2}" ]] ; then + err_exit "Compound trees 'mytree_global1' and 'mytree_global2' not identical" + diff -u <( printf "%s\n" "${mytree_global1}" ) <( printf "%s\n" "${mytree_global2}" ) + fi + + if [[ "${mytree_local1}" != "${mytree_local2}" ]] ; then + err_exit "Compound trees 'mytree_local1' and 'mytree_local2' not identical" + diff -u <( printf "%s\n" "${mytree_local1}" ) <( printf "%s\n" "${mytree_local2}" ) + fi + + + #### test "unset" in a subshell + ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ + err_exit "Try 1: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." + ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ + err_exit "Try 2: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." + + # remove parent node (array element) and then check whether the child is gone, too: + ( + set -o errexit + unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' + ! unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ) || err_exit "Global: Parent node removed (array element), child still exists" + ( + set -o errexit + unset 'mytree_local1.l1[urw].l2[itc zapfdingbats]' + ! unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ) || err_exit "Local: Parent node removed (array element), child still exists" + + # remove parent node (array variable) and then check whether the child is gone, too: + ( + set -o errexit + unset 'mytree_local1.l1[urw].l2' + ! unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ) || err_exit "Global: Parent node removed (array variable), child still exists" + ( + set -o errexit + unset 'mytree_local1.l1[urw].l2' + ! unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ) || err_exit "Local: Parent node removed (array variable), child still exists" + + + #### test "unset" and compare trees + unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + err_exit "Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." + + [[ "${mytree_global1}" != "${mytree_local1}" ]] || err_exit "mytree_global1 and mytree_local1 should differ" + + unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + err_exit "Variable 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." + + # Compare trees (after "unset") + if [[ "${mytree_global1}" != "${mytree_local1}" ]] ; then + err_exit "Compound trees 'mytree_local1' and 'mytree_global1' not identical after unset" + diff -u <( printf "%s\n" "${mytree_global1}" ) <( printf "%s\n" "${mytree_local1}" ) + fi +} + +main + +exit $((Errors)) +# EOF: Index: src/lib/libshell/common/tests/signal.sh =================================================================== --- src/lib/libshell/common/tests/signal.sh (revision 0) +++ src/lib/libshell/common/tests/signal.sh (revision 1122) @@ -0,0 +1,219 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2008 AT&T Intellectual Property # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" +trap 'cd /; rm -rf /tmp/ksh$$' EXIT +cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" + +# begin standalone SIGINT test generation + +cat > tst <<'!' +# shell trap tests +# +# tst control script that calls tst-1, must be run by ksh +# tst-1 calls tst-2 +# tst-2 calls tst-3 +# tst-3 defaults or handles and discards/propagates SIGINT +# +# initial -v option lists script entry and SIGINT delivery +# +# three test options +# +# d call next script directly, otherwise via $SHELL -c +# t trap, echo, and kill self on SIGINT, otherwise x or SIGINT default if no x +# x trap, echo on SIGINT, and exit 0, otherwise SIGINT default +# +# Usage: tst [-v] [-options] shell-to-test ... + +# "trap + sig" is an unadvertized extension for this test +# if run from nmake SIGINT is set to SIG_IGN +# this call sets it back to SIG_DFL +# semantics w.r.t. function scope must be worked out before +# making it public +trap + INT + +set -o monitor + +function gen +{ + typeset o t x d + for x in - x + do case $x in + [$1]) for t in - t + do case $t in + [$1]) for d in - d + do case $d in + [$1]) o="$o $x$t$d" + esac + done + esac + done + esac + done + echo '' $o +} + +case $1 in +-v) v=v; shift ;; +-*v*) v=v ;; +*) v= ;; +esac +case $1 in +*' '*) o=$1; shift ;; +-*) o=$(gen $1); shift ;; +*) o=$(gen -txd) ;; +esac +case $# in +0) set ksh bash ksh88 pdksh ash zsh ;; +esac +for f in $o +do case $# in + 1) ;; + *) echo ;; + esac + for sh + do if $sh -c 'exit 0' > /dev/null 2>&1 + then case $# in + 1) printf '%3s ' "$f" ;; + *) printf '%16s %3s ' "$sh" "$f" ;; + esac + $sh tst-1 $v$f $sh > tst.out & + wait + echo $(cat tst.out) + fi + done +done +case $# in +1) ;; +*) echo ;; +esac +! +cat > tst-1 <<'!' +exec 2>/dev/null +case $1 in +*v*) echo 1-main ;; +esac +{ + sleep 2 + case $1 in + *v*) echo "SIGINT" ;; + esac + kill -s INT 0 +} & +case $1 in +*t*) trap ' + echo 1-intr + trap - INT + # omitting the self kill exposes shells that deliver + # the SIGINT trap but exit 0 for -xt + # kill -s INT $$ + ' INT + ;; +esac +case $1 in +*d*) tst-2 $1 $2; status=$? ;; +*) $2 -c "tst-2 $1 $2"; status=$? ;; +esac +printf '1-%04d\n' $status +sleep 2 +! +cat > tst-2 <<'!' +case $1 in +*x*) trap ' + echo 2-intr + exit + ' INT + ;; +*t*) trap ' + echo 2-intr + trap - INT + kill -s INT $$ + ' INT + ;; +esac +case $1 in +*v*) echo 2-main ;; +esac +case $1 in +*d*) tst-3 $1 $2; status=$? ;; +*) $2 -c "tst-3 $1 $2"; status=$? ;; +esac +printf '2-%04d\n' $status +! +cat > tst-3 <<'!' +case $1 in +*x*) trap ' + sleep 2 + echo 3-intr + exit 0 + ' INT + ;; +*) trap ' + sleep 2 + echo 3-intr + trap - INT + kill -s INT $$ + ' INT + ;; +esac +case $1 in +*v*) echo 3-main ;; +esac +sleep 5 +printf '3-%04d\n' $? +! +chmod +x tst tst-? + +# end standalone test generation + +export PATH=$PATH: +typeset -A expected +expected[---]="3-intr" +expected[--d]="3-intr" +expected[-t-]="3-intr 2-intr 1-intr 1-0258" +expected[-td]="3-intr 2-intr 1-intr 1-0258" +expected[x--]="3-intr 2-intr 1-0000" +expected[x-d]="3-intr 2-intr 1-0000" +expected[xt-]="3-intr 2-intr 1-intr 1-0000" +expected[xtd]="3-intr 2-intr 1-intr 1-0000" + +tst $SHELL > tst.got + +while read ops out +do [[ $out == ${expected[$ops]} ]] || err_exit "interrupt $ops test failed -- got '$out', expected '${expected[$ops]}'" +done < tst.got + +float s=$SECONDS +[[ $($SHELL -c 'trap "print SIGUSR1 ; exit 0" USR1; (trap "" USR1 ; exec kill -USR1 $$ & sleep 5); print done') == SIGUSR1 ]] || err_exit 'subshell ignoring signal does not send signal to parent' +(( (SECONDS-s) < 4 )) && err_exit 'parent does not wait for child to complete before handling signal' +((s = SECONDS)) +[[ $($SHELL -c 'trap "print SIGUSR1 ; exit 0" USR1; (trap "exit" USR1 ; exec kill -USR1 $$ & sleep 5); print done') == SIGUSR1 ]] || err_exit 'subshell catching signal does not send signal to parent' +(( SECONDS-s < 4 )) && err_exit 'parent completes early' +exit $((Errors)) Index: src/lib/libshell/common/tests/return.sh =================================================================== --- src/lib/libshell/common/tests/return.sh (revision 974) +++ src/lib/libshell/common/tests/return.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -144,7 +144,7 @@ if [[ $x != $0 ]] then err_exit "\$0 in a dot script is $x. Should be $0" fi -x=$($SHELL -i 2> /dev/null <<\! +x=$($SHELL -i --norc 2> /dev/null <<\! typeset -i x=1/0 print hello ! Index: src/lib/libshell/common/tests/expand.sh =================================================================== --- src/lib/libshell/common/tests/expand.sh (revision 974) +++ src/lib/libshell/common/tests/expand.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -37,6 +37,8 @@ 'f{d,e,f}g' 'fdg feg ffg' \ '{l,n,m}xyz' 'lxyz nxyz mxyz' \ '{abc\,def}' '{abc,def}' \ + '{"abc,def"}' '{abc,def}' \ + "{'abc,def'}" '{abc,def}' \ '{abc}' '{abc}' \ '\{a,b,c,d,e}' '{a,b,c,d,e}' \ '{x,y,\{a,b,c}}' 'x} y} {a} b} c}' \ Index: src/lib/libshell/common/tests/cubetype.sh =================================================================== --- src/lib/libshell/common/tests/cubetype.sh (revision 0) +++ src/lib/libshell/common/tests/cubetype.sh (revision 1122) @@ -0,0 +1,187 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2008 AT&T Intellectual Property # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 +integer n=10 + +typeset -T Box_t=( + float -h 'height in inches' x=2 + float -h 'width in inches' y=4 + comvar=(top=8 bottom=9) + integer -S count=0 + items=(foo bar) + colors=([wall]=blue [floor]=red) + typeset name=unknown + typeset -L6 status=INIT + len() + { + print -r $((sqrt(_.x*_.x + _.y*_.y))) + (( _.count++)) + } + typeset -fh 'distance from the origin' len + depth() + { + print 0 + } + float x=3 +) + +for ((i=0; i < n; i++)) +do +Box_t b=(name=box1) +[[ ${b.x} == 3 ]] || err_exit '${b.x} is not 3' +(( b.len == 5 )) || err_exit 'b.len is not 5' +[[ ${b.name} == box1 ]] || err_exit '${b.name} is not box1' +(( b.count == 1 )) || err_exit 'b.count is not 1' +b.colors[wall]=green +b.colors[door]=white +[[ ${#b.colors[@]} == 3 ]] || err_exit 'b.color should have 3 colors' +b.comvar.bottom=11 +b.items[1]=bam +b.items[2]=extra +[[ ${#b.items[@]} == 3 ]] || err_exit 'b.items should have 3 items' +Box_t bb=b +bb.colors[desk]=orange +[[ ${#bb.colors[@]} == 4 ]] || err_exit 'bb.colors should have 4 colors' +unset b.colors +[[ ${#b.colors[@]} == 2 ]] || err_exit 'b.colors should have 2 colors' +unset b.items +[[ ${#b.items[@]} == 2 ]] || err_exit 'b.items should have 2 items' +unset bb.colors +[[ ${#bb.colors[@]} == 2 ]] || err_exit 'bb.colors should have 2 colors' +unset bb.items +[[ ${#bb.items[@]} == 2 ]] || err_exit 'bb.items should have 2 items' +[[ $b == "$bb" ]] || err_exit '$b != $bb' +b.count=0 +unset b bb +done + +typeset -T Cube_t=( + Box_t _=(y=5) + float z=1 + depth() + { + print -r -- $((_.z)) + } + len() + { + print -r $((sqrt(_.x*_.x + _.y*_.y + _.z*_.z))) + (( _.count++)) + } + float x=8 + fun() + { + print 'hello world' + } +) + + +for ((i=0; i < n; i++)) +do +Box_t b=(name=box2) +[[ ${b.name} == box2 ]] || err_exit '${b.name} is not box2' +(( b.len == 5 )) || err_exit 'b.len is not 5 for box2' +(( b.count == 1 )) || err_exit 'b.count is not 1' +Cube_t c=(name=cube1) +[[ $c == $'(\n\ttypeset -l -E x=8\n\ttypeset -l -E y=5\n\tcomvar=(\n\t\ttypeset top=8\n\t\ttypeset bottom=9\n\t)\n\ttypeset -S -l -i count=1\n\ttypeset -a items=(\n\t\tfoo\n\t\tbar\n\t)\n\ttypeset -A colors=(\n\t\t[floor]=red\n\t\t[wall]=blue\n\t)\n\tname=cube1\n\ttypeset -L 6 status=INIT\n\ttypeset -l -E z=1\n)' ]] || err_exit '$c not correct' +[[ ${c.x} == 8 ]] || err_exit '${c.x} != 8' +[[ ${c.depth} == 1 ]] || err_exit '${c.depth} != 1' +[[ ${c.name} == cube1 ]] || err_exit '${c.name} != cube1 ' +[[ $(c.fun) == 'hello world' ]] || err_exit '$(c.fun) != "hello world"' +[[ ${c.fun} == 'hello world' ]] || err_exit '${c.fun} != "hello world"' +(( abs(c.len - sqrt(90)) < 1e-10 )) || err_exit 'c.len != sqrt(90)' +(( c.count == 2 )) || err_exit 'c.count != 2' +(( c.count == b.count )) || err_exit 'c.count != b.count' +c.count=0 +Cube_t d=c +[[ $d == "$c" ]] || err_exit '$d != $c' +unset b c d +done +for ((i=0; i < n; i++)) +do +Cube_t cc +cc[2]=(x=2 y=3 name=two colors+=([table]=white) items+=(pencil) z=6) +[[ ${cc[2].y} == 3 ]] || err_exit '${cc[2].y} != 3' +(( cc[2].y == 3 )) || err_exit '(( cc[2].y != 3))' +[[ ${cc[2].colors[table]} == white ]] || err_exit '${cc[2].colors[table]} != white' +[[ ${cc[2].items[2]} == pencil ]] || err_exit '${cc[2].items[2]} != pencil' +(( cc[2].len == 7 )) || err_exit '(( cc[2].len != 7 ))' +[[ $(cc[2].len) == 7 ]] || err_exit '$(cc[2].len) != 7 ))' +[[ ${cc[2].len} == 7 ]] || err_exit '${cc[2].len} != 7 ))' +(( cc[2].count == 2 )) || err_exit 'cc[2].count != 2' +unset cc[2].x cc[2].y cc[2].z +(( cc[2].len == cc[0].len )) || err_exit 'cc[2].len != cc[0].len' +(( cc[2].len == cc.len )) || err_exit 'cc[2].len != cc.len' +(( cc[2].count == 6 )) || err_exit 'cc[2].count != 6' +unset cc[2].name cc[2].colors cc[2].items +[[ $cc == "${cc[2]}" ]] || err_exit '$cc != ${cc[2]}' +cc.count=0 +unset cc +Cube_t -A cc +cc[two]=(x=2 y=3 name=two colors+=([table]=white) items+=(pencil) z=6) +Cube_t cc[one] +[[ ${#cc[@]} == 2 ]] || err_exit '${#cc[@]} != 2' +[[ ${cc[two].y} == 3 ]] || err_exit '${cc[two].y} != 3' +(( cc[two].y == 3 )) || err_exit '(( cc[two].y != 3))' +[[ ${cc[two].colors[table]} == white ]] || err_exit '${cc[two].colors[table]} != white' +[[ ${cc[two].items[2]} == pencil ]] || err_exit '${cc[two].items[2]} != pencil' +(( cc[two].len == 7 )) || err_exit '(( cc[two].len != 7 ))' +[[ $(cc[two].len) == 7 ]] || err_exit '$(cc[two].len) != 7 ))' +[[ ${cc[two].len} == 7 ]] || err_exit '${cc[two].len} != 7 ))' +(( cc[two].count == 2 )) || err_exit 'cc[two].count != 2' +unset cc[two].x cc[two].y cc[two].z +(( cc[two].len == cc[one].len )) || err_exit 'cc[two].len != cc[one].len' +(( cc[two].count == 4 )) || err_exit 'cc[two].count != 4' +unset cc[two].name unset cc[two].colors cc[two].items +[[ ${cc[one]} == "${cc[two]}" ]] || err_exit '${cc[one]} != ${cc[two]}' +cc[two].count=0 +unset cc +Cube_t cc=( + [one]= + [two]=(x=2 y=3 name=two colors+=([table]=white) z=6) +) +[[ ${#cc[@]} == 2 ]] || err_exit '${#cc[@]} != 2' +[[ ${cc[two].y} == 3 ]] || err_exit '${cc[two].y} != 3' +(( cc[two].y == 3 )) || err_exit '(( cc[two].y != 3))' +[[ ${cc[two].colors[table]} == white ]] || err_exit '${cc[two].colors[table]} != white' +(( cc[two].len == 7 )) || err_exit '(( cc[two].len != 7 ))' +[[ $(cc[two].len) == 7 ]] || err_exit '$(cc[two].len) != 7 ))' +[[ ${cc[two].len} == 7 ]] || err_exit '${cc[two].len} != 7 ))' +(( cc[two].count == 2 )) || err_exit 'cc[two].count != 2' +unset cc[two].x cc[two].y cc[two].z +(( cc[two].len == cc[one].len )) || err_exit 'cc[two].len != cc[one].len' +(( cc[two].count == 4 )) || err_exit 'cc[two].count != 4' +cc[three]=cc[two] +[[ ${cc[two]} == "${cc[three]}" ]] || err_exit ' ${cc[two]} != ${cc[three]}' +[[ $cc[two] == "${cc[three]}" ]] || err_exit ' $cc[two] != $cc[three]' +[[ ${#cc[@]} == 3 ]] || err_exit '${#cc[@]} != 3' +unset cc[two].name unset cc[two].colors +cc[two].count=0 +unset cc +done +exit $Errors Index: src/lib/libshell/common/tests/glob.sh =================================================================== --- src/lib/libshell/common/tests/glob.sh (revision 974) +++ src/lib/libshell/common/tests/glob.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -19,8 +19,7 @@ ######################################################################## function err_exit { - print -u2 -n "\t" - print -u2 -r ${Command}[$1]: "${@:2}" + print -u2 -r $'\t'"${Command}[$1] ${@:2}" ((errors++)) } alias err_exit='err_exit $LINENO' @@ -30,6 +29,8 @@ function test_glob { typeset lineno expected drop arg got sep op val add del + lineno=$1 + shift if [[ $1 == --* ]] then del=${1#--} shift @@ -38,8 +39,8 @@ then add=${1#++} shift fi - lineno=$1 expected=$2 - shift 2 + expected=$1 + shift if (( contrary )) then if [[ $expected == "<Beware> "* ]] then expected=${expected#"<Beware> "} @@ -62,9 +63,10 @@ fi fi if [[ $got != "$expected" ]] - then err_exit $lineno "glob: got '$got' expected '$expected'" + then 'err_exit' $lineno "glob: got '$got' expected '$expected'" fi } +alias test_glob='test_glob $LINENO' function test_case { @@ -77,9 +79,10 @@ esac " if [[ $got != "$expected" ]] - then err_exit $lineno "case $subject in $pattern) got '$got' expected '$expected'" + then 'err_exit' $lineno "case $subject in $pattern) got '$got' expected '$expected'" fi } +alias test_case='test_case $LINENO' Command=${0##*/} tmp=/tmp/ksh$$ @@ -88,9 +91,9 @@ export LC_COLLATE=C -mkdir $tmp || err_exit $LINENO "mkdir $tmp failed" +mkdir $tmp || err_exit "mkdir $tmp failed" trap "cd /; rm -rf $tmp" EXIT -cd $tmp || err_exit $LINENO "cd $tmp failed" +cd $tmp || err_exit "cd $tmp failed" rm -rf * touch B b @@ -108,14 +111,14 @@ touch a b c d abc abd abe bb bcd ca cb dd de Beware mkdir bdir -test_glob $LINENO '<a> <abc> <abd> <abe> <X*>' a* X* -test_glob $LINENO '<a> <abc> <abd> <abe>' \a* +test_glob '<a> <abc> <abd> <abe> <X*>' a* X* +test_glob '<a> <abc> <abd> <abe>' \a* if ( set --nullglob ) 2>/dev/null then set --nullglob - test_glob $LINENO '<a> <abc> <abd> <abe>' a* X* + test_glob '<a> <abc> <abd> <abe>' a* X* set --nonullglob fi @@ -126,54 +129,54 @@ mkdir tmp touch tmp/l1 tmp/l2 tmp/l3 - test_glob $LINENO '' tmp/l[12] tmp/*4 tmp/*3 - test_glob $LINENO '' tmp/l[12] tmp/*4 tmp/*3 + test_glob '' tmp/l[12] tmp/*4 tmp/*3 + test_glob '' tmp/l[12] tmp/*4 tmp/*3 rm -r tmp set --nofailglob fi -test_glob $LINENO '<bdir/>' b*/ -test_glob $LINENO '<*>' \* -test_glob $LINENO '<a*>' 'a*' -test_glob $LINENO '<a*>' a\* -test_glob $LINENO '<c> <ca> <cb> <a*> <*q*>' c* a\* *q* -test_glob $LINENO '<**>' "*"* -test_glob $LINENO '<**>' \** -test_glob $LINENO '<\.\./*/>' "\.\./*/" -test_glob $LINENO '<s/\..*//>' 's/\..*//' -test_glob $LINENO '</^root:/{s/^[!:]*:[!:]*:\([!:]*\).*$/\1/>' "/^root:/{s/^[!:]*:[!:]*:\([!:]*\).*"'$'"/\1/" -test_glob $LINENO '<abc> <abd> <abe> <bb> <cb>' [a-c]b* -test_glob ++Beware $LINENO '<abd> <abe> <bb> <bcd> <bdir> <ca> <cb> <dd> <de>' [a-y]*[!c] -test_glob $LINENO '<abd> <abe>' a*[!c] +test_glob '<bdir/>' b*/ +test_glob '<*>' \* +test_glob '<a*>' 'a*' +test_glob '<a*>' a\* +test_glob '<c> <ca> <cb> <a*> <*q*>' c* a\* *q* +test_glob '<**>' "*"* +test_glob '<**>' \** +test_glob '<\.\./*/>' "\.\./*/" +test_glob '<s/\..*//>' 's/\..*//' +test_glob '</^root:/{s/^[!:]*:[!:]*:\([!:]*\).*$/\1/>' "/^root:/{s/^[!:]*:[!:]*:\([!:]*\).*"'$'"/\1/" +test_glob '<abc> <abd> <abe> <bb> <cb>' [a-c]b* +test_glob ++Beware '<abd> <abe> <bb> <bcd> <bdir> <ca> <cb> <dd> <de>' [a-y]*[!c] +test_glob '<abd> <abe>' a*[!c] touch a-b aXb -test_glob $LINENO '<a-b> <aXb>' a[X-]b +test_glob '<a-b> <aXb>' a[X-]b touch .x .y -test_glob --Beware $LINENO '<Beware> <d> <dd> <de>' [!a-c]* +test_glob --Beware '<Beware> <d> <dd> <de>' [!a-c]* if mkdir a\*b 2>/dev/null then touch a\*b/ooo - test_glob $LINENO '<a*b/ooo>' a\*b/* - test_glob $LINENO '<a*b/ooo>' a\*?/* - test_case $LINENO '<match>' '!7' '*\!*' - test_case $LINENO '<match>' 'r.*' '*.\*' - test_glob $LINENO '<abc>' a[b]c - test_glob $LINENO '<abc>' a["b"]c - test_glob $LINENO '<abc>' a[\b]c - test_glob $LINENO '<abc>' a?c - test_case $LINENO '<match>' 'abc' 'a"b"c' - test_case $LINENO '<match>' 'abc' 'a*c' - test_case $LINENO '<nomatch>' 'abc' '"a?c"' - test_case $LINENO '<nomatch>' 'abc' 'a\*c' - test_case $LINENO '<nomatch>' 'abc' 'a\[b]c' - test_case $LINENO '<match>' '"$undefined"' '""' - test_case $LINENO '<match>' 'abc' 'a["\b"]c' + test_glob '<a*b/ooo>' a\*b/* + test_glob '<a*b/ooo>' a\*?/* + test_case '<match>' '!7' '*\!*' + test_case '<match>' 'r.*' '*.\*' + test_glob '<abc>' a[b]c + test_glob '<abc>' a["b"]c + test_glob '<abc>' a[\b]c + test_glob '<abc>' a?c + test_case '<match>' 'abc' 'a"b"c' + test_case '<match>' 'abc' 'a*c' + test_case '<nomatch>' 'abc' '"a?c"' + test_case '<nomatch>' 'abc' 'a\*c' + test_case '<nomatch>' 'abc' 'a\[b]c' + test_case '<match>' '"$undefined"' '""' + test_case '<match>' 'abc' 'a["\b"]c' rm -rf mkdir a\*b fi @@ -182,68 +185,68 @@ mkdir man/man1 touch man/man1/sh.1 -test_glob $LINENO '<man/man1/sh.1>' */man*/sh.* -test_glob $LINENO '<man/man1/sh.1>' $(echo */man*/sh.*) -test_glob $LINENO '<man/man1/sh.1>' "$(echo */man*/sh.*)" +test_glob '<man/man1/sh.1>' */man*/sh.* +test_glob '<man/man1/sh.1>' $(echo */man*/sh.*) +test_glob '<man/man1/sh.1>' "$(echo */man*/sh.*)" -test_case $LINENO '<match>' 'abc' 'a***c' -test_case $LINENO '<match>' 'abc' 'a*****?c' -test_case $LINENO '<match>' 'abc' '?*****??' -test_case $LINENO '<match>' 'abc' '*****??' -test_case $LINENO '<match>' 'abc' '*****??c' -test_case $LINENO '<match>' 'abc' '?*****?c' -test_case $LINENO '<match>' 'abc' '?***?****c' -test_case $LINENO '<match>' 'abc' '?***?****?' -test_case $LINENO '<match>' 'abc' '?***?****' -test_case $LINENO '<match>' 'abc' '*******c' -test_case $LINENO '<match>' 'abc' '*******?' -test_case $LINENO '<match>' 'abcdecdhjk' 'a*cd**?**??k' -test_case $LINENO '<match>' 'abcdecdhjk' 'a**?**cd**?**??k' -test_case $LINENO '<match>' 'abcdecdhjk' 'a**?**cd**?**??k***' -test_case $LINENO '<match>' 'abcdecdhjk' 'a**?**cd**?**??***k' -test_case $LINENO '<match>' 'abcdecdhjk' 'a**?**cd**?**??***k**' -test_case $LINENO '<match>' 'abcdecdhjk' 'a****c**?**??*****' -test_case $LINENO '<match>' "'-'" '[-abc]' -test_case $LINENO '<match>' "'-'" '[abc-]' -test_case $LINENO '<match>' "'\\'" '\\' -test_case $LINENO '<match>' "'\\'" '[\\]' -test_case $LINENO '<match>' "'\\'" "'\\'" -test_case $LINENO '<match>' "'['" '[[]' -test_case $LINENO '<match>' '[' '[[]' -test_case $LINENO '<match>' "'['" '[' -test_case $LINENO '<match>' '[' '[' -test_case $LINENO '<match>' "'[abc'" "'['*" -test_case $LINENO '<nomatch>' "'[abc'" '[*' -test_case $LINENO '<match>' '[abc' "'['*" -test_case $LINENO '<nomatch>' '[abc' '[*' -test_case $LINENO '<match>' 'abd' "a[b/c]d" -test_case $LINENO '<match>' 'a/d' "a[b/c]d" -test_case $LINENO '<match>' 'acd' "a[b/c]d" -test_case $LINENO '<match>' "']'" '[]]' -test_case $LINENO '<match>' "'-'" '[]-]' -test_case $LINENO '<match>' 'p' '[a-\z]' -test_case $LINENO '<match>' '"/tmp"' '[/\\]*' -test_case $LINENO '<nomatch>' 'abc' '??**********?****?' -test_case $LINENO '<nomatch>' 'abc' '??**********?****c' -test_case $LINENO '<nomatch>' 'abc' '?************c****?****' -test_case $LINENO '<nomatch>' 'abc' '*c*?**' -test_case $LINENO '<nomatch>' 'abc' 'a*****c*?**' -test_case $LINENO '<nomatch>' 'abc' 'a********???*******' -test_case $LINENO '<nomatch>' "'a'" '[]' -test_case $LINENO '<nomatch>' 'a' '[]' -test_case $LINENO '<nomatch>' "'['" '[abc' -test_case $LINENO '<nomatch>' '[' '[abc' +test_case '<match>' 'abc' 'a***c' +test_case '<match>' 'abc' 'a*****?c' +test_case '<match>' 'abc' '?*****??' +test_case '<match>' 'abc' '*****??' +test_case '<match>' 'abc' '*****??c' +test_case '<match>' 'abc' '?*****?c' +test_case '<match>' 'abc' '?***?****c' +test_case '<match>' 'abc' '?***?****?' +test_case '<match>' 'abc' '?***?****' +test_case '<match>' 'abc' '*******c' +test_case '<match>' 'abc' '*******?' +test_case '<match>' 'abcdecdhjk' 'a*cd**?**??k' +test_case '<match>' 'abcdecdhjk' 'a**?**cd**?**??k' +test_case '<match>' 'abcdecdhjk' 'a**?**cd**?**??k***' +test_case '<match>' 'abcdecdhjk' 'a**?**cd**?**??***k' +test_case '<match>' 'abcdecdhjk' 'a**?**cd**?**??***k**' +test_case '<match>' 'abcdecdhjk' 'a****c**?**??*****' +test_case '<match>' "'-'" '[-abc]' +test_case '<match>' "'-'" '[abc-]' +test_case '<match>' "'\\'" '\\' +test_case '<match>' "'\\'" '[\\]' +test_case '<match>' "'\\'" "'\\'" +test_case '<match>' "'['" '[[]' +test_case '<match>' '[' '[[]' +test_case '<match>' "'['" '[' +test_case '<match>' '[' '[' +test_case '<match>' "'[abc'" "'['*" +test_case '<nomatch>' "'[abc'" '[*' +test_case '<match>' '[abc' "'['*" +test_case '<nomatch>' '[abc' '[*' +test_case '<match>' 'abd' "a[b/c]d" +test_case '<match>' 'a/d' "a[b/c]d" +test_case '<match>' 'acd' "a[b/c]d" +test_case '<match>' "']'" '[]]' +test_case '<match>' "'-'" '[]-]' +test_case '<match>' 'p' '[a-\z]' +test_case '<match>' '"/tmp"' '[/\\]*' +test_case '<nomatch>' 'abc' '??**********?****?' +test_case '<nomatch>' 'abc' '??**********?****c' +test_case '<nomatch>' 'abc' '?************c****?****' +test_case '<nomatch>' 'abc' '*c*?**' +test_case '<nomatch>' 'abc' 'a*****c*?**' +test_case '<nomatch>' 'abc' 'a********???*******' +test_case '<nomatch>' "'a'" '[]' +test_case '<nomatch>' 'a' '[]' +test_case '<nomatch>' "'['" '[abc' +test_case '<nomatch>' '[' '[abc' -test_glob ++Beware $LINENO '<b> <bb> <bcd> <bdir>' b* -test_glob $LINENO '<Beware> <b> <bb> <bcd> <bdir>' [bB]* +test_glob ++Beware '<b> <bb> <bcd> <bdir>' b* +test_glob '<Beware> <b> <bb> <bcd> <bdir>' [bB]* if ( set --nocaseglob ) 2>/dev/null then set --nocaseglob - test_glob $LINENO '<Beware> <b> <bb> <bcd> <bdir>' b* - test_glob $LINENO '<Beware> <b> <bb> <bcd> <bdir>' [b]* - test_glob $LINENO '<Beware> <b> <bb> <bcd> <bdir>' [bB]* + test_glob '<Beware> <b> <bb> <bcd> <bdir>' b* + test_glob '<Beware> <b> <bb> <bcd> <bdir>' [b]* + test_glob '<Beware> <b> <bb> <bcd> <bdir>' [bB]* set --nonocaseglob fi @@ -252,7 +255,7 @@ then set -f - test_glob $LINENO '<*>' * + test_glob '<*>' * set +f fi @@ -261,43 +264,114 @@ then set --noglob - test_glob $LINENO '<*>' * + test_glob '<*>' * set --glob fi FIGNORE='.*|*' -test_glob $LINENO '<*>' * +test_glob '<*>' * FIGNORE='.*|*c|*e|?' -test_glob $LINENO '<a-b> <aXb> <abd> <bb> <bcd> <bdir> <ca> <cb> <dd> <man>' * +test_glob '<a-b> <aXb> <abd> <bb> <bcd> <bdir> <ca> <cb> <dd> <man>' * FIGNORE='.*|*b|*d|?' -test_glob $LINENO '<Beware> <abc> <abe> <bdir> <ca> <de> <man>' * +test_glob '<Beware> <abc> <abe> <bdir> <ca> <de> <man>' * FIGNORE= -test_glob $LINENO '<man/man1/sh.1>' */man*/sh.* +test_glob '<man/man1/sh.1>' */man*/sh.* unset FIGNORE -test_glob $LINENO '<bb> <ca> <cb> <dd> <de>' ?? -test_glob $LINENO '<man/man1/sh.1>' */man*/sh.* +test_glob '<bb> <ca> <cb> <dd> <de>' ?? +test_glob '<man/man1/sh.1>' */man*/sh.* GLOBIGNORE='.*:*' set -- * if [[ $1 == '*' ]] then GLOBIGNORE='.*:*c:*e:?' - test_glob $LINENO '<>' * + test_glob '<>' * GLOBIGNORE='.*:*b:*d:?' - test_glob $LINENO '<>' * + test_glob '<>' * unset GLOBIGNORE - test_glob $LINENO '<>' * - test_glob $LINENO '<man/man1/sh.1>' */man*/sh.* + test_glob '<>' * + test_glob '<man/man1/sh.1>' */man*/sh.* GLOBIGNORE= - test_glob $LINENO '<man/man1/sh.1>' */man*/sh.* + test_glob '<man/man1/sh.1>' */man*/sh.* fi +unset GLOBIGNORE +function test_sub +{ + x='${subject'$2'}' + eval g=$x + if [[ "$g" != "$3" ]] + then 'err_exit' $1 subject="'$subject' $x failed, expected '$3', got '$g'" + fi +} +alias test_sub='test_sub $LINENO' + +set --noglob --nobraceexpand + +subject='A regular expressions test' + +test_sub '/e/#' 'A r#gular expressions test' +test_sub '//e/#' 'A r#gular #xpr#ssions t#st' +test_sub '/[^e]/#' '# regular expressions test' +test_sub '//[^e]/#' '###e######e###e########e##' +test_sub '/+(e)/#' 'A r#gular expressions test' +test_sub '//+(e)/#' 'A r#gular #xpr#ssions t#st' +test_sub '/@-(e)/#' 'A r#gular expressions test' +test_sub '//@-(e)/#' 'A r#gular #xpr#ssions t#st' +test_sub '/?(e)/#' '#A regular expressions test' +test_sub '//?(e)/#' '#A# #r#g#u#l#a#r# #x#p#r#s#s#i#o#n#s# #t#s#t#' +test_sub '/*(e)/#' '#A regular expressions test' +test_sub '//*(e)/#' '#A# #r#g#u#l#a#r# #x#p#r#s#s#i#o#n#s# #t#s#t#' +test_sub '//@(e)/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st' +test_sub '//@-(e)/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st' +test_sub '//+(e)/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st' +test_sub '//+-(e)/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st' +test_sub '//@(+(e))/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st' +test_sub '//@(+-(e))/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st' +test_sub '//-(e)/#' 'A regular expressions test' +test_sub '//--(e)/#' 'A regular expressions test' +test_sub '//?(e)/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//{0,1}(e)/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//*(e)/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//{0,}(e)/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//@(?(e))/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//@({0,1}(e))/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//@(*(e))/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//@({0,}(e))/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '/?-(e)/#' '#A regular expressions test' +test_sub '/@(?-(e))/[\1]' '[]A regular expressions test' +test_sub '/!(e)/#' '#' +test_sub '//!(e)/#' '#' +test_sub '/@(!(e))/[\1]' '[A regular expressions test]' +test_sub '//@(!(e))/[\1]' '[A regular expressions test]' + +subject='e' + +test_sub '/!(e)/#' '#e' +test_sub '//!(e)/#' '#e#' +test_sub '/!(e)/[\1]' '[]e' +test_sub '//!(e)/[\1]' '[]e[]' +test_sub '/@(!(e))/[\1]' '[]e' +test_sub '//@(!(e))/[\1]' '[]e[]' + +subject='a' + +test_sub '/@(!(a))/[\1]' '[]a' +test_sub '//@(!(a))/[\1]' '[]a[]' + +subject='aha' + +test_sub '/@(!(a))/[\1]' '[aha]' +test_sub '//@(!(a))/[\1]' '[aha]' +test_sub '/@(!(aha))/[\1]' '[ah]a' +test_sub '//@(!(aha))/[\1]' '[ah][a]' + exit $errors Index: src/lib/libshell/common/tests/attributes.sh =================================================================== --- src/lib/libshell/common/tests/attributes.sh (revision 974) +++ src/lib/libshell/common/tests/attributes.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -123,6 +123,10 @@ if [[ $(/tmp/ksh$$) != 13 ]] then err_exit 'attributes not cleared for script execution' fi +print 'print VAR=$VAR' > /tmp/ksh$$ +typeset -L70 VAR=var +/tmp/ksh$$ > /tmp/ksh$$.1 +[[ $(< /tmp/ksh$$.1) == VAR= ]] || err_exit 'typeset -L should not be inherited' typeset -Z LAST=00 unset -f foo function foo @@ -140,7 +144,8 @@ if (( ${#LAST} != 2 )) then err_exit 'LAST!=2' fi -rm -rf /tmp/ksh$$ +[[ $(set | grep LAST) == LAST=02 ]] || err_exit "LAST not correct in set list" +rm -rf /tmp/ksh$$* set -a unset foo foo=bar @@ -213,4 +218,13 @@ fun [[ $(export | grep foo) == 'foo=hello' ]] || err_exit 'export not working in functions' [[ $(export | grep bar) ]] && err_exit 'typeset -x not local' +[[ $($SHELL -c 'typeset -r IFS=;print -r $(pwd)' 2> /dev/null) == "$(pwd)" ]] || err_exit 'readonly IFS causes command substitution to fail' +fred[66]=88 +[[ $(typeset -pa) == *fred* ]] || err_exit 'typeset -pa not working' +unset x y z +typeset -LZ3 x=abcd y z=00abcd +y=03 +[[ $y == "3 " ]] || err_exit '-LZ3 not working for value 03' +[[ $x == "abc" ]] || err_exit '-LZ3 not working for value abcd' +[[ $x == "abc" ]] || err_exit '-LZ3 not working for value 00abcd' exit $((Errors)) Index: src/lib/libshell/common/tests/comvar.sh =================================================================== --- src/lib/libshell/common/tests/comvar.sh (revision 974) +++ src/lib/libshell/common/tests/comvar.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -73,6 +73,7 @@ then err_exit 'name references not expanded on prefix matching' fi unset x +unset -n x ( x=() x.foo.bar=7 @@ -191,7 +192,117 @@ localvar (( (point.x*point.x + point.y*point.y) == 100 )) || err_exit "global compound variable not preserved" [[ $($SHELL -c 'foo=();foo.[x]=(y z); print ${foo.x[@]}') == 'y z' ]] 2> /dev/null || err_exit 'foo=( [x]=(y z) not working' +function staticvar +{ + if [[ $1 ]] + then print -r -- "$point" + return + fi + typeset -S point=(typeset -i x=3 y=4) + (( (point.x*point.x + point.y*point.y) == 25 )) || err_exit "local compound variable not working" + point.y=5 + point.z=foobar +} +staticvar + (( (point.x*point.x + point.y*point.y) == 100 )) || err_exit "global compound variable not preserved" +[[ $(staticvar x) == $'(\n\ttypeset -i x=3\n\ttypeset -i y=5\n\tz=foobar\n)' ]] || err_exit 'static variables in function not working' +integer x=3 +( typeset -S x=+++)2> /dev/null || err_exit "typeset -S doesn't unset first" + unset z ( [[ ${z.foo.bar:-abc} == abc ]] 2> /dev/null) || err_exit ':- not working with compound variables' +stack=() +typeset -a stack.items=([0]=foo [1]=bar) +[[ ${stack.items[0]} == foo ]] || err_exit 'typeset -a variable not expanding correctly' +$SHELL -c 'typeset -a info=( [1]=( passwd=( since=2005-07-20) ))' || err_exit 'problem with embedded index array in compound variable' +x=(foo=([1]=(y=([2]=(z=4))))) +[[ $x == *'.y'=* ]] && err_exit 'expansion with bogus leading . in name' +unset z +z=1 +function foo +{ + z=3 + [[ ${a.z} == 3 ]] && err_exit "\${a.z} should not be 3" + print hi +} +a=( b=$(foo) ) +[[ ${a.z} == 3 ]] && err_exit 'a.z should not be set to 3' +function a.b.get +{ + .sh.value=foo +} +{ b=( b1=${a.b} ) ;} 2> /dev/null +[[ ${b.b1} == foo ]] || err_exit '${b.b1} should be foo' +function dcl1 +{ + eval 'a=1 + function a.set + { print ${.sh.name}=${.sh.value}; }' +} +function dcl2 +{ + eval 'b=(typeset x=0; typeset y=0 ) + function b.x.set + { print ${.sh.name}=${.sh.value}; }' +} +dcl1 +[[ ${ a=123;} == 'a=123' ]] || err_exit 'should be a=123' +dcl2 +[[ ${ b.x=456;} == 'b.x=456' ]] || err_exit 'should be b.x=456' +eval 'b=(typeset x=0; typeset y=0 ) +function b.x.set +{ print ${.sh.name}=${.sh.value}; }' > /dev/null +[[ ${ b.x=789;} == 'b.x=789' ]] || err_exit 'should be b.x=789' +unset a b +function func +{ + typeset X + X=( bar=2 ) +} + +X=( foo=1 ) +func +[[ $X == $'(\n\tfoo=1\n)' ]] || err_exit 'scoping problem with compound variables' +unset foo +typeset -A foo=([a]=aa;[b]=bb;[c]=cc) +[[ ${foo[c]} == cc ]] || err_exit 'associative array assignment with; not working' +[[ $({ $SHELL -c 'x=(); typeset -a x.foo; x.foo=bar; print -r -- "$x"' ;} 2> /dev/null) == $'(\n\ttypeset -a foo=bar\n)' ]] || err_exit 'indexed array in compound variable with only element 0 defined fails' +unset foo +foo=(typeset -a bar) +[[ $foo == *'typeset -a bar'* ]] || err_exit 'array attribute -a not preserved in compound variable' +unset s +typeset -A s=( [foo]=(y=2 z=3) [bar]=(y=4 z=5)) +[[ ${s[@]} == *z=*z=* ]] || err_exit 'missing elements in compound associative array' +unset nodes +typeset -A nodes +nodes[0]+=( integer x=5) +[[ ${nodes[0].x} == 5 ]] || err_exit '${nodes[0].x} should be 5' +unset foo +typeset -C foo +foo.bar=abc +[[ $foo = $'(\n\tbar=abc\n)' ]] || err_exit 'typeset -C not working for foo' +typeset -C foo=(bar=def) +[[ $foo = $'(\n\tbar=def\n)' ]] || err_exit 'typeset -C not working when initialized' +foo=( + hello=ok + yes=( bam=2 yes=4) + typeset -A array=([one]=one [two]=2) + last=me +) +eval foo2="$foo" +foo2.hello=notok foo2.yes.yex=no foo2.extra=yes. +typeset -C bar bam +{ + read -Cu3 bar + read -Cu3 bam + read -ru3 +} 3<<- ++++ + "$foo" + "$foo2" + last line +++++ +[[ $? == 0 ]] || err_exit ' read -C failed' +[[ $bar == "$foo" ]] || err_exit '$foo != $bar' +[[ $bam == "$foo2" ]] || err_exit '$foo2 != $bmr' +[[ $REPLY == 'last line' ]] || err_exit "\$REPLY=$REPLY should be 'last line" exit $((Errors)) - Index: src/lib/libshell/common/tests/alias.sh =================================================================== --- src/lib/libshell/common/tests/alias.sh (revision 974) +++ src/lib/libshell/common/tests/alias.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -78,6 +78,20 @@ if whence rm > /dev/null then [[ ! $(alias -t | grep rm= ) ]] && err_exit 'tracked alias not set' PATH=$PATH - [[ $(alias -t | grep rm= ) ]] && err_exit 'tracked alias not cleared' + [[ $(alias -t | grep rm= ) ]] && err_exit 'tracked alias not cleared' fi +if hash -r 2>/dev/null && [[ ! $(hash) ]] +then mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" + trap "cd /; rm -rf /tmp/ksh$$" EXIT + PATH=/tmp/ksh$$:/bin:/usr/bin + for i in foo -foo -- + do print ':' > /tmp/ksh$$/$i + chmod +x /tmp/ksh$$/$i + hash -r -- $i 2>/dev/null || err_exit "hash -r -- $i failed" + [[ $(hash) == $i=/tmp/ksh$$/$i ]] || err_exit "hash -r -- $i failed, expected $i=/tmp/ksh$$/$i, got $(hash)" + done +else err_exit 'hash -r failed' +fi +( alias :pr=print) 2> /dev/null || err_exit 'alias beginning with : fails' +( alias p:r=print) 2> /dev/null || err_exit 'alias with : in name fails' exit $((Errors)) Index: src/lib/libshell/common/tests/vartree2.sh =================================================================== --- src/lib/libshell/common/tests/vartree2.sh (revision 0) +++ src/lib/libshell/common/tests/vartree2.sh (revision 1122) @@ -0,0 +1,337 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2008 AT&T Intellectual Property # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +# +# variable tree test #002 +# Propose of this test is whether ksh93 handles global variable trees +# and function-local variable trees the same way, including "nameref" +# and "unset" handling. +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +# "built_tree1" and "built_tree2" are identical except the way how they test +# whether a variable exists: +# - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable +# as non-zero length content +# - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell +function build_tree1 +{ +#set -o errexit -o xtrace + typeset index + typeset s + typeset i + typeset dummy + typeset a b c d e f + + nameref dest_tree="$1" # destination tree + nameref srcdata="$2" # source data + typeset tree_mode="$3" # mode to define the type of leads + + typeset -A dest_tree.l1 + + for index in "${!srcdata.hashnodes[@]}" ; do + nameref node=srcdata.hashnodes["${index}"] + + for i in "${node.xlfd[@]}" ; do + IFS='-' read dummy a b c d e f <<<"$i" + + if [[ "$a" == "" ]] ; then + a="$dummy" + fi + + [[ "$a" == "" ]] && a='-' + [[ "$b" == "" ]] && b='-' + [[ "$c" == "" ]] && c='-' + + if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then + #if ! (unset dest_tree.l1["$a"]) ; then + typeset -A dest_tree.l1["$a"].l2 + fi + + if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then + #if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3 + fi + + if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries + fi + + typeset new_index + if [[ "${tree_mode}" == "leaf_name" ]] ; then + new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) + else + new_index="${node.name}" + + # skip if the leaf node already exists + if [[ "${dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}]}" != "" ]] ; then + continue + fi + fi + + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" + done + done + + return 0 +} + +# "built_tree1" and "built_tree2" are identical except the way how they test +# whether a variable exists: +# - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable +# as non-zero length content +# - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell +function build_tree2 +{ +#set -o errexit -o xtrace + typeset index + typeset s + typeset i + typeset dummy + typeset a b c d e f + + nameref dest_tree="$1" # destination tree + nameref srcdata="$2" # source data + typeset tree_mode="$3" # mode to define the type of leads + + typeset -A dest_tree.l1 + + for index in "${!srcdata.hashnodes[@]}" ; do + nameref node=srcdata.hashnodes["${index}"] + + for i in "${node.xlfd[@]}" ; do + IFS='-' read dummy a b c d e f <<<"$i" + + if [[ "$a" == "" ]] ; then + a="$dummy" + fi + + [[ "$a" == "" ]] && a='-' + [[ "$b" == "" ]] && b='-' + [[ "$c" == "" ]] && c='-' + + #if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then + if ! (unset dest_tree.l1["$a"]) ; then + typeset -A dest_tree.l1["$a"].l2 + fi + + #if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then + if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3 + fi + + if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries + fi + + typeset new_index + if [[ "${tree_mode}" == "leaf_name" ]] ; then + new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) + else + new_index="${node.name}" + + # skip if the leaf node already exists + if [[ "${dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}]}" != "" ]] ; then + continue + fi + fi + + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" + done + done + + return 0 +} + + +function add_tree_leaf +{ + nameref tree_leafnode="$1" + nameref data_node=srcdata.hashnodes["$2"] + typeset add_mode="$3" + + case "${add_mode}" in + "leaf_name") + tree_leafnode="${data_node.name}" + return 0 + ;; + "leaf_compound") + tree_leafnode=( + typeset name="${data_node.name}" + typeset -a filenames=( "${data_node.filenames[@]}" ) + typeset -a comments=( "${data_node.comments[@]}" ) + typeset -a xlfd=( "${data_node.xlfd[@]}" ) + ) + return 0 + ;; + *) + print -u2 -f "ERROR: Unknown mode %s in add_tree_leaf\n" "${add_mode}" + return 1 + ;; + esac + + # not reached + return 1 +} + +# "mysrcdata_local" and "mysrcdata_global" must be identical +typeset mysrcdata_global=( + typeset -A hashnodes=( + [abcd]=( + name='abcd' + typeset -a xlfd=( + '-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific' + ) + typeset -a comments=( + 'comment 1' + 'comment 2' + 'comment 3' + ) + typeset -a filenames=( + '/home/foo/abcd_1' + '/home/foo/abcd_2' + '/home/foo/abcd_3' + ) + ) + ) +) + +mytree_global1=() +mytree_global2=() + +function main +{ + # "mysrcdata_local" and "mysrcdata_global" must be identical + typeset mysrcdata_local=( + typeset -A hashnodes=( + [abcd]=( + name='abcd' + typeset -a xlfd=( + '-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific' + ) + typeset -a comments=( + 'comment 1' + 'comment 2' + 'comment 3' + ) + typeset -a filenames=( + '/home/foo/abcd_1' + '/home/foo/abcd_2' + '/home/foo/abcd_3' + ) + ) + ) + ) + + #### Build tree using global tree variables + build_tree1 mytree_global1 mysrcdata_global leaf_compound || \ + err_exit 'build_tree1 mytree_global1 mysrcdata_global leaf_compound returned an error' + (( $(print -r -- "${mytree_global1}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_global1' too small." + + build_tree2 mytree_global2 mysrcdata_global leaf_compound || \ + err_exit 'build_tree2 mytree_global2 mysrcdata_global leaf_compound returned an error' + (( $(print -r -- "${mytree_global2}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_global2' too small." + + + #### build tree using local tree variables + mytree_local1=() + mytree_local2=() + + build_tree1 mytree_local1 mysrcdata_local leaf_compound || \ + err_exit 'build_tree1 mytree_local1 mysrcdata_local leaf_compound returned an error' + (( $(print -r -- "${mytree_local1}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_local1' too small." + + build_tree2 mytree_local2 mysrcdata_local leaf_compound || \ + err_exit 'build_tree2 mytree_local2 mysrcdata_local leaf_compound returned an error' + (( $(print -r -- "${mytree_local2}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_local2' too small." + + + #### Compare treess + if [[ "${mytree_global1}" != "${mytree_local1}" ]] ; then + err_exit "Compound trees 'mytree_global1' and 'mytree_local1' not identical" + diff -u <( printf "%s\n" "${mytree_global1}" ) <( printf "%s\n" "${mytree_local1}" ) + fi + + if [[ "${mytree_global1}" != "${mytree_global2}" ]] ; then + err_exit "Compound trees 'mytree_global1' and 'mytree_global2' not identical" + diff -u <( printf "%s\n" "${mytree_global1}" ) <( printf "%s\n" "${mytree_global2}" ) + fi + + if [[ "${mytree_local1}" != "${mytree_local2}" ]] ; then + err_exit "Compound trees 'mytree_local1' and 'mytree_local2' not identical" + diff -u <( printf "%s\n" "${mytree_local1}" ) <( printf "%s\n" "${mytree_local2}" ) + fi + + + #### test "unset" in a subshell + ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ + err_exit "Try 1: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." + ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ + err_exit "Try 2: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." + + # remove parent node (array element) and then check whether the child is gone, too: + ( + unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' + unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ) && err_exit "Global: Parent node removed (array element), child still exists" + ( + unset 'mytree_local1.l1[urw].l2[itc zapfdingbats]' + unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ) && err_exit "Local: Parent node removed (array element), child still exists" + + # remove parent node (array variable) and then check whether the child is gone, too: + ( + unset 'mytree_local1.l1[urw].l2' + unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ) && err_exit "Global: Parent node removed (array variable), child still exists" + ( + unset 'mytree_local1.l1[urw].l2' + unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ) && err_exit "Local: Parent node removed (array variable), child still exists" + + + #### test "unset" and compare trees + unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + err_exit "Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." + + [[ "${mytree_global1}" != "${mytree_local1}" ]] || err_exit "mytree_global1 and mytree_local1 should differ" + + unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + err_exit "Variable 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." + + # Compare trees (after "unset") + if [[ "${mytree_global1}" != "${mytree_local1}" ]] ; then + err_exit "Compound trees 'mytree_local1' and 'mytree_global1' not identical after unset" + diff -u <( printf "%s\n" "${mytree_global1}" ) <( printf "%s\n" "${mytree_local1}" ) + fi +} + +main Index: src/lib/libshell/common/tests/options.sh =================================================================== --- src/lib/libshell/common/tests/options.sh (revision 974) +++ src/lib/libshell/common/tests/options.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -46,9 +46,9 @@ tmp=/tmp/ksh$$ mkdir $tmp rc=$tmp/.kshrc -print $'function env_hit\n{\n\tprint OK\n}' > $rc +print $'PS1=""\nfunction env_hit\n{\n\tprint OK\n}' > $rc -export ENV=$rc +export ENV='${nosysrc}'$rc if [[ -o privileged ]] then [[ $(print env_hit | $SHELL 2>&1) == "OK" ]] && @@ -72,6 +72,8 @@ err_exit '--rc ignores $ENV file' [[ $(print env_hit | $SHELL --norc 2>&1) == "OK" ]] && err_exit '--norc reads $ENV file' + [[ $(print env_hit | $SHELL -i 2>&1) == "OK" ]] || + err_exit '-i ignores $ENV file' fi export ENV= @@ -304,10 +306,59 @@ then err_exit "[[ -o ?no$opt ]] should fail" fi done + +[[ $(set +o) == $(set --state) ]] || err_exit "set --state different from set +o" +set -- $(set --state) +[[ $1 == set && $2 == --default ]] || err_exit "set --state failed -- expected 'set --default *', got '$1 $2 *'" +shift +restore=$* +shift +off= +for opt +do case $opt in + --not*) opt=${opt/--/--no} ;; + --no*) opt=${opt/--no/--} ;; + --*) opt=${opt/--/--no} ;; + esac + off="$off $opt" +done +set $off +state=$(set --state) +default=$(set --default --state) +[[ $state == $default ]] || err_exit "set --state for default options failed: expected '$default', got '$state'" +set $restore +state=$(set --state) +[[ $state == "set $restore" ]] || err_exit "set --state after restore failed: expected 'set $restore', got '$state'" + false | true | true || err_exit 'pipe not exiting exit value of last element' true | true | false && err_exit 'pipe not exiting false' set -o pipefail false | true | true && err_exit 'pipe with first not failing with pipefail' true | false | true && err_exit 'pipe middle not failing with pipefail' true | true | false && err_exit 'pipe last not failing with pipefail' +print hi | (sleep 1;/bin/cat) > /dev/null || err_exit 'pipeline fails with pipefail' +( + set -o pipefail + false | true + (( $? )) || err_exit 'pipe not failing in subshell with pipefail' +) | wc >/dev/null +$SHELL -c 'set -o pipefail; false | $(whence -p true);' && err_exit 'pipefail not returning failure with sh -c' +$SHELL -c '[[ $- == *c* ]]' || err_exit 'option c not in $-' +trap 'rm -f /tmp/.profile' EXIT +> /tmp/.profile +for i in i l r s D E a b e f h k n r t u v x B C G H +do HOME=/tmp ENV= $SHELL -$i 2> /dev/null <<- ++EOF++ || err_exit "option $i not in \$-" + [[ \$- == *$i* ]] || exit 1 + ++EOF++ +done +letters=ilrabefhknuvxBCGE +integer j=0 +for i in interactive login restricted allexport notify errexit \ + noglob trackall keyword noexec nounset verbose xtrace braceexpand \ + noclobber globstar rc +do HOME=/tmp ENV= $SHELL -o $i 2> /dev/null <<- ++EOF++ || err_exit "option $i not equivalent to ${letters:j:1}" + [[ \$- == *${letters:j:1}* ]] || exit 1 + ++EOF++ + ((j++)) +done exit $((Errors)) Index: src/lib/libshell/common/tests/grep.sh =================================================================== --- src/lib/libshell/common/tests/grep.sh (revision 974) +++ src/lib/libshell/common/tests/grep.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # Index: src/lib/libshell/common/tests/sun_solaris_local_compound_nameref001.sh =================================================================== --- src/lib/libshell/common/tests/sun_solaris_local_compound_nameref001.sh (revision 0) +++ src/lib/libshell/common/tests/sun_solaris_local_compound_nameref001.sh (revision 1122) @@ -0,0 +1,66 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# name reference test #001 +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +integer Errors=0 + +function function2 +{ + nameref v=$1 + + v.x=19 + v.y=20 +} + +function function1 +{ + typeset compound_var=() + + function2 compound_var + + printf "x=%d, y=%d\n" compound_var.x compound_var.y +} + +x="$(function1)" + +[[ "$x" != 'x=19, y=20' ]] && err_exit "expected 'x=19, y=20', got '${x}'" + +exit $((Errors)) +# EOF. Index: src/lib/libshell/common/tests/timetype.sh =================================================================== --- src/lib/libshell/common/tests/timetype.sh (revision 0) +++ src/lib/libshell/common/tests/timetype.sh (revision 1122) @@ -0,0 +1,76 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2008 AT&T Intellectual Property # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +typeset -T Time_t=( + integer .=-1 + _='%F+%H:%M' + get() + { + if (( _ < 0 )) + then .sh.value=${ printf "%(${_._})T" now ;} + else .sh.value=${ printf "%(${_._})T" "#$((_))" ;} + fi + } + set() + { + .sh.value=${ printf "%(%#)T" "${.sh.value}";} + } +) + +d=$(printf "%(%F+%H:%M)T" now) +integer s=$(printf "%(%#)T" "$d") +Time_t t=$d +[[ $t == "$d" ]] || err_exit 'printf %T and Time_t are different' +(( t == s )) || err_exit 'numerical Time_t not correct' +t._='%#' +[[ $t == $s ]] || err_exit 'setting _ to %# not getting correct results' +unset t +Time_t tt=(yesterday today tomorrow) +tt[3]=2pm +[[ ${!tt[@]} == '0 1 2 3' ]] || err_exit 'indexed array subscript names not correct' +[[ ${tt[0]} == *+00:00 ]] || err_exit 'tt[0] is not yesterday' +[[ ${tt[1]} == *+00:00 ]] || err_exit 'tt[1] is not today' +[[ ${tt[2]} == *+00:00 ]] || err_exit 'tt[2] is not tomorrow' +[[ ${tt[3]} == *+14:00 ]] || err_exit 'tt[0] is not 2pm' +(( (tt[1] - tt[0] ) == 24*3600 )) || err_exit 'today-yesterday not one day' +(( (tt[2] - tt[1] ) == 24*3600 )) || err_exit 'tomorrow-today not one day' +(( (tt[3] - tt[1] ) == 14*3600 )) || err_exit '2pm is not 14 hours' +unset tt +Time_t tt=([yesterday]=yesterday [today]=today [tomorrow]=tomorrow) +tt[2pm]=2pm +[[ ${tt[yesterday]} == *+00:00 ]] || err_exit 'tt[yesterday] is not yesterday' +[[ ${tt[today]} == *+00:00 ]] || err_exit 'tt[today] is not today' +[[ ${tt[tomorrow]} == *+00:00 ]] || err_exit 'tt[tomorrow] is not tomorrow' +[[ ${tt[2pm]} == *+14:00 ]] || err_exit 'tt[2pm] is not 2pm' +(( (tt[today] - tt[yesterday] ) == 24*3600 )) || err_exit 'today-yesterday not one day' +(( (tt[tomorrow] - tt[today] ) == 24*3600 )) || err_exit 'tomorrow-today not one day' +(( (tt[2pm] - tt[today] ) == 14*3600 )) || err_exit '2pm is not 14 hours' +unset tt +exit $Errors Index: src/lib/libshell/common/tests/tilde.sh =================================================================== --- src/lib/libshell/common/tests/tilde.sh (revision 974) +++ src/lib/libshell/common/tests/tilde.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # Index: src/lib/libshell/common/tests/io.sh =================================================================== --- src/lib/libshell/common/tests/io.sh (revision 974) +++ src/lib/libshell/common/tests/io.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -229,6 +229,17 @@ [[ $REPLY == *WWWWW* ]] || err_exit '<# not working for pipes' else err_exit "/tmp/seek$$: cannot open for reading" fi +command exec 3<&- || 'cannot close 3' +for ((i=0; i < 62; i++)) +do printf "%.39c\n" ${x:i:1} +done > /tmp/seek$$ +if command exec {n}<> /tmp/seek$$ +then { command exec {n}<#((EOF)) ;} 2> /dev/null || err_exit '{n}<# not working' + if $SHELL -c '{n}</dev/null' 2> /dev/null + then (( $({n}<#) == 40*62)) || err_exit '$({n}<#) not working' + else err_exit 'not able to parse {n}</dev/null' + fi +fi trap "" EXIT rm -f /tmp/seek$$ $SHELL -ic ' @@ -248,4 +259,22 @@ $SHELL -c "{ > /tmp/io.sh$$.1 ; date;} >&- 2> /dev/null" > /tmp/io.sh$$.2 [[ -s /tmp/io.sh$$.1 || -s /tmp/io.sh$$.2 ]] && err_exit 'commands with standard output closed produce output' $SHELL -c "$SHELL -c ': 3>&1' 1>&- 2>/dev/null" && err_exit 'closed standard output not passed to subshell' +[[ $(cat <<- \EOF | $SHELL + do_it_all() + { + dd 2>/dev/null # not a ksh93 buildin + return $? + } + do_it_all ; exit $? + hello world +EOF) == 'hello world' ]] || err_exit 'invalid readahead on stdin' +$SHELL -c 'exec 3>; /dev/null' 2> /dev/null && err_exit '>; with exec should be an error' +$SHELL -c ': 3>; /dev/null' 2> /dev/null || err_exit '>; not working with at all' +print hello > /tmp/io.sh$$.1 +if ! $SHELL -c "false >; /tmp/io.sh$$.1" 2> /dev/null +then [[ $(</tmp/io.sh$$.1) == hello ]] || err_exit '>; not preserving file on failure' +fi +if ! $SHELL -c "sed -e 's/hello/hello world/' /tmp/io.sh$$.1" >; /tmp/io.sh$$.1 2> /dev/null +then [[ $(</tmp/io.sh$$.1) == 'hello world' ]] || err_exit '>; not updating file on success' +fi exit $((Errors)) Index: src/lib/libshell/common/tests/restricted.sh =================================================================== --- src/lib/libshell/common/tests/restricted.sh (revision 0) +++ src/lib/libshell/common/tests/restricted.sh (revision 1122) @@ -0,0 +1,77 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2008 AT&T Intellectual Property # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +# test restricted shell +Command=${0##*/} +integer Errors=0 +mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" +trap "cd /; rm -rf /tmp/ksh$$" EXIT +pwd=$PWD +case $SHELL in +/*) ;; +*/*) SHELL=$pwd/$SHELL;; +*) SHELL=$(whence "$SHELL");; +esac +function check_restricted +{ + rm -f out + rksh -c "$@" 2> out > /dev/null + grep restricted out > /dev/null 2>&1 +} + +[[ $SHELL != /* ]] && SHELL=$pwd/$SHELL +cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +ln -s $SHELL rksh +PATH=$PWD:$PATH +rksh -c '[[ -o restricted ]]' || err_exit 'restricted option not set' +[[ $(rksh -c 'print hello') == hello ]] || err_exit 'unable to run print' +check_restricted /bin/echo || err_exit '/bin/echo not resticted' +check_restricted ./echo || err_exit './echo not resticted' +check_restricted 'SHELL=ksh' || err_exit 'SHELL asignment not resticted' +check_restricted 'PATH=/bin' || err_exit 'PATH asignment not resticted' +check_restricted 'FPATH=/bin' || err_exit 'FPATH asignment not resticted' +check_restricted 'ENV=/bin' || err_exit 'ENV asignment not resticted' +check_restricted 'print > file' || err_exit '> file not restricted' +> empty +check_restricted 'print <> empty' || err_exit '<> file not restricted' +print 'echo hello' > script +chmod +x ./script +! check_restricted script || err_exit 'script without builtins should run in restricted mode' +check_restricted ./script || err_exit 'script with / in name should not run in restricted mode' +print '/bin/echo hello' > script +! check_restricted script || err_exit 'script with pathnames should run in restricted mode' +print 'echo hello> file' > script +! check_restricted script || err_exit 'script with output redirection should run in restricted mode' +print 'PATH=/bin' > script +! check_restricted script || err_exit 'script with PATH assignment should run in restricted mode' +cat > script <<! +#! $SHELL +print hello +! +! check_restricted 'script;:' || err_exit 'script with #! pathname should run in restricted mode' +! check_restricted 'script' || err_exit 'script with #! pathname should run in restricted mode even if last command in script' +exit $((Errors)) Index: src/lib/libshell/common/tests/variables.sh =================================================================== --- src/lib/libshell/common/tests/variables.sh (revision 974) +++ src/lib/libshell/common/tests/variables.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -27,6 +27,10 @@ Command=${0##*/} integer Errors=0 +unset ss +[[ ${@ss} ]] && err_exit '${@ss} should be empty string when ss is unset' +[[ ${!ss} == ss ]] || err_exit '${!ss} should be ss when ss is unset' +[[ ${#ss} == 0 ]] || err_exit '${#ss} should be 0 when ss is unset' # RANDOM if (( RANDOM==RANDOM || $RANDOM==$RANDOM )) then err_exit RANDOM variable not working @@ -249,7 +253,7 @@ if (( $# !=1 )) then err_exit '"${@-}" not expanding to null string' fi -for i in : % + / 3b '**' '***' '@@' '{' '[' '}' !! '*a' '@a' '$foo' +for i in : % + / 3b '**' '***' '@@' '{' '[' '}' !! '*a' '$foo' do (eval : \${"$i"} 2> /dev/null) && err_exit "\${$i} not an syntax error" done unset IFS @@ -555,4 +559,47 @@ [[ ${x[@]} == '12 8 5 3' ]] || err_exit 'set discipline for indexed array not working correctly' ((SECONDS=3*4)) (( SECONDS < 12 || SECONDS > 12.1 )) && err_exit "SECONDS is $SECONDS and should be close to 12" +unset a +function a.set +{ + print -r -- "${.sh.name}=${.sh.value}" +} +[[ $(a=1) == a=1 ]] || err_exit 'set discipline not working in subshell assignment' +[[ $(a=1 :) == a=1 ]] || err_exit 'set discipline not working in subshell command' + +unset r v x +path=$PATH +x=foo +for v in EDITOR VISUAL OPTIND CDPATH FPATH PATH ENV LINENO RANDOM SECONDS _ +do nameref r=$v + unset $v + if ( $SHELL -c "unset $v; : \$$v" ) 2>/dev/null + then [[ $r ]] && print -u2 "unset $v failed -- expected '', got '$r'" + r=$x + [[ $r == $x ]] || print -u2 "$v=$x failed -- expected '$x', got '$r'" + else print -u2 "unset $v; : \$$v failed" + fi +done +for v in LC_ALL LC_CTYPE LC_MESSAGES LC_COLLATE LC_NUMERIC +do nameref r=$v + unset $v + [[ $r ]] && print -u2 "unset $v failed -- expected '', got '$r'" + d=$($SHELL -c "$v=$x" 2>&1) + [[ $d ]] || print -u2 "$v=$x failed -- expected locale diagnostic" + ( r=$x; [[ ! $r ]] ) 2>/dev/null || print -u2 "$v=$x failed -- expected ''" + ( r=C; r=$x; [[ $r == C ]] ) 2>/dev/null || print -u2 "$v=C; $v=$x failed -- expected 'C'" +done +PATH=$path +[[ ${.sh.subshell} == 0 ]] || err_exit '${.sh.subshell} should be 0' +( + [[ ${.sh.subshell} == 1 ]] || err_exit '${.sh.subshell} should be 1' + ( + [[ ${.sh.subshell} == 2 ]] || err_exit '${.sh.subshell} should be 2' + ) +) + +set -- {1..32768} +(( $# == 32768 )) || err_exit "\$# failed -- expected 32768, got $#" +set -- + exit $((Errors)) Index: src/lib/libshell/common/tests/heredoc.sh =================================================================== --- src/lib/libshell/common/tests/heredoc.sh (revision 974) +++ src/lib/libshell/common/tests/heredoc.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # Index: src/lib/libshell/common/tests/exit.sh =================================================================== --- src/lib/libshell/common/tests/exit.sh (revision 974) +++ src/lib/libshell/common/tests/exit.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -78,4 +78,5 @@ fi cd ~- || err_exit "cd back failed" rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" +$SHELL -c 'builtin -f cmd getconf; getconf --"?-version"; exit 0' >/dev/null 2>&1 || err_exit 'ksh plugin exit failed -- was ksh built with CCFLAGS+=$(CC.EXPORT.DYNAMIC)?' exit $((Errors)) Index: src/lib/libshell/common/tests/statics.sh =================================================================== --- src/lib/libshell/common/tests/statics.sh (revision 0) +++ src/lib/libshell/common/tests/statics.sh (revision 1122) @@ -0,0 +1,104 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2008 AT&T Intellectual Property # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit2 +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +function testfunc +{ + integer line_number=$1 + typeset cmd="$2" + typeset expected_output="$3" + typeset output + + output="$($SHELL -c "${cmd}" 2>&1 )" + + [[ "${output}" != "${expected_output}" ]] && err_exit2 ${line_number} "${output} != ${expected_output}" +} +alias testfunc='testfunc $LINENO' +alias err_exit='err_exit2 $LINENO' + +Command=${0##*/} +integer Errors=0 + +# string +testfunc '(function l { typeset -S x ; x+="#" ; $1 && print "$x" ; } ; l false ; l false ; l true)' "###" +testfunc 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false ; l false ; l true' ">###" +testfunc 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false ; (l false) ; l true' ">##" +testfunc 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false; ( ulimit -c 0 ; l false) ; l true' ">##" + +# integer +testfunc '(function l { typeset -S -i x ; x+=1 ; $1 && print "$x" ; } ; l false ; l false ; l true )' "3" +testfunc '(function l { typeset -S -i x ; x+=1 ; $1 && print "$x" ; } ; l false ; (l false) ; l true )' "2" + +# float +testfunc '(function l { float -S x=0.5 ; (( x+=.5 )) ; $1 && print "$x" ; } ; l false ; l false ; l true )' "2" +testfunc '(function l { float -S x=0.5 ; (( x+=.5 )) ; $1 && print "$x" ; } ; l false ; (l false) ; l true )' "1.5" + +# compound variable +[[ "${ + function l + { + typeset -S s=( a=0 b=0 ) + + (( s.a++, s.b++ )) + + $1 && printf 'a=%d, b=%d\n' s.a s.b + } + l false ; l false ; l true +}" != "a=3, b=3" ]] && err_exit "static compound var failed" + + +# array variable +[[ "$( + function ar + { + typeset -a -S s=( "hello" ) + + s+=( "an element" ) + + $1 && { printf '%s' "${s[@]}" ; printf '\n' ; } + } + ar false ; ar false ; ar true +)" != "helloan elementan elementan element" ]] && err_exit "static array var failed" + + +# Test visibilty of "global" vs. "static" variables. if we have a "static" variable in a +# function and "unset" it we should see a global variable with the same +# name, right ? +integer hx=5 +function test_hx_scope +{ + integer -S hx=9 + $2 && unset hx + $1 && printf "hx=%d\n" hx +} +test_hx_scope false false +test_hx_scope false false +# first test the "unset" call in a $(...) subshell... +[[ "$( test_hx_scope true true )" != "hx=5" ]] && err_exit "can't see global variable hx after unsetting static variable hx" +# ... end then test whether the value has changed. +[[ "${ test_hx_scope true false }" != "hx=9" ]] && err_exit "hx variable somehow changed" + +exit $((Errors)) + Index: src/lib/libshell/common/tests/sun_solaris_vartree001.sh =================================================================== --- src/lib/libshell/common/tests/sun_solaris_vartree001.sh (revision 0) +++ src/lib/libshell/common/tests/sun_solaris_vartree001.sh (revision 1122) @@ -0,0 +1,193 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# variable tree test #001 +# Propose of this test is whether ksh93 crashes or not - ast-ksh.2008-05-14 +# crashes like this when running this test: +# +# program terminated by signal ILL (illegal opcode) +# 0xffffffffffffffff: <bad address 0xffffffffffffffff> +# Current function is nv_diropen +# 123 dp->hp = (Namval_t*)dtprev(dp->root,&fake); +# (dbx) where +# [1] 0x100381e80(0x100381e80, 0xffffffff7fffe690, 0x10, 0x61, 0x0, 0x100381ec9), at 0x100381e80 +# =>[2] nv_diropen(np = (nil), name = 0x100381ebc "mysrcdata"), line 123 in "nvtree.c" +# [3] walk_tree(np = 0x1003809e0, dlete = 524289), line 743 in "nvtree.c" +# [4] put_tree(np = 0x1003809e0, val = (nil), flags = 524289, fp = 0x100381db0), line 814 in "nvtree.c" +# [5] nv_putv(np = 0x1003809e0, value = (nil), flags = 524289, nfp = 0x100381db0), line 141 in "nvdisc.c" +# [6] _nv_unset(np = 0x1003809e0, flags = 524289), line 1976 in "name.c" +# [7] table_unset(shp = 0x10033e900, root = 0x100380900, flags = 524289, oroot = 0x100360980), line 1902 in "name.c" +# [8] sh_unscope(shp = 0x10033e900), line 2711 in "name.c" +# [9] sh_funscope(argn = 1, argv = 0x10035e680, fun = (nil), arg = 0xffffffff7ffff118, execflg = 4), line 2470 in "xec.c" +# [10] sh_funct(np = 0x100380860, argn = 1, argv = 0x10035e680, envlist = (nil), execflg = 4), line 2528 in "xec.c" +# [11] sh_exec(t = 0x10035e620, flags = 4), line 1032 in "xec.c" +# [12] exfile(shp = 0x10033e900, iop = 0x100379a20, fno = 10), line 589 in "main.c" +# [13] sh_main(ac = 2, av = 0xffffffff7ffffa08, userinit = (nil)), line 364 in "main.c" +# [14] main(argc = 2, argv = 0xffffffff7ffffa08), line 46 in "pmain.c" +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +integer Errors=0 + + +function build_tree +{ +#set -o errexit -o xtrace + typeset index + typeset s + typeset i + typeset dummy + typeset a b c d e f + + nameref dest_tree="$1" # destination tree + nameref srcdata="$2" # source data + typeset tree_mode="$3" # mode to define the type of leads + + typeset -A dest_tree.l1 + + for index in "${!srcdata.hashnodes[@]}" ; do + nameref node=srcdata.hashnodes["${index}"] + + for i in "${node.xlfd[@]}" ; do + IFS='-' read dummy a b c d e f <<<"$i" + + if [[ "$a" == "" ]] ; then + a="$dummy" + fi + + [[ "$a" == "" ]] && a='-' + [[ "$b" == "" ]] && b='-' + [[ "$c" == "" ]] && c='-' + + if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then + #if ! (unset dest_tree.l1["$a"]) ; then + typeset -A dest_tree.l1["$a"].l2 + fi + + if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then + #if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3 + fi + + if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries + fi + + #dest_tree.l1["$a"].l2["$b"].l3["$c"].entries+=( "$index" ) + typeset new_index + if [[ "${tree_mode}" == "leaf_name" ]] ; then + new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) + else + new_index="${node.name}" + + # skip if the leaf node already exists + if [[ "${dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}]}" != "" ]] ; then + continue + fi + fi + + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" + done + done + + return 0 +} + +function add_tree_leaf +{ + nameref tree_leafnode="$1" + nameref data_node=srcdata.hashnodes["$2"] + typeset add_mode="$3" + + case "${add_mode}" in + "leaf_name") + tree_leafnode="${data_node.name}" + return 0 + ;; + "leaf_compound") + tree_leafnode=( + typeset name="${data_node.name}" + typeset -a filenames=( "${data_node.filenames[@]}" ) + typeset -a comments=( "${data_node.comments[@]}" ) + typeset -a xlfd=( "${data_node.xlfd[@]}" ) + ) + return 0 + ;; + *) + print -u2 -f "ERROR: Unknown mode %s in add_tree_leaf\n" "${add_mode}" + return 1 + ;; + esac + + # not reached + return 1 +} + +function main +{ + typeset mysrcdata=( + typeset -A hashnodes=( + [abcd]=( + name='abcd' + typeset -a xlfd=( + '-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific' + ) + typeset -a comments=( + 'comment 1' + 'comment 2' + 'comment 3' + ) + typeset -a filenames=( + '/home/foo/abcd_1' + '/home/foo/abcd_2' + '/home/foo/abcd_3' + ) + ) + ) + ) + + mytree=() + build_tree mytree mysrcdata leaf_compound +# (( $(print -r -- "$mytree" | wc -l) > 10 )) || err_exit "Compound tree too small." +} + +main + +exit $((Errors)) +# EOF: Index: src/lib/libshell/common/tests/sun_solaris_builtin_sum.sh =================================================================== --- src/lib/libshell/common/tests/sun_solaris_builtin_sum.sh (revision 0) +++ src/lib/libshell/common/tests/sun_solaris_builtin_sum.sh (revision 1122) @@ -0,0 +1,95 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# Test whether the ksh93/libcmd sum builtin is compatible to Solaris/SysV +# /usr/bin/sum +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +typeset x + +builtin sum || err_exit "sum builtin not found" + +# Basic tests +x="$(print 'hello' | /usr/bin/sum)" +[[ "$x" == "542 1" ]] || err_exit "print 'hello' | /usr/bin/sum did not return 542 1" + +[[ "$(print 'hello' | /usr/bin/sum)" == "$(print 'hello' | sum)" ]] || err_exit "sum hello != /usr/bin/sum hello" +[[ "$(print 'fish' | /usr/bin/sum)" == "$(print 'fish' | sum)" ]] || err_exit "sum fish != /usr/bin/sum fish" +[[ "$(print '12345' | /usr/bin/sum)" == "$(print '12345' | sum)" ]] || err_exit "sum 12345 != /usr/bin/sum 12345" +[[ "$(print '\n\r\n \v' | /usr/bin/sum)" == "$(print '\n\r\n \v' | sum)" ]] || err_exit "sum spaces != /usr/bin/sum spaces" + +# Test some binary files... +x="/usr/bin/ls" +[[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" +[[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" + +x="/usr/bin/chmod" +[[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" +[[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" + +x="/usr/bin/tee" +[[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" +[[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" + +x="/usr/bin/grep" +[[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" +[[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" + +x="/usr/bin/egrep" +[[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" +[[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" + +x="/usr/bin/awk" +[[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" +[[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" + +x="/usr/bin/nawk" +[[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" +[[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" + +x="/usr/bin/ksh" +[[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" +[[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" + +x="/usr/bin/sh" +[[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" +[[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" + + +exit $((Errors)) Index: src/lib/libshell/common/tests/sun_solaris_vartree003.sh =================================================================== --- src/lib/libshell/common/tests/sun_solaris_vartree003.sh (revision 0) +++ src/lib/libshell/common/tests/sun_solaris_vartree003.sh (revision 1122) @@ -0,0 +1,197 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# variable tree test #003 +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +integer Errors=0 + +function example_tree +{ +cat <<EOF +( + typeset -A l1=( + [adobe]=( + typeset -A l2=( + [avantgarde]=( + typeset -A l3=( + [demi]=( + typeset -A entries=( + [182c069a485316b1bc7ae001c04c7835]=( + typeset -a comments=( + FONT + -adobe-avantgarde-demi-r-normal--199-120-1200-1200-p-1130-iso8859-1 + COPYRIGHT + 'Copyright Notice not available' + RAW_PIXELSIZE + RAW_POINTSIZE + -- + section + diaeresis + copyright + ordfeminine + guillemotleft + ) + typeset -a filenames=( + X11Rx/R6.4/xc/programs/Xserver/XpConfig/C/print/models/SPSPARC2/fonts/AvantGarde-Demi.pmf + ) + md5sum=182c069a485316b1bc7ae001c04c7835 + typeset -a xlfd=( + -adobe-avantgarde-demi-r-normal--199-120-1200-1200-p-1130-iso8859-1 + ) + ) + [7db15b51965d8fe1f1c55fcb101d7616]=( + typeset -a comments=( + FONT + -adobe-avantgarde-demi-i-normal--199-120-1200-1200-p-1130-iso8859-1 + COPYRIGHT + 'Copyright Notice not available' + RAW_PIXELSIZE + RAW_POINTSIZE + -- + section + diaeresis + copyright + ordfeminine + guillemotleft + ) + typeset -a filenames=( + X11Rx/R6.4/xc/programs/Xserver/XpConfig/C/print/models/SPSPARC2/fonts/AvantGarde-DemiOblique.pmf + ) + md5sum=7db15b51965d8fe1f1c55fcb101d7616 + typeset -a xlfd=( + -adobe-avantgarde-demi-i-normal--199-120-1200-1200-p-1130-iso8859-1 + ) + ) + [a37e4a4a5035abf6f294d830fbd9e775]=( + typeset -a comments=( + FONT + -adobe-avantgarde-demi-r-normal--422-120-2540-2540-p-2395-iso8859-1 + COPYRIGHT + 'Copyright (c) 1985, 1987, 1989, 1990, 1991 Adobe Systems Incorporated. All Rights Reserved.ITC Avant Garde Gothic is a registered trademark of International Typeface Corporation.' + RAW_PIXELSIZE + RAW_POINTSIZE + -- + section + diaeresis + copyright + ordfeminine + guillemotleft + ) + typeset -a filenames=( + fox-gate/XW_NV/open-src/tarballs/xorg-server-1.3.0.0/hw/xprint/config/C/print/models/PSdefault/fonts/AvantGarde-Demi.pmf + ) + md5sum=a37e4a4a5035abf6f294d830fbd9e775 + typeset -a xlfd=( + -adobe-avantgarde-demi-r-normal--422-120-2540-2540-p-2395-iso8859-1 + ) + ) + [da3d6d94fcf759b95c7f829ce5619374]=( + typeset -a comments=( + FONT + -adobe-avantgarde-demi-i-normal--422-120-2540-2540-p-2395-iso8859-1 + COPYRIGHT + 'Copyright (c) 1985, 1987, 1989, 1990, 1991 Adobe Systems Incorporated. All Rights Reserved.ITC Avant Garde Gothic is a registered trademark of International Typeface Corporation.' + RAW_PIXELSIZE + RAW_POINTSIZE + -- + section + diaeresis + copyright + ordfeminine + guillemotleft + ) + typeset -a filenames=( + fox-gate/XW_NV/open-src/tarballs/xorg-server-1.3.0.0/hw/xprint/config/C/print/models/PSdefault/fonts/AvantGarde-DemiOblique.pmf + ) + md5sum=da3d6d94fcf759b95c7f829ce5619374 + typeset -a xlfd=( + -adobe-avantgarde-demi-i-normal--422-120-2540-2540-p-2395-iso8859-1 + ) + ) + ) + ) + ) + ) + ) + ) + ) +) +EOF +} + +function main +{ + set -o errexit + + typeset xlfd_tree=() + typeset -A xlfd_tree.l1 + + eval "xlfd_tree=$( example_tree )" + + typeset i j k l fn + + # filter chain begin + for i in "${!xlfd_tree.l1[@]}" ; do + for j in "${!xlfd_tree.l1["$i"].l2[@]}" ; do + for k in "${!xlfd_tree.l1["$i"].l2["$j"].l3[@]}" ; do + nameref vndnode=xlfd_tree.l1["$i"].l2["$j"].l3["$k"] + + for l in "${!vndnode.entries[@]}" ; do + nameref node=vndnode.entries["$l"] + + for fn in "${node.filenames[@]}" ; do + if [[ "${fn}" != ~(E)x-re_gate_XW_NV_MWS ]] ; then + unset "${!node}" + break + fi + done + done + done + done + done + + # filter chain end + + return 0 +} + +main || ((Errors++)) + +exit $((Errors)) +# EOF. Index: src/lib/libshell/common/tests/nameref.sh =================================================================== --- src/lib/libshell/common/tests/nameref.sh (revision 974) +++ src/lib/libshell/common/tests/nameref.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -226,4 +226,56 @@ } i=foo [[ $(fun $i) == hi ]] || err_exit 'nameref for compound variable with in function name of caller fails' +unset -n foo bar +typeset -A foo +foo[x.y]=(x=3 y=4) +nameref bar=foo[x.y] +[[ ${bar.x} == 3 ]] || err_exit 'nameref to subscript containing . fails' +[[ ${!bar} == 'foo[x.y]' ]] || err_exit '${!var} not correct for nameref to an array instance' +typeset +n bar +nameref bar=foo +[[ ${!bar} == foo ]] || err_exit '${!var} not correct for nameref to array variable' +$SHELL -c 'function bar { nameref x=foo[++];};typeset -A foo;bar' 2> /dev/null ||err_exit 'nameref of associative array tries to evaluate subscript' +i=$($SHELL -c 'nameref foo=bar; bar[2]=(x=3 y=4); nameref x=foo[2].y;print -r -- $x' 2> /dev/null) +[[ $i == 4 ]] || err_exit 'creating reference from subscripted variable whose name is a reference failed' +[[ $($SHELL 2> /dev/null <<- '+++EOF' + function bar + { + nameref x=$1 + print -r -- "$x" + } + function foo + { + typeset var=( foo=hello) + bar var + } + foo ++++EOF +) == *foo=hello* ]] || err_exit 'unable to display compound variable from name reference of local variable' +#set -x +for c in '=' '[' ']' '\' "'" '"' '<' '=' '(' +do [[ $($SHELL 2> /dev/null <<- ++EOF++ + x;i=\\$c;typeset -A a; a[\$i]=foo;typeset -n x=a[\$i]; print "\$x" + ++EOF++ +) != foo ]] && err_exit 'nameref x=[$c] '"not working for c=$c" +done +unset -n foo x +unset foo x +typeset -A foo +nameref x=foo[xyz] +foo[xyz]=ok +[[ $x == ok ]] || err_exit 'nameref to unset subscript not working' +function function2 +{ + nameref v=$1 + v.x=19 v.y=20 +} +function function1 +{ + typeset compound_var=() + function2 compound_var + printf "x=%d, y=%d\n" compound_var.x compound_var.y +} +x="$(function1)" +[[ "$x" != 'x=19, y=20' ]] && err_exit "expected 'x=19, y=20', got '${x}'" exit $((Errors)) Index: src/lib/libshell/common/tests/select.sh =================================================================== --- src/lib/libshell/common/tests/select.sh (revision 974) +++ src/lib/libshell/common/tests/select.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # Index: src/lib/libshell/common/tests/substring.sh =================================================================== --- src/lib/libshell/common/tests/substring.sh (revision 974) +++ src/lib/libshell/common/tests/substring.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -166,6 +166,21 @@ if [[ "${x//\[(*)\]/\{\1\}}" != {123}def ]] then err_exit 'closing brace escape not working' fi +xx=%28text%29 +if [[ ${xx//%28/abc\)} != 'abc)text%29' ]] +then err_exit '${xx//%28/abc\)} not working' +fi +xx='a:b' +str='(){}[]*?|&^%$#@l' +for ((i=0 ; i < ${#str}; i++)) +do [[ $(eval print -r -- \"\${xx//:/\\${str:i:1}}\") == "a${str:i:1}b" ]] || err_exit "substitution of \\${str:i:1}} failed" + [[ $(eval print -rn -- \"\${xx//:/\'${str:i:1}\'}\") == "a${str:i:1}b" ]] || err_exit "substitution of '${str:i:1}' failed" + [[ $(eval print -r -- \"\${xx//:/\"${str:i:1}\"}\") == "a${str:i:1}b" ]] || err_exit "substitution of \"${str:i:1}\" failed" +done +[[ ${xx//:/\\n} == 'a\nb' ]] || err_exit "substituion of \\\\n failed" +[[ ${xx//:/'\n'} == 'a\nb' ]] || err_exit "substituion of '\\n' failed" +[[ ${xx//:/"\n"} == 'a\nb' ]] || err_exit "substituion of \"\\n\" failed" +[[ ${xx//:/$'\n'} == $'a\nb' ]] || err_exit "substituion of \$'\\n' failed" unset foo foo=one/two/three if [[ ${foo//'/'/_} != one_two_three ]] @@ -270,6 +285,10 @@ a='\[abc @(*) def\]' b='[abc 123 def]' [[ ${b//$a/\1} == 123 ]] || err_exit "\${var/pattern} not working with \[ in pattern" +unset foo +foo='(win32.i386) ' +[[ ${foo/'('/'(x11-'} == '(x11-win32.i386) ' ]] || err_exit "\${var/pattern} not working with ' in pattern" +$SHELL -c $'v=\'$(hello)\'; [[ ${v//\'$(\'/-I\'$(\'} == -I"$v" ]]' 2> /dev/null || err_exit "\${var/pattern} not working with \$( as pattern" unset X $SHELL -c '[[ ! ${X[@]:0:300} ]]' 2> /dev/null || err_exit '${X[@]:0:300} with X undefined fails' $SHELL -c '[[ ${@:0:300} == "$0" ]]' 2> /dev/null || err_exit '${@:0:300} with no arguments fails' @@ -501,4 +520,52 @@ fi { $SHELL -c 'unset x;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is not set' { $SHELL -c 'x=;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is null' + +# subject pattern result # +set -- \ + 'a$z' '~(E)([$]|#)' 'a($)z' \ + 'a#z' '~(E)([$]|#)' 'a(#)z' \ + 'a$z' '~(Elr)([$]|#)' 'a$z' \ + 'a#z' '~(Elr)([$]|#)' 'a#z' \ + 'a$' '~(E)([$]|#)' 'a($)' \ + 'a#' '~(E)([$]|#)' 'a(#)' \ + 'a$' '~(Elr)([$]|#)' 'a$' \ + 'a#' '~(Elr)([$]|#)' 'a#' \ + '$z' '~(E)([$]|#)' '($)z' \ + '#z' '~(E)([$]|#)' '(#)z' \ + '$z' '~(Elr)([$]|#)' '$z' \ + '#z' '~(Elr)([$]|#)' '#z' \ + '$' '~(E)([$]|#)' '($)' \ + '#' '~(E)([$]|#)' '(#)' \ + '$' '~(Elr)([$]|#)' '($)' \ + '#' '~(Elr)([$]|#)' '(#)' \ + 'a$z' '~(E)(\$|#)' 'a$z()' \ + 'a$z' '~(E)(\\$|#)' 'a$z' \ + 'a$z' '~(E)(\\\$|#)' 'a($)z' \ + 'a#z' '~(E)(\\\$|#)' 'a(#)z' \ + 'a$z' '~(Elr)(\\\$|#)' 'a$z' \ + 'a#z' '~(Elr)(\\\$|#)' 'a#z' \ + 'a$' '~(E)(\\\$|#)' 'a($)' \ + 'a#' '~(E)(\\\$|#)' 'a(#)' \ + 'a$' '~(Elr)(\\\$|#)' 'a$' \ + 'a#' '~(Elr)(\\\$|#)' 'a#' \ + '$z' '~(E)(\\\$|#)' '($)z' \ + '#z' '~(E)(\\\$|#)' '(#)z' \ + '$z' '~(Elr)(\\\$|#)' '$z' \ + '#z' '~(Elr)(\\\$|#)' '#z' \ + '$' '~(E)(\\\$|#)' '($)' \ + '#' '~(E)(\\\$|#)' '(#)' \ + '$' '~(Elr)(\\\$|#)' '($)' \ + '#' '~(Elr)(\\\$|#)' '(#)' \ +# do not delete this line # +unset i o +while (( $# >= 3 )) +do i=$1 + eval o=\${i/$2/\\\(\\\1\\\)} + if [[ "$o" != "$3" ]] + then err_exit "i='$1'; \${i/$2/\\(\\1\\)} failed -- got '$o', expected '$3'" + fi + shift 3 +done + exit $((Errors)) Index: src/lib/libshell/common/tests/basic.sh =================================================================== --- src/lib/libshell/common/tests/basic.sh (revision 974) +++ src/lib/libshell/common/tests/basic.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -28,6 +28,27 @@ # test basic file operations like redirection, pipes, file expansion Command=${0##*/} integer Errors=0 +set -- \ + go+r 0000 \ + go-r 0044 \ + ug=r 0330 \ + go+w 0000 \ + go-w 0022 \ + ug=w 0550 \ + go+x 0000 \ + go-x 0011 \ + ug=x 0660 \ + go-rx 0055 \ + uo-wx 0303 \ + ug-rw 0660 \ + o= 0007 +while (( $# >= 2 )) +do umask 0 + umask $1 + g=$(umask) + [[ $g == $2 ]] || err_exit "umask 0; umask $1 failed -- expected $2, got $g" + shift 2 +done umask u=rwx,go=rx || err_exit "umask u=rws,go=rx failed" if [[ $(umask -S) != u=rwx,g=rx,o=rx ]] then err_exit 'umask -S incorrect' @@ -37,6 +58,13 @@ pwd=$PWD [[ $SHELL != /* ]] && SHELL=$pwd/$SHELL cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +um=$(umask -S) +( umask 0777; > foobar ) +rm -f foobar +> foobar +[[ -r foobar ]] || err_exit 'umask not being restored after subshell' +umask "$um" +rm -f foobar # optimizer bug test > foobar for i in 1 2 @@ -285,7 +313,7 @@ (( $# == 2 )) || err_exit "$# jobs not reported -- 2 expected" } foo -[[ $( (trap 'print alarm' ALRM; sleep 4) & sleep 2; kill -ALRM $!) == alarm ]] || err_exit 'ALRM signal not working' +[[ $( (trap 'print alarm' ALRM; sleep 4) & sleep 2; kill -ALRM $!; sleep 2) == alarm ]] || err_exit 'ALRM signal not working' [[ $($SHELL -c 'trap "" HUP; $SHELL -c "(sleep 2;kill -HUP $$)& sleep 4;print done"') != done ]] && err_exit 'ignored traps not being ignored' [[ $($SHELL -c 'o=foobar; for x in foo bar; do (o=save);print $o;done' 2> /dev/null ) == $'foobar\nfoobar' ]] || err_exit 'for loop optimization subshell bug' command exec 3<> /dev/null @@ -330,7 +358,51 @@ print 'print -- $0' >> /tmp/ksh$$x chmod +x /tmp/ksh$$x [[ $(/tmp/ksh$$x) == /tmp/ksh$$x ]] || err_exit "\$0 is $0 instead of /tmp/ksh$$x" +cat > /tmp/ksh$$x <<- \EOF + myfilter() { x=$(print ok | cat); print -r -- $SECONDS;} + set -o pipefail + sleep 3 | myfilter +EOF +(( $($SHELL /tmp/ksh$$x) > 2.0 )) && err_exit 'command substitution causes pipefail option to hang' rm -f /tmp/ksh$$x exec 3<&- ( typeset -r foo=bar) 2> /dev/null || err_exit 'readonly variables set in a subshell cannot unset' +$SHELL -c 'x=${ print hello;}; [[ $x == hello ]]' 2> /dev/null || err_exit '${ command;} not supported' +$SHELL 2> /dev/null <<- \EOF || err_exit 'multiline ${...} command substituion not supported' + x=${ + print hello + } + [[ $x == hello ]] +EOF +$SHELL 2> /dev/null <<- \EOF || err_exit '${...} command substituion with side effects not supported ' + y=bye + x=${ + y=hello + print hello + } + [[ $y == $x ]] +EOF +$SHELL 2> /dev/null <<- \EOF || err_exit 'nested ${...} command substituion not supported' + x=${ + print ${ print hello;} $(print world) + } + [[ $x == 'hello world' ]] +EOF +$SHELL 2> /dev/null <<- \EOF || err_exit 'terminating } is not a reserved word with ${ command }' + x=${ { print -n } ; print -n hello ; } ; print ' world' } + [[ $x == '}hello world' ]] +EOF + +unset foo +function foo +{ + print bar +} +[[ ${foo} == bar ]] || err_exit '${foo} is not command substitution when foo unset' +[[ ! ${foo[@]} ]] || err_exit '${foo[@]} is not empty when foo is unset' +[[ ! ${foo[3]} ]] || err_exit '${foo[3]} is not empty when foo is unset' +[[ $(print "[${ print foo }]") == '[foo]' ]] || err_exit '${...} not working when } is followed by ]' +[[ $(print "${ print "[${ print foo }]" }") == '[foo]' ]] || err_exit 'nested ${...} not working when } is followed by ]' +unset foo +foo=$(false) > /dev/null && err_exit 'failed command substitution with redirection not returning false' exit $((Errors)) Index: src/lib/libshell/common/tests/subshell.sh =================================================================== --- src/lib/libshell/common/tests/subshell.sh (revision 0) +++ src/lib/libshell/common/tests/subshell.sh (revision 1122) @@ -0,0 +1,93 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2008 AT&T Intellectual Property # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + + +z=() +z.foo=( [one]=hello [two]=(x=3 y=4) [three]=hi) +z.bar[0]=hello +z.bar[2]=world +z.bar[1]=(x=4 y=5) +val='( + typeset -a bar=( + [0]=hello + [2]=world + [1]=( + x=4 + y=5 + ) + ) + typeset -A foo=( + [one]=hello + [three]=hi + [two]=( + x=3 + y=4 + ) + ) +)' +[[ $z == "$val" ]] || err_exit 'compound variable with mixed arrays not working' +z.bar[1]=yesyes +[[ ${z.bar[1]} == yesyes ]] || err_exit 'reassign of index array compound variable fails' +z.bar[1]=(x=12 y=5) +[[ ${z.bar[1]} == $'(\n\tx=12\n\ty=5\n)' ]] || err_exit 'reassign array simple to compound variable fails' +eval val="$z" +( + z.foo[three]=good + [[ ${z.foo[three]} == good ]] || err_exit 'associative array assignment in subshell not working' +) +[[ $z == "$val" ]] || err_exit 'compound variable changes after associative array assignment' +eval val="$z" +( +false + z.foo[two]=ok + [[ ${z.foo[two]} == ok ]] || err_exit 'associative array assignment to compound variable in subshell not working' + z.bar[1]=yes + [[ ${z.bar[1]} == yes ]] || err_exit 'index array assignment to compound variable in subshell not working' +) +[[ $z == "$val" ]] || err_exit 'compound variable changes after associative array assignment' + +x=( + foo=( qqq=abc rrr=def) + bar=( zzz=no rst=fed) +) +eval val="$x" +( + unset x.foo + [[ ${x.foo.qqq} ]] && err_exit 'x.foo.qqq should be unset' + x.foo=good + [[ ${x.foo} == good ]] || err_exit 'x.foo should be good' +) +[[ $x == "$val" ]] || err_exit 'compound variable changes after unset leaves' +unset l +( + l=( a=1 b="BE" ) +) +[[ ${l+foo} != foo ]] || err_exit 'l should be unset' +exit $Errors Index: src/lib/libshell/common/tests/arrays2.sh =================================================================== --- src/lib/libshell/common/tests/arrays2.sh (revision 0) +++ src/lib/libshell/common/tests/arrays2.sh (revision 1122) @@ -0,0 +1,124 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2008 AT&T Intellectual Property # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 +for ((i=0; i < 4; i++ )) +do for ((j=0; j < 5; j++ )) + do a[i][j]=$i$j + done +done +for ((i=0; i < 4; i++ )) +do for ((j=0; j < 5; j++ )) + do [[ ${a[i][j]} == "$i$j" ]] || err_exit "\${a[$i][$j]} != $i$j" + done +done +for ((i=0; i < 4; i++ )) +do j=0;for k in ${a[i][@]} + do [[ $k == "$i$j" ]] || err_exit "\${a[i][@]} != $i$j" + (( j++ )) + done +done +unset a +a=( + ( 00 01 02 03 04 ) + ( 10 11 12 13 14 15) + ( 20 21 22 23 24 ) + ( 30 31 32 33 34 ) +) + +function check +{ + nameref a=$1 + nameref b=a[2] + typeset c=$1 + integer i j + for ((i=0; i < 4; i++ )) + do for ((j=0; j < 5; j++ )) + do [[ ${a[$i][$j]} == "$i$j" ]] || err_exit "\${$c[$i][$j]} != $i$j" + done + done + (( ${#a[@]} == 4 )) || err_exit "\${#$c[@]} not 4" + (( ${#a[0][@]} == 5 )) || err_exit "\${#$c[0][@]} not 5" + (( ${#a[1][@]} == 6 )) || err_exit "\${#$c[1][@]} not 6" + set -s -- ${!a[@]} + [[ ${@} == '0 1 2 3' ]] || err_exit "\${!$c[@]} not 0 1 2 3" + set -s -- ${!a[0][@]} + [[ ${@} == '0 1 2 3 4' ]] || err_exit "\${!$c[0][@]} not 0 1 2 3 4" + set -s -- ${!a[1][@]} + [[ ${@} == '0 1 2 3 4 5' ]] || err_exit "\${!$c[1][@]} not 0 1 2 3 4 5" + [[ $a == 00 ]] || err_exit "\$$c is not 00" + [[ ${a[0]} == 00 ]] || err_exit "\${$a[0]} is not 00" + [[ ${a[0][0]} == 00 ]] || err_exit "${a[0][0]} is not 00" + [[ ${a[0][0][0]} == 00 ]] || err_exit "\${$c[0][0][0]} is not 00" + [[ ${a[0][0][1]} == '' ]] || err_exit "\${$c[0][0][1]} is not empty" + [[ ${b[3]} == 23 ]] || err_exit "${!b}[3] not = 23" +} + +check a +exit + +unset a +typeset -A a +for ((i=0; i < 4; i++ )) +do for ((j=0; j < 5; j++ )) + do a[$i][j]=$i$j + done +done +for ((i=0; i < 4; i++ )) +do for ((j=0; j < 5; j++ )) + do [[ ${a[$i][j]} == "$i$j" ]] || err_exit "\${a[$i][$j]} == $i$j" + done +done +a[1][5]=15 +b=( + [0]=( 00 01 02 03 04 ) + [1]=( 10 11 12 13 14 15) + [2]=( 20 21 22 23 24 ) + [3]=( 30 31 32 33 34 ) +) +check b +[[ ${a[1][@]} == "${b[1][@]}" ]] || err_exit "a[1] not equal to b[1]" +c=( + [0]=( [0]=00 [1]=01 [2]=02 [3]=03 [4]=04 ) + [1]=( [0]=10 [1]=11 [2]=12 [3]=13 [4]=14 [5]=15) + [2]=( [0]=20 [1]=21 [2]=22 [3]=23 [4]=24 ) + [3]=( [0]=30 [1]=31 [2]=32 [3]=33 [4]=34 ) +) +check c +typeset -A d +d[0]=( [0]=00 [1]=01 [2]=02 [3]=03 [4]=04 ) +d[1]=( [0]=10 [1]=11 [2]=12 [3]=13 [4]=14 [5]=15) +d[2]=( [0]=20 [1]=21 [2]=22 [3]=23 [4]=24 ) +d[3]=( [0]=30 [1]=31 [2]=32 [3]=33 [4]=34 ) +check d +unset a b c d +[[ ${a-set} ]] || err_exit "a is set after unset" +[[ ${b-set} ]] || err_exit "b is set after unset" +[[ ${c-set} ]] || err_exit "c is set after unset" +[[ ${d-set} ]] || err_exit "c is set after unset" +exit $((Errors)) Index: src/lib/libshell/common/tests/shtests =================================================================== --- src/lib/libshell/common/tests/shtests (revision 974) +++ src/lib/libshell/common/tests/shtests (revision 1122) @@ -1,24 +1,46 @@ # This program runs ksh regression tests -# shtests [ name=value ... ] a.sh b.sh ... +# shtests [ name=value ... ] [ --all | --compile ] [ --time ] [ a.sh b.sh ... ] unset DISPLAY ENV FIGNORE LANG=C LC_ALL=C +compile=1 +script=1 time=1 +vmdebug=1 while : do case $1 in + -a|--a*)compile=2 + script=2 + ;; + -c|--c*)compile=2 + script= + ;; + -s|--s*)compile= + script=2 + ;; + -t|--not*)time= + ;; + -v|--nov*)vmdebug= + ;; + -*) echo $0: $1: invalid option >&2 + exit 2 + ;; *=*) n=${1%%=*} v=${1#*=} eval $n=\'$v\' export $n ;; - -t|--t*)time= - ;; *) break ;; esac shift done +if [[ ! $vmdebug ]] +then unset VMDEBUG +elif [[ ! $VMDEBUG ]] +then export VMDEBUG=a +fi export LANG LC_ALL PATH PWD SHELL PWD=`pwd` SHELL=${SHELL-ksh} @@ -37,27 +59,71 @@ then PATH=$PATH:/usr/ucb fi PATH=$PATH:$d -if [[ $INSTALLROOT && -r $INSTALLROOT/bin/.paths ]] +if [[ $INSTALLROOT && -r $INSTALLROOT/bin/.paths ]] then PATH=$INSTALLROOT/bin:$PATH fi +if [[ $compile ]] +then SHCOMP=${SHCOMP:-shcomp} + if whence $SHCOMP > /dev/null + then tmp=/tmp/ksh-$$ + trap 'rm -rf $tmp' EXIT + mkdir $tmp || exit + elif [[ $compile != 1 ]] + then echo $0: --compile: $SHCOMP not found >&2 + exit 1 + else compile= + fi +fi +typeset -A tests for i in ${*-*.sh} -do echo test $i begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} - t=$(grep -c err_exit $i) +do t=$(grep -c err_exit $i) if (( $t )) then (( t = $t - 1 )) fi + tests[$i]=$t T=test if (( $t != 1 )) then T=${T}s fi E=error - if $SHELL $i - then echo test $i passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]" - else e=$? - E=error - if (( $e != 1 )) - then E=${E}s + if [[ $script ]] + then echo test $i begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} + if $SHELL $i + then echo test $i passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]" + else e=$? + E=error + if (( $e != 1 )) + then E=${E}s + fi + echo test $i failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]" fi - echo test $i failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]" fi done +if [[ $compile ]] +then for i in ${*-*.sh} + do t=${tests[$i]} + T=test + if (( $t != 1 )) + then T=${T}s + fi + E=error + o=${i##*/} + o=shcomp-${o%.sh}.ksh + echo test $o begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} + E=error + if $SHCOMP $i > $tmp/$o + then if $SHELL $tmp/$o + then echo test $o passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]" + else e=$? + if (( $e != 1 )) + then E=${E}s + fi + echo test $o failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]" + fi + else e=$? + t=1 + T=test + echo test $o failed to compile ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T 1 $E ]" + fi + done +fi Index: src/lib/libshell/common/tests/quoting.sh =================================================================== --- src/lib/libshell/common/tests/quoting.sh (revision 974) +++ src/lib/libshell/common/tests/quoting.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -328,4 +328,10 @@ x=${x:-`id | sed 's/^[^(]*(\([^)]*\)).*/\1/'`} } 2> /dev/null || err_exit 'skipping over `` failed' [[ $x == x ]] || err_exit 'assignment ${x:=`...`} failed' +[[ $($SHELL -c 'print a[') == 'a[' ]] || err_exit "unbalanced '[' in command arg fails" +$SHELL -c $'false && (( `wc -l /dev/null | nawk \'{print $1}\'` > 2 )) && true;:' 2> /dev/null || err_exit 'syntax error with ` in arithmetic expression' +{ $SHELL -c '(( 1`: "{ }"` ))' ;} 2> /dev/null || err_exit 'problem with ` inside (())' +varname=foobarx +x=`print '"\$'${varname}'"'` +[[ $x == '"$foobarx"' ]] || err_exit $'\\$\' not handled correctly inside ``' exit $((Errors)) Index: src/lib/libshell/common/tests/builtins.sh =================================================================== --- src/lib/libshell/common/tests/builtins.sh (revision 974) +++ src/lib/libshell/common/tests/builtins.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -43,9 +43,9 @@ then err_exit "'getopts :r:s var -r' not working" fi OPTIND=1 -getopts :d#u var -d 100 -if [[ $var != d || $OPTARG != 100 ]] -then err_exit "'getopts :d#u var -d 100' not working var=$var" +getopts :d#u OPT -d 16177 +if [[ $OPT != d || $OPTARG != 16177 ]] +then err_exit "'getopts :d#u OPT=d OPTARG=16177' failed -- OPT=$OPT OPTARG=$OPTARG" fi OPTIND=1 while getopts 'ab' option -a -b @@ -128,6 +128,8 @@ if [[ $(eval 'print $0') != $x ]] then err_exit '$0 not correct for eval' fi +$SHELL -c 'read x <<< hello' 2> /dev/null || err_exit 'syntax <<< not recognized' +($SHELL -c 'read x[1] <<< hello') 2> /dev/null || err_exit 'read x[1] not working' unset x readonly x set -- $(readonly) @@ -159,7 +161,7 @@ if [[ $(print -f "%b" "\a\n\v\b\r\f\E\03\\oo") != $'\a\n\v\b\r\f\E\03\\oo' ]] then err_exit 'print -f "%b" not working' fi -if [[ $(print -f "%P" "[^x].*b$") != '*[!x]*b' ]] +if [[ $(print -f "%P" "[^x].*b\$") != '*[!x]*b' ]] then err_exit 'print -f "%P" not working' fi if [[ $(abc: for i in foo bar;do print $i;break abc;done) != foo ]] @@ -184,10 +186,9 @@ if [[ $(trap -p HUP) != 'print HUP' ]] then err_exit '$(trap -p HUP) not working' fi -[[ $($SHELL -c 'trap "print ok" SIGTERM; kill -s SIGTERM $$' 2> /dev/null) == ok - ]] || err_exit 'SIGTERM not recognized' -[[ $($SHELL -c 'trap "print ok" sigterm; kill -s sigterm $$' 2> /dev/null) == ok - ]] || err_exit 'SIGTERM not recognized' +[[ $($SHELL -c 'trap "print ok" SIGTERM; kill -s SIGTERM $$' 2> /dev/null) == ok ]] || err_exit 'SIGTERM not recognized' +[[ $($SHELL -c 'trap "print ok" sigterm; kill -s sigterm $$' 2> /dev/null) == ok ]] || err_exit 'SIGTERM not recognized' +[[ $($SHELL -c '( trap "" TERM);kill $$;print bad' == bad) ]] 2> /dev/null && err_exit 'trap ignored in subshell causes it to be ignored by parent' ${SHELL} -c 'kill -1 -$$' 2> /dev/null [[ $(kill -l $?) == HUP ]] || err_exit 'kill -1 -pid not working' ${SHELL} -c 'kill -1 -$$' 2> /dev/null @@ -349,6 +350,34 @@ if [[ $($SHELL -c $'printf \'%2$s %1$s\n\' world hello') != 'hello world' ]] then err_exit 'printf %2$s %1$s not working' fi +val=$(( 'C' )) +set -- \ + "'C" $val 0 \ + "'C'" $val 0 \ + '"C' $val 0 \ + '"C"' $val 0 \ + "'CX" $val 1 \ + "'CX'" $val 1 \ + "'C'X" $val 1 \ + '"CX' $val 1 \ + '"CX"' $val 1 \ + '"C"X' $val 1 +while (( $# >= 3 )) +do arg=$1 val=$2 code=$3 + shift 3 + for fmt in '%d' '%g' + do out=$(printf "$fmt" "$arg" 2>/dev/null) + err=$(printf "$fmt" "$arg" 2>&1 >/dev/null) + printf "$fmt" "$arg" >/dev/null 2>&1 + ret=$? + [[ $out == $val ]] || err_exit "printf $fmt $arg failed -- got $out, expected $val" + if (( $code )) + then [[ $err ]] || err_exit "printf $fmt $arg failed -- error message expected" + else [[ $err ]] && err_exit "$err: printf $fmt $arg failed -- error message not expected" + fi + (( $ret == $code )) || err_exit "printf $fmt $arg failed -- got exit code $ret, expected $code" + done +done ((n=0)) ((n++)); ARGC[$n]=1 ARGV[$n]="" ((n++)); ARGC[$n]=2 ARGV[$n]="-a" @@ -365,6 +394,16 @@ then err_exit "\$OPTIND after getopts loop incorrect -- got $OPTIND, expected ${ARGC[$i]}" fi done +options=ab:c +optarg=foo +set -- -a -b $optarg -c bar +while getopts $options opt +do case $opt in + a|c) [[ $OPTARG ]] && err_exit "getopts $options \$OPTARG for flag $opt failed, expected \"\", got \"$OPTARG\"" ;; + b) [[ $OPTARG == $optarg ]] || err_exit "getopts $options \$OPTARG failed -- \"$optarg\" expected, got \"$OPTARG\"" ;; + *) err_exit "getopts $options failed -- got flag $opt" ;; + esac +done unset a { read -N3 a; read -N1 b;} <<! abcdefg @@ -448,4 +487,7 @@ elif (( total_t < reps * delay )) then err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too fast" fi +$SHELL -c 'sleep $(printf "%a" .95)' 2> /dev/null || err_exit "sleep doesn't except %a format constants" +$SHELL -c 'test \( ! -e \)' 2> /dev/null ; [[ $? == 1 ]] || err_exit 'test \( ! -e \) not working' +[[ $(ulimit) == "$(ulimit -fS)" ]] || err_exit 'ulimit is not the same as ulimit -fS' exit $((Errors)) Index: src/lib/libshell/common/tests/vartree1.sh =================================================================== --- src/lib/libshell/common/tests/vartree1.sh (revision 0) +++ src/lib/libshell/common/tests/vartree1.sh (revision 1122) @@ -0,0 +1,215 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2008 AT&T Intellectual Property # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +# +# variable tree test #001 +# Propose of this test is whether ksh93 handles global variable trees +# and function-local variable trees the same way, including "nameref" +# and "unset" handling. +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +function build_tree +{ +#set -o errexit -o xtrace + typeset index + typeset s + typeset i + typeset dummy + typeset a b c d e f + + nameref dest_tree="$1" # destination tree + nameref srcdata="$2" # source data + typeset tree_mode="$3" # mode to define the type of leads + + typeset -A dest_tree.l1 + + for index in "${!srcdata.hashnodes[@]}" ; do + nameref node=srcdata.hashnodes["${index}"] + + for i in "${node.xlfd[@]}" ; do + IFS='-' read dummy a b c d e f <<<"$i" + + if [[ "$a" == "" ]] ; then + a="$dummy" + fi + + [[ "$a" == "" ]] && a='-' + [[ "$b" == "" ]] && b='-' + [[ "$c" == "" ]] && c='-' + + if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then + #if ! (unset dest_tree.l1["$a"]) ; then + typeset -A dest_tree.l1["$a"].l2 + fi + + if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then + #if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3 + fi + + if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries + fi + + #dest_tree.l1["$a"].l2["$b"].l3["$c"].entries+=( "$index" ) + typeset new_index + if [[ "${tree_mode}" == "leaf_name" ]] ; then + new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) + else + new_index="${node.name}" + + # skip if the leaf node already exists + if [[ "${dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}]}" != "" ]] ; then + continue + fi + fi + + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" + done + done + + return 0 +} + +function add_tree_leaf +{ + nameref tree_leafnode="$1" + nameref data_node=srcdata.hashnodes["$2"] + typeset add_mode="$3" + + case "${add_mode}" in + "leaf_name") + tree_leafnode="${data_node.name}" + return 0 + ;; + "leaf_compound") + tree_leafnode=( + typeset name="${data_node.name}" + typeset -a filenames=( "${data_node.filenames[@]}" ) + typeset -a comments=( "${data_node.comments[@]}" ) + typeset -a xlfd=( "${data_node.xlfd[@]}" ) + ) + return 0 + ;; + *) + print -u2 -f "ERROR: Unknown mode %s in add_tree_leaf\n" "${add_mode}" + return 1 + ;; + esac + + # not reached + return 1 +} + +# "mysrcdata_local" and "mysrcdata_global" must be identical +typeset mysrcdata_global=( + typeset -A hashnodes=( + [abcd]=( + name='abcd' + typeset -a xlfd=( + '-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific' + ) + typeset -a comments=( + 'comment 1' + 'comment 2' + 'comment 3' + ) + typeset -a filenames=( + '/home/foo/abcd_1' + '/home/foo/abcd_2' + '/home/foo/abcd_3' + ) + ) + ) +) + +mytree_global=() + +function main +{ + # "mysrcdata_local" and "mysrcdata_global" must be identical + typeset mysrcdata_local=( + typeset -A hashnodes=( + [abcd]=( + name='abcd' + typeset -a xlfd=( + '-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific' + ) + typeset -a comments=( + 'comment 1' + 'comment 2' + 'comment 3' + ) + typeset -a filenames=( + '/home/foo/abcd_1' + '/home/foo/abcd_2' + '/home/foo/abcd_3' + ) + ) + ) + ) + + # build tree using global tree variables + build_tree mytree_global mysrcdata_global leaf_compound || \ + err_exit 'build_tree mytree_global mysrcdata_global leaf_compound returned an error' + + (( $(print -r -- "${mytree_global}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_global' too small." + + # build tree using local tree variables + mytree_local=() + build_tree mytree_local mysrcdata_local leaf_compound || \ + err_exit 'build_tree mytree_local mysrcdata_local leaf_compound returned an error' + + (( $(print -r -- "${mytree_local}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_local' too small." + + # Compare trees + if [[ "${mytree_global}" != "${mytree_local}" ]] ; then + err_exit "Compound trees 'mytree_local' and 'mytree_global' not identical" + diff -u <( printf "%s\n" "${mytree_global}" ) <( printf "%s\n" "${mytree_local}" ) + fi + + unset 'mytree_global.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + err_exit "Variable 'mytree_global.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." + + [[ "${mytree_global}" != "${mytree_local}" ]] || err_exit "mytree_global and mytree_local should differ" + + unset 'mytree_local.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + err_exit "Variable 'mytree_local.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." + + # Compare trees (after "unset") + if [[ "${mytree_global}" != "${mytree_local}" ]] ; then + err_exit "Compound trees 'mytree_local' and 'mytree_global' not identical after unset" + diff -u <( printf "%s\n" "${mytree_global}" ) <( printf "%s\n" "${mytree_local}" ) + fi +} + +main Index: src/lib/libshell/common/tests/pointtype.sh =================================================================== --- src/lib/libshell/common/tests/pointtype.sh (revision 0) +++ src/lib/libshell/common/tests/pointtype.sh (revision 1122) @@ -0,0 +1,94 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2008 AT&T Intellectual Property # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +typeset -T Pt_t=( + float x=1 + float y=0 + len() + { + print -r $((sqrt(_.x*_.x + _.y*_.y))) + } +) + +for ((i=0; i < 100; i++)) +do +Pt_t p +[[ ${p.x} == 1 ]] || err_exit '${p[x]} is not 1' +(( p.x == 1 )) || err_ext 'p[x] is not 1' +[[ $(p.len) == 1 ]] || err_exit '$(p.len) != 1' +[[ ${p.len} == 1 ]] || err_exit '${p.len} != 1' +(( p.len == 1 )) || err_exit '((p.len != 1))' +Pt_t q=(y=2) +(( q.x == 1 )) || err_exit 'q.x is not 1' +(( (q.len - sqrt(5)) < 10e-10 )) || err_exit 'q.len != sqrt(5)' +q.len() +{ + print -r $((abs(_.x)+abs(_.y) )) +} +(( q.len == 3 )) || err_exit 'q.len is not 3' +p=q +[[ ${p.y} == 2 ]] || err_exit '${p[y]} is not 2' +[[ ${@p} == Pt_t ]] || err_exit 'type of p is not Pt_t' +[[ ${@q} == Pt_t ]] || err_exit 'type of q is not Pt_t' +(( p.len == 3 )) || err_exit 'p.len is not 3' +unset p q +Pt_t pp=( ( x=3 y=4) ( x=5 y=12) (y=2) ) +(( pp[0].len == 5 )) || err_exit 'pp[0].len != 5' +(( pp[1].len == 13 )) || err_exit 'pp[0].len != 12' +(( (pp[2].len - sqrt(5)) < 10e-10 )) || err_exit 'pp[2].len != sqrt(5)' +[[ ${pp[1]} == $'(\n\ttypeset -l -E x=5\n\ttypeset -l -E y=12\n)' ]] || err_exit '${pp[1] is not correct' +[[ ${!pp[@]} == '0 1 2' ]] || err_exit '${pp[@] != "0 1 2"' +pp+=( x=6 y=8) +(( pp[3].len == 10 )) || err_exit 'pp[3].len != 10' +[[ ${!pp[@]} == '0 1 2 3' ]] || err_exit '${pp[@] != "0 1 2 3"' +pp[4]=pp[1] +[[ ${pp[4]} == $'(\n\ttypeset -l -E x=5\n\ttypeset -l -E y=12\n)' ]] || err_exit '${pp[4] is not correct' +unset pp +Pt_t pp=( [one]=( x=3 y=4) [two]=( x=5 y=12) [three]=(y=2) ) +(( pp[one].len == 5 )) || err_exit 'pp[one].len != 5' +(( pp[two].len == 13 )) || err_exit 'pp[two].len != 12' +[[ ${pp[two]} == $'(\n\ttypeset -l -E x=5\n\ttypeset -l -E y=12\n)' ]] || err_exit '${pp[two] is not correct' +[[ ${!pp[@]} == 'one three two' ]] || err_exit '${pp[@] != "one three two"' +[[ ${@pp[1]} == Pt_t ]] || err_exit 'type of pp[1] is not Pt_t' +unset pp +done +# redefinition of point +typeset -T Pt_t=( + Pt_t _=(x=3 y=6) + float z=2 + len() + { + print -r $((sqrt(_.x*_.x + _.y*_.y + _.z*_.z))) + } +) +Pt_t p +[[ ${p.y} == 6 ]] || err_exit '${p.y} != 6' +(( p.len == 7 )) || err_exit '((p.len !=7))' +exit $Errors Index: src/lib/libshell/common/tests/path.sh =================================================================== --- src/lib/libshell/common/tests/path.sh (revision 974) +++ src/lib/libshell/common/tests/path.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -30,6 +30,40 @@ mkdir /tmp/ksh$$ cd /tmp/ksh$$ trap "PATH=$PATH; cd /; rm -rf /tmp/ksh$$" EXIT +mkdir dir1 dir2 +cat > dir1/foobar << '+++' +foobar() { print foobar1;} +function dir1 { print dir1;} ++++ +cat > dir2/foobar << '+++' +foobar() { print foobar2;} +function dir2 { print dir2;} ++++ +chmod +x dir[12]/foobar +p=$PATH +FPATH=$PWD/dir1 +PATH=$FPATH:$p +[[ $( foobar) == foobar1 ]] || err_exit 'foobar should output foobar1' +FPATH=$PWD/dir2 +PATH=$FPATH:$p +[[ $(foobar) == foobar2 ]] || err_exit 'foobar should output foobar2' +FPATH=$PWD/dir1 +PATH=$FPATH:$p +[[ $(foobar) == foobar1 ]] || err_exit 'foobar should output foobar1 again' +FPATH=$PWD/dir2 +PATH=$FPATH:$p +[[ ${ foobar;} == foobar2 ]] || err_exit 'foobar should output foobar2 with ${}' +[[ ${ dir2;} == dir2 ]] || err_exit 'should be dir2' +[[ ${ dir1;} == dir1 ]] 2> /dev/null && err_exit 'should not be be dir1' +FPATH=$PWD/dir1 +PATH=$FPATH:$p +[[ ${ foobar;} == foobar1 ]] || err_exit 'foobar should output foobar1 with ${}' +[[ ${ dir1;} == dir1 ]] || err_exit 'should be dir1' +[[ ${ dir2;} == dir2 ]] 2> /dev/null && err_exit 'should not be be dir2' +FPATH=$PWD/dir2 +PATH=$FPATH:$p +[[ ${ foobar;} == foobar2 ]] || err_exit 'foobar should output foobar2 with ${} again' +PATH=$p (PATH="/bin") [[ $($SHELL -c 'print -r -- "$PATH"') == "$PATH" ]] || err_exit 'export PATH lost in subshell' cat > bug1 <<- \EOF @@ -183,4 +217,13 @@ [[ $status == 127 ]] || err_exit "not found command with ERR trap exit status $status -- expected 127" status=$($SHELL -c $'trap \'print $?\' ERR;/dev/null 2> /dev/null') [[ $status == 126 ]] || err_exit "non executable command ERR trap exit status $status -- expected 126" + +# universe via PATH + +builtin getconf +getconf UNIVERSE - att # override sticky default 'UNIVERSE = foo' + +[[ $(PATH=/usr/ucb/bin:/usr/bin echo -n ucb) == 'ucb' ]] || err_exit "ucb universe echo ignores -n option" +[[ $(PATH=/usr/xpg/bin:/usr/bin echo -n att) == '-n att' ]] || err_exit "att universe echo does not ignore -n option" + exit $((Errors)) Index: src/lib/libshell/common/tests/recttype.sh =================================================================== --- src/lib/libshell/common/tests/recttype.sh (revision 0) +++ src/lib/libshell/common/tests/recttype.sh (revision 1122) @@ -0,0 +1,69 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2008 AT&T Intellectual Property # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +typeset -T Pt_t=( + float x=1 + float y=0 + len() + { + print -r $((sqrt(_.x*_.x + _.y*_.y))) + } +) + +typeset -T Rect_t=( + Pt_t ll=(x=0 y=0) + Pt_t ur=(x=1 y=1) + area() + { + print -r $(( abs((_.ur.x-_.ll.x)*(_.ur.y-_.ll.y)) )) + } +) + +for ((i=0; i < 100; i++)) +do +Rect_t r +[[ ${r.area} == 1 ]] || err_exit '${r.area} != 1' +Rect_t s=( + Pt_t ur=(x=9 y=9) + Pt_t ll=(x=7 y=7) +) +[[ ${s.ur.x} == 9 ]] || err_exit ' ${s.ur.x} != 9' +(( s.ur.x == 9 ))|| err_exit ' ((s.ur.x)) != 9' +[[ ${s.ll.y} == 7 ]] || err_exit '${s.ll.y} != 7' +(( s.area == 4 )) || err_exit 'area of s should be 4' +[[ ${s.area} == 4 ]] || err_exit '${s.area} != 4' +unset r s +done +Rect_t -A r +r[one]=(ur=(x=4 y=4)) +(( r[one].area == 16 )) || err_exit 'area of r[one] should be 16' +[[ ${r[one].area} == 16 ]] || err_exit '${r[one].area} should be 16' +unset r +exit $Errors Index: src/lib/libshell/common/tests/coprocess.sh =================================================================== --- src/lib/libshell/common/tests/coprocess.sh (revision 974) +++ src/lib/libshell/common/tests/coprocess.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -154,7 +154,7 @@ ) && err_exit 'coprocess with subshell would hang' for sig in IOT ABRT do if ( trap - $sig ) 2> /dev/null - then if [[ $( + then if [[ $( { sig=$sig $SHELL 2> /dev/null <<- '++EOF++' cat |& pid=$! trap "print TRAP" $sig @@ -164,9 +164,12 @@ sleep 2 kill -$sig $$ kill $pid + sleep 2 + kill $$ ) 2> /dev/null & read -p - ) != $'TRAP\nTRAP' ]] + ++EOF++ + } 2> /dev/null ) != $'TRAP\nTRAP' ]] then err_exit 'traps when reading from coprocess not working' fi break Index: src/lib/libshell/common/tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh =================================================================== --- src/lib/libshell/common/tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh (revision 0) +++ src/lib/libshell/common/tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh (revision 1122) @@ -0,0 +1,112 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# Test whether CR #6713682 has been fixed. +# +# Creating a compound variable in s subshell "bleeds through" to the calling subshell in some conditions. +# Example: +# -- snip -- +# $ ksh93 -c 'unset l ; ( l=( a=1 b="BE" ) ; print "$l" ) ; print $l' +# ( +# a=1 +# b=BE +# ) +# ( ) +# -- snip -- +# The first bracket pair is Ok since it's coming from $ print "$l" # , however the 2nd pair comes from the print $l _outside_ the subshell where the variable "l" should no longer exist. +# +# Workaround: +# Force ksh93 to call |fork()| for the matching subshell using $ ulimit -c #, e.g. ... +# -- snip -- +# $ ksh93 -c 'unset l ; ( ulimit -c 0 ; l=( a=1 b="BE" ) ; print "$l" ) ; print $l' +# ( +# a=1 +# b=BE +# ) +# -- snip -- +# ... provides the correct output. +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +integer Errors=0 + +typeset var1 var2 + +# use unset, l=() compound syntax and print +var1="$(${SHELL} -c 'unset l ; ( l=( a=1 b="BE" ) ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; l=( a=1 b="BE" ) ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +[[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." + +# do not use unset, l=() compound syntax and print +var1="$(${SHELL} -c '( l=( a=1 b="BE" ) ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +var2="$(${SHELL} -c '( ulimit -c 0 ; l=( a=1 b="BE" ) ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +[[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (without unset)." + +# use unset, typeset -C compound syntax and print +var1="$(${SHELL} -c 'unset l ; ( typeset -C l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; typeset -C l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +[[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." + +# do not use unset, typeset -C compound syntax and print +var1="$(${SHELL} -c '( typeset -C l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +var2="$(${SHELL} -c '( ulimit -c 0 ; typeset -C l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +[[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." + +# use of printf "%B\n" disabled due to another bug + +# use unset, l=() compound syntax and printf "%B\n" +#var1="$(${SHELL} -c 'unset l ; ( l=( a=1 b="BE" ) ; printf "%B\n" l ) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +#var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; l=( a=1 b="BE" ) ; printf "%B\n" l ) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +#[[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." + +# do not use unset, l=() compound syntax and printf "%B\n" +#var1="$(${SHELL} -c '( l=( a=1 b="BE" ) ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +#var2="$(${SHELL} -c '( ulimit -c 0 ; l=( a=1 b="BE" ) ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +#[[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (without unset)." + +# use unset, typeset -C compound syntax and printf "%B\n" +#var1="$(${SHELL} -c 'unset l ; ( typeset -C l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +#var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; typeset -C l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +#[[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." + +# do not use unset, typeset -C compound syntax and printf "%B\n" +#var1="$(${SHELL} -c '( typeset -C l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +#var2="$(${SHELL} -c '( ulimit -c 0 ; typeset -C l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +#[[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." + +exit $((Errors)) +# EOF. Index: src/lib/libshell/common/tests/arrays.sh =================================================================== --- src/lib/libshell/common/tests/arrays.sh (revision 974) +++ src/lib/libshell/common/tests/arrays.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # @@ -155,7 +155,6 @@ if (( s[$y] != 4 )) then err_exit '(( s[$y] != 4 ))' fi -unset y set -A y 2 4 6 typeset -i y z=${y[@]} @@ -378,4 +377,79 @@ unset bar : ${_foo[bar=4]} (( bar == 4 )) || err_exit 'subscript of unset variable not evaluated' +unset foo bar +foo[5]=4 +bar[4]=3 +bar[0]=foo +foo[0]=bam +foo[4]=5 +[[ ${!foo[2+2]} == 'foo[4]' ]] || err_exit '${!var[sub]} should be var[sub]' +[[ ${bar[${foo[5]}]} == 3 ]] || err_exit 'array subscript cannot be an array instance' +[[ $bar[4] == 3 ]] || err_exit '$bar[x] != ${bar[x]} inside [[ ]]' +(( $bar[4] == 3 )) || err_exit '$bar[x] != ${bar[x]} inside (( ))' +[[ $bar[$foo[5]] == 3 ]] || err_exit '$bar[foo[x]] != ${bar[foo[x]]} inside [[ ]]' +(( $bar[$foo[5]] == 3 )) || err_exit '$bar[foo[x]] != ${bar[foo[x]]} inside (( ))' +x=$bar[4] +[[ $x == 4 ]] && err_exit '$bar[4] should not be an array in an assignment' +x=${bar[$foo[5]]} +(( $x == 3 )) || err_exit '${bar[$foo[sub]]} not working' +[[ $($SHELL <<- \++EOF+++ + typeset -i test_variable=0 + typeset -A test_array + test_array[1]=100 + read test_array[2] <<-! + 2 + ! + read test_array[3] <<-! + 3 + ! + test_array[3]=4 + print "val=${test_array[3]}" +++EOF+++ +) == val=4 ]] 2> /dev/null || err_exit 'after reading array[j] and assign array[j] fails' +[[ $($SHELL <<- \+++EOF+++ + pastebin=( typeset -a form) + pastebin.form+=( name="name" data="clueless" ) + print -r -- ${pastebin.form[0].name} ++++EOF+++ +) == name ]] 2> /dev/null || err_exit 'indexed array in compound variable not working' +unset foo bar +: ${foo[bar=2]} +[[ $bar == 2 ]] || err_exit 'subscript not evaluated for unset variable' +unset foo bar +bar=1 +typeset -a foo=([1]=ok [2]=no) +[[ $foo[bar] == ok ]] || err_exit 'typeset -a not working for simple assignment' +unset foo +typeset -a foo=([1]=(x=ok) [2]=(x=no)) +[[ $(typeset | grep 'foo$') == *index* ]] || err_exit 'typeset -a not creating an indexed array' +foo+=([5]=good) +[[ $(typeset | grep 'foo$') == *index* ]] || err_exit 'append to indexed array not preserving array type' +unset foo +typeset -A foo=([1]=ok [2]=no) +[[ $foo[bar] == ok ]] && err_exit 'typeset -A not working for simple assignment' +unset foo +typeset -A foo=([1]=(x=ok) [2]=(x=no)) +[[ ${foo[bar].x} == ok ]] && err_exit 'typeset -A not working for compound assignment' +[[ $($SHELL -c 'typeset -a foo;typeset | grep "foo$"' 2> /dev/null) == *index* ]] || err_exit 'typeset fails for indexed array with no elements' +xxxxx=(one) +[[ $(typeset | grep xxxxx$) == *'indexed array'* ]] || err_exit 'array of one element not an indexed array' +unset foo +foo[1]=(x=3 y=4) +{ [[ ${!foo[1].*} == 'foo[1].x foo[1].y' ]] ;} 2> /dev/null || err_exit '${!foo[sub].*} not expanding correctly' +unset x +x=( typeset -a foo=( [0]="a" [1]="b" [2]="c" )) +[[ ${@x.foo} == 'typeset -a'* ]] || err_exit 'x.foo is not an indexed array' +x=( typeset -A foo=( [0]="a" [1]="b" [2]="c" )) +[[ ${@x.foo} == 'typeset -A'* ]] || err_exit 'x.foo is not an associative array' +$SHELL -c $'x=(foo\n\tbar\nbam\n)' 2> /dev/null || err_exit 'compound array assignment with new-lines not working' +$SHELL -c $'x=(foo\n\tbar:\nbam\n)' 2> /dev/null || err_exit 'compound array assignment with labels not working' +$SHELL -c $'x=(foo\n\tdone\nbam\n)' 2> /dev/null || err_exit 'compound array assignment with reserved words not working' +[[ $($SHELL -c 'typeset -A A; print $(( A[foo].bar ))' 2> /dev/null) == 0 ]] || err_exit 'unset variable not evaluating to 0' +unset a +typeset -A a +a[a].z=1 +a[z].z=2 +unset a[a] +[[ ${!a[@]} == z ]] || err_exit '"unset a[a]" unsets entire array' exit $((Errors)) Index: src/lib/libshell/common/tests/sun_solaris_staticvariables.sh =================================================================== --- src/lib/libshell/common/tests/sun_solaris_staticvariables.sh (revision 0) +++ src/lib/libshell/common/tests/sun_solaris_staticvariables.sh (revision 1122) @@ -0,0 +1,111 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +function err_exit2 +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +function testfunc +{ + integer line_number=$1 + typeset cmd="$2" + typeset expected_output="$3" + typeset output + + output="$($SHELL -c "${cmd}" 2>&1 )" + + [[ "${output}" != "${expected_output}" ]] && err_exit2 ${line_number} "${output} != ${expected_output}" +} +alias testfunc='testfunc $LINENO' +alias err_exit='err_exit2 $LINENO' + +integer Errors=0 + +# string +testfunc '(function l { typeset -S x ; x+="#" ; $1 && print "$x" ; } ; l false ; l false ; l true)' "###" +testfunc 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false ; l false ; l true' ">###" +testfunc 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false ; (l false) ; l true' ">##" +testfunc 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false; ( ulimit -c 0 ; l false) ; l true' ">##" + +# integer +testfunc '(function l { typeset -S -i x ; x+=1 ; $1 && print "$x" ; } ; l false ; l false ; l true )' "3" +testfunc '(function l { typeset -S -i x ; x+=1 ; $1 && print "$x" ; } ; l false ; (l false) ; l true )' "2" + +# float +testfunc '(function l { float -S x=0.5 ; (( x+=.5 )) ; $1 && print "$x" ; } ; l false ; l false ; l true )' "2" +testfunc '(function l { float -S x=0.5 ; (( x+=.5 )) ; $1 && print "$x" ; } ; l false ; (l false) ; l true )' "1.5" + +# compound variable +[[ "${ + function l + { + typeset -S s=( a=0 b=0 ) + + (( s.a++, s.b++ )) + + $1 && printf 'a=%d, b=%d\n' s.a s.b + } + l false ; l false ; l true +}" != "a=3, b=3" ]] && err_exit "static compound var failed" + + +# array variable +[[ "$( + function ar + { + typeset -a -S s=( "hello" ) + + s+=( "an element" ) + + $1 && { printf '%s' "${s[@]}" ; printf '\n' ; } + } + ar false ; ar false ; ar true +)" != "helloan elementan elementan element" ]] && err_exit "static array var failed" + + +# Test visibilty of "global" vs. "static" variables. if we have a "static" variable in a +# function and "unset" it we should see a global variable with the same +# name, right ? +integer hx=5 +function test_hx_scope +{ + integer -S hx=9 + $2 && unset hx + $1 && printf "hx=%d\n" hx +} +test_hx_scope false false +test_hx_scope false false +# first test the "unset" call in a $(...) subshell... +[[ "$( test_hx_scope true true )" != "hx=5" ]] && err_exit "can't see global variable hx after unsetting static variable hx" +# ... end then test whether the value has changed. +[[ "${ test_hx_scope true false }" != "hx=9" ]] && err_exit "hx variable somehow changed" + +exit $((Errors)) Index: src/lib/libshell/common/tests/enum.sh =================================================================== --- src/lib/libshell/common/tests/enum.sh (revision 0) +++ src/lib/libshell/common/tests/enum.sh (revision 1122) @@ -0,0 +1,62 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2008 AT&T Intellectual Property # +# and is licensed under the # +# Common Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.opensource.org/licenses/cpl1.0.txt # +# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 +enum Color_t=(red green blue orange yellow) +enum -i Sex_t=(Male Female) +for ((i=0; i < 1000; i++)) +do +Color_t x +[[ $x == red ]] || err_exit 'Color_t does not default to red' +x=orange +[[ $x == orange ]] || err_exit '$x should be orange' +( x=violet) 2> /dev/null && err_exit 'x=violet should fail' +x[2]=green +[[ ${x[2]} == green ]] || err_exit '${x[2]} should be green' +(( x[2] == 1 )) || err_exit '((x[2]!=1))' +[[ $((x[2])) == 1 ]] || err_exit '$((x[2]))!=1' +[[ $x == orange ]] || err_exit '$x is no longer orange' +Color_t -A y +y[foo]=yellow +[[ ${y[foo]} == yellow ]] || err_exit '${y[foo]} != yellow' +(( y[foo] == 4 )) || err_exit '(( y[foo] != 4))' +unset y +typeset -a [Color_t] z +z[green]=xyz +[[ ${z[green]} == xyz ]] || err_exit '${z[green]} should be xyz' +[[ ${z[1]} == xyz ]] || err_exit '${z[1]} should be xyz' +z[orange]=bam +[[ ${!z[@]} == 'green orange' ]] || err_exit '${!z[@]} == "green orange"' +unset x +Sex_t x +[[ $x == Male ]] || err_exit 'Sex_t not defaulting to Male' +x=female +[[ $x == Female ]] || err_exit 'Sex_t not case sensitive' +unset x y z +done +exit $Errors Index: src/lib/libshell/common/llib-lshell =================================================================== --- src/lib/libshell/common/llib-lshell (revision 974) +++ src/lib/libshell/common/llib-lshell (revision 1122) @@ -19,14 +19,14 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * lib/libshell/common/llib-lshell * */ -#pragma ident "@(#)llib-lshell 1.1 07/06/27 SMI" +#pragma ident "%Z%%M% %I% %E% SMI" /*LINTLIBRARY*/ /*PROTOLIB1*/ @@ -35,6 +35,7 @@ #include <nval.h> /* automatically generated data start here */ +/* <shell.h> */ extern const char e_defpath[]; extern const char e_found[]; extern const char e_nospace[]; @@ -43,90 +44,92 @@ extern const char e_restricted[]; extern const char e_recursive[]; extern char e_version[]; -extern Dt_t *sh_bltin_tree (void); -extern void sh_subfork (void); -extern Shell_t *sh_init (int,char*[],Shinit_f); -extern int sh_reinit (char*[]); -extern int sh_eval (Sfio_t*,int); -extern void sh_delay (double); -extern void *sh_parse (Shell_t*, Sfio_t*,int); -extern int sh_trap (const char*,int); -extern int sh_fun (Namval_t*,Namval_t*, char*[]); -extern int sh_funscope (int,char*[],int(*)(void*),void*,int); -extern Sfio_t *sh_iogetiop (int,int); -extern int sh_main (int, char*[], void(*)(int)); -extern void sh_menu (Sfio_t*, int, char*[]); -extern Namval_t *sh_addbuiltin (const char*, int(*)(int, char*[],void*), void*); -extern char *sh_fmtq (const char*); -extern char *sh_fmtqf (const char*, int, int); -extern Sfdouble_t sh_strnum (const char*, char**, int); -extern int sh_access (const char*,int); -extern int sh_close (int); -extern int sh_dup (int); -extern void sh_exit (int); -extern int sh_fcntl (int, int, ...); -extern Sfio_t *sh_fd2sfio (int); -extern Shell_t *sh_getinterp (void); -extern int sh_open (const char*, int, ...); -extern int sh_openmax (void); -extern Sfio_t *sh_pathopen (const char*); -extern ssize_t sh_read (int, void*, size_t); -extern ssize_t sh_write (int, const void*, size_t); -extern off_t sh_seek (int, off_t, int); -extern int sh_pipe (int[]); -extern mode_t sh_umask (mode_t); -extern void *sh_waitnotify (Shwait_f); -extern Shscope_t *sh_getscope (int,int); -extern Shscope_t *sh_setscope (Shscope_t*); -extern void sh_sigcheck (void); -extern unsigned long sh_isoption (int); -extern unsigned long sh_onoption (int); -extern unsigned long sh_offoption (int); -extern int sh_waitsafe (void); -extern int sh_exec (const Shnode_t*,int); +extern Dt_t *sh_bltin_tree(void); +extern void sh_subfork(void); +extern Shell_t *sh_init(int,char*[],Shinit_f); +extern int sh_reinit(char*[]); +extern int sh_eval(Sfio_t*,int); +extern void sh_delay(double); +extern void *sh_parse(Shell_t*, Sfio_t*,int); +extern int sh_trap(const char*,int); +extern int sh_fun(Namval_t*,Namval_t*, char*[]); +extern int sh_funscope(int,char*[],int(*)(void*),void*,int); +extern Sfio_t *sh_iogetiop(int,int); +extern int sh_main(int, char*[], void(*)(int)); +extern int sh_run(int, char*[]); +extern void sh_menu(Sfio_t*, int, char*[]); +extern Namval_t *sh_addbuiltin(const char*, int(*)(int, char*[],void*), void*); +extern char *sh_fmtq(const char*); +extern char *sh_fmtqf(const char*, int, int); +extern Sfdouble_t sh_strnum(const char*, char**, int); +extern int sh_access(const char*,int); +extern int sh_close(int); +extern int sh_dup(int); +extern void sh_exit(int); +extern int sh_fcntl(int, int, ...); +extern Sfio_t *sh_fd2sfio(int); +extern Shell_t *sh_getinterp(void); +extern int sh_open(const char*, int, ...); +extern int sh_openmax(void); +extern Sfio_t *sh_pathopen(const char*); +extern ssize_t sh_read(int, void*, size_t); +extern ssize_t sh_write(int, const void*, size_t); +extern off_t sh_seek(int, off_t, int); +extern int sh_pipe(int[]); +extern mode_t sh_umask(mode_t); +extern void *sh_waitnotify(Shwait_f); +extern Shscope_t *sh_getscope(int,int); +extern Shscope_t *sh_setscope(Shscope_t*); +extern void sh_sigcheck(void); +extern unsigned long sh_isoption(int); +extern unsigned long sh_onoption(int); +extern unsigned long sh_offoption(int); extern int sh_waitsafe(void); extern int sh_exec(const Shnode_t*,int); extern void **sh_getliblist(void); extern Shell_t sh; -extern Namarr_t *nv_setarray (Namval_t*,void*(*)(Namval_t*,const char*,int)); -extern void *nv_associative (Namval_t*,const char*,int); -extern int nv_aindex (Namval_t*); -extern int nv_nextsub (Namval_t*); -extern char *nv_getsub (Namval_t*); -extern Namval_t *nv_putsub (Namval_t*, char*, long); -extern Namval_t *nv_opensub (Namval_t*); -extern int nv_adddisc (Namval_t*, const char**, Namval_t**); -extern int nv_clone (Namval_t*, Namval_t*, int); -extern void nv_close (Namval_t*); -extern void *nv_context (Namval_t*); -extern Namval_t *nv_create (const char*, Dt_t*, int,Namfun_t*); -extern Dt_t *nv_dict (Namval_t*); -extern Sfdouble_t nv_getn (Namval_t*, Namfun_t*); -extern Sfdouble_t nv_getnum (Namval_t*); -extern char *nv_getv (Namval_t*, Namfun_t*); -extern char *nv_getval (Namval_t*); -extern Namfun_t *nv_hasdisc (Namval_t*, const Namdisc_t*); -extern int nv_isnull (Namval_t*); -extern Namval_t *nv_lastdict (void); -extern void nv_newattr (Namval_t*,unsigned,int); -extern Namval_t *nv_open (const char*,Dt_t*,int); -extern void nv_putval (Namval_t*,const char*,int); -extern void nv_putv (Namval_t*,const char*,int,Namfun_t*); -extern int nv_scan (Dt_t*,void(*)(Namval_t*,void*),void*,int,int); -extern Namval_t *nv_scoped (Namval_t*); -extern char *nv_setdisc (Namval_t*,const char*,Namval_t*,Namfun_t*); -extern void nv_setref (Namval_t*, Dt_t*,int); -extern int nv_settype (Namval_t*, Namval_t*, int); -extern void nv_setvec (Namval_t*,int,int,char*[]); -extern void nv_setvtree (Namval_t*); -extern int nv_setsize (Namval_t*,int); -extern Namfun_t *nv_disc (Namval_t*,Namfun_t*,int); -extern void nv_unset (Namval_t*); -extern Namval_t *nv_search (const char *, Dt_t*, int); -extern void nv_unscope (void); -extern char *nv_name (Namval_t*); -extern Namval_t *nv_type (Namval_t*); -extern const Namdisc_t *nv_discfun (int); +/* <nval.h> */ +extern Namarr_t *nv_arrayptr(Namval_t*); +extern Namarr_t *nv_setarray(Namval_t*,void*(*)(Namval_t*,const char*,int)); +extern int nv_arraynsub(Namarr_t*); +extern void *nv_associative(Namval_t*,const char*,int); +extern int nv_aindex(Namval_t*); +extern int nv_nextsub(Namval_t*); +extern char *nv_getsub(Namval_t*); +extern Namval_t *nv_putsub(Namval_t*, char*, long); +extern Namval_t *nv_opensub(Namval_t*); +extern int nv_adddisc(Namval_t*, const char**, Namval_t**); +extern int nv_clone(Namval_t*, Namval_t*, int); +extern void nv_close(Namval_t*); +extern void *nv_context(Namval_t*); +extern Namval_t *nv_create(const char*, Dt_t*, int,Namfun_t*); +extern Dt_t *nv_dict(Namval_t*); +extern Sfdouble_t nv_getn(Namval_t*, Namfun_t*); +extern Sfdouble_t nv_getnum(Namval_t*); +extern char *nv_getv(Namval_t*, Namfun_t*); +extern char *nv_getval(Namval_t*); +extern Namfun_t *nv_hasdisc(Namval_t*, const Namdisc_t*); +extern int nv_isnull(Namval_t*); +extern Namval_t *nv_lastdict(void); +extern Namval_t *nv_mkinttype(char*, size_t, int, const char*, Namdisc_t*); +extern void nv_newattr(Namval_t*,unsigned,int); +extern Namval_t *nv_open(const char*,Dt_t*,int); +extern void nv_putval(Namval_t*,const char*,int); +extern void nv_putv(Namval_t*,const char*,int,Namfun_t*); +extern int nv_scan(Dt_t*,void(*)(Namval_t*,void*),void*,int,int); +extern char *nv_setdisc(Namval_t*,const char*,Namval_t*,Namfun_t*); +extern void nv_setref(Namval_t*, Dt_t*,int); +extern int nv_settype(Namval_t*, Namval_t*, int); +extern void nv_setvec(Namval_t*,int,int,char*[]); +extern void nv_setvtree(Namval_t*); +extern int nv_setsize(Namval_t*,int); +extern Namfun_t *nv_disc(Namval_t*,Namfun_t*,int); +extern void nv_unset(Namval_t*); +extern Namval_t *nv_search(const char *, Dt_t*, int); +extern char *nv_name(Namval_t*); +extern Namval_t *nv_type(Namval_t*); +extern void nv_addtype(Namval_t*,const char*, Optdisc_t*, size_t); +extern const Namdisc_t *nv_discfun(int); /* end of automatically generated data */ /* Manually added based on libshell/common/include/builtins.h */ Index: src/lib/libshell/common/TYPES =================================================================== --- src/lib/libshell/common/TYPES (revision 0) +++ src/lib/libshell/common/TYPES (revision 1122) @@ -0,0 +1,177 @@ + +The ability for users to define types has been added to ksh93t. +Here is a quick summary of how types are defined and used in ksh93t. +This is still a work in progress so some changes and additions +are likely. + +A type can be defined either by a shared library or by using the new +typeset -T option to the shell. The method for defining types via +a shared library is not described here. However, the source file +bltins/enum.c is an example of a builtin that creates enumeration types. + +By convention, typenames begin with a capitol letter and end in _t. +To define a type, use + typeset -T Type_t=( + definition + ) +where definition contains assignment commands, declaration commands, +and function definitions. A declaration command (for example typeset, +readonly, and export), is a built-in that differs from other builtins in +that tilde substitution is performed on arguments after an =, assignments +do not have to precede the command name, and field splitting and pathname +expansion is not performed on the arguments. +For example, + typeset -T Pt_t=( + float -h 'length in inches' x=1 + float -h 'width in inches' y=0 + integer -S count=0 + len() + { + print -r $((sqrt(_.x*_.x + _.y*_.y))) + } + set() + { + (( _.count++)) + } + ) + +defines a type Pt_t that has three variables x, y, and count defined as well +as the discipline functions len and set. The variable x has an initial value +of 1 and the variable y has an initial value of 0. The new -h option argument, +is used for documentations purposes as described later and is ignored outside +of a type definition. + +The variable count has the new -S attribute which means that it is shared +between all instances of the type. The -S option to typeset is ignored +outside of a type definition. Note the variable named _ that is used inside +the function definition for len and set. It will be a reference to the +instance of Pt_t that invoked the function. The functions len and set +could also have been defined with function len and function set, but +since there are no local variables, the len() and set() form are more +efficient since they don't need to set up a context for local variables +and for saving and restoring traps. + +When a type is defined, a declaration built-in command by this name +is added to ksh. As with other shell builtins, you can get the man page +for this newly added command by invoking Pt_t --man. The information from +the -h options will be embedded in this man page. Any functions that +use getopts to process arguments will be cross referenced on the generated +man page. + +Since Pt_t is now a declaration command it can be used in the definition +of other types, for example + typeset -T Rect_t=( Pt_t ur ll) + +Because a type definition is a command, it can be loaded on first reference +by putting the definition into a file that is found on FPATH. +Thus, if this definition is in a file named Pt_t on FPATH, then +a program can create instances of Pt_t without first including +the definition. + +A type definition is readonly and cannot be unset. Unsetting non-shared +elements of a type restores them to their default value. Unsetting a +shared element has no effect. + +The Pt_t command is used to create an instance of Pt_t. + Pt_t p1 +creates an instance named p1 with the initial value for p1.x set to 1 +and the initial value of p1.y set to 0. + Pt_t p2=(x=3 y=4) +creates an instance with the specified initial values. The len function +gives the distance of the point to the origin. Thus, p1.len will output +1 and p2.len will output 5. + +ksh93t also introduces a more efficient command substitution mechanism. +Instead of $(command), the new command substitution ${ command;} +can be used. Unlike (and ) which are always special, the { and } are +reserved words and require the space after { and a newline or ; before }. +Unlike $(), the ${ ;} command substitution executes the command in +the current shell context saving the need to save and restore +changes, therefore also allowing side effects. + +When trying to expand an element of a type, if the element does not exist, +ksh will look for a discipline function with that name and treat this as if +it were the ${ ;} command substitution. Thus, ${p1.len} is equivalent to +${ p1.len;} and within an arithmetic expression, p1.len will be expanded +via the new command substitution method. + +The type of any variable can be obtained from the new prefix +operator @. Thus, ${@p1} will output Pt_t. + +By default, each instance inherits all the discipline functions +defined by the type definition. However, each instance can create +a function by the same name that will override this definition. +However, only discipline functions with the same name as those defined +by the type or the standard get, set, append, and unset disciplines +can be defined by each instance. + +Each instance of the type Pt_t behaves like a compound variable except +that only the variables defined by the type can be referenced or set. +Thus, p2.x=9 is valid, but p2.z=9 is not. Unless a set discipline function +does otherwise, the value of $p1 will be expanded to the form of a compound +variable that can be used for reinput into ksh. + +If the variables var1 and var2 are of the same type, then the assignment + var2=var1 +will create a copy of the variable var1 into var2. This is equivalent to + eval var2="$var1" +but is faster since the variable does not need to get expanded or reparsed. + +The type Pt_t can be referenced as if it were a variable using the name +.sh.type.Pt_t. To change the default point location for subsequent +instances of Pt_t, you can do + .sh.type.Pt_t=(x=5 y=12) +so that + Pt_t p3 + p3.len +would be 13. + +Types can be defined for simple variables as well as for compound +objects such as Pt_t. In this case, the variable named . inside +the definition refers to the real value for the variable. For example, +the type definition + typeset -T Time_t=( + integer .=0 + _='%H:%M:%S' + get() + { + .sh.value=$(printf "%(${_._})T" "#$((_))" ) + } + set() + { + .sh.value=$(printf "%(%#)T" "${.sh.value}") + + } + ) + +The sub-variable name _ is reserved for data used by discipline functions +and will not be included with data written with the %B option to printf. +In this case it is used to specify a date format. + +In this case + Time_t t1 t2=now +will define t1 as the time at the beginning of the epoch and t2 +as the current time. Unlike the previous case, $t2 will output +the current time in the date format specified by the value t2._. +However, the value of ${t2.} will expand the instance to a form +that can be used as input to the shell. + +Finally, types can be derived from an existing type. If the first +element in a type definition is named _, then the new type +consists of all the elements and discipline functions from the +type of _ extended by elements and discipline functions defined +by new type definition. For example, + + typeset -T Pq_t=( + Pt_t _ + float z=0. + len() + { + print -r $((sqrt(_.x*_.x + _.y*_.y + _.z*_.z))) + } + ) + +defines a new type Pq_t which is based on Pq_t and contains an additional +field z and a different len discipline function. It is also possible +to create a new type Pt_t based on the original Pt_t. In this case +the original Pt_t is no longer accessible. Index: src/lib/libshell/common/PROMO.mm =================================================================== --- src/lib/libshell/common/PROMO.mm (revision 974) +++ src/lib/libshell/common/PROMO.mm (revision 1122) @@ -110,7 +110,7 @@ .LI Improved debugging: KSH-93 can generate line numbers on execution traces. Also, I/O redirections are now traced. -There is a DEBUG trap that gets evaluated after each command +There is a DEBUG trap that gets evaluated before each command so that errors can be localized. .LI Job Control: On systems that support job control, including Index: src/lib/libshell/common/shell.3 =================================================================== --- src/lib/libshell/common/shell.3 (revision 974) +++ src/lib/libshell/common/shell.3 (revision 1122) @@ -20,6 +20,7 @@ Shell_t; Shopt_t; Shscope_t; +Shbltin_t; Shbltin_f; Shinit_f; Shwait_f; @@ -29,7 +30,7 @@ .nf .ft 5 int sh_main(int \fIargc\fP, char *\fIargv\fP[], Sh_init \fIfn\fP); -Shell_t *sh_init(int \fIargc\fP, char *\fIargv\fP); +Shell_t *sh_init(int \fIargc\fP, char *\fIargv\fP[]); Shell_t *sh_getinterp(void); Namval_t *sh_addbuiltin(const char *\fIname\fP,Sh_bltin_f \fIfn\fP,void *\fIarg\fP); @@ -40,6 +41,7 @@ void *sh_parse(Shell_t *\fIshp\fP, Sfio_t *\fIsp\fP, int \fIflags\fP); int sh_trap(const char *\fIstring\fP, int \fImode\fP); +int sh_run(int \fIargc\fP, char *\fIargv\fP[]); int sh_eval(Sfio_t *\fIsp\fP,int \fImode\fP); int sh_fun(Namval_t *\fIfunnode\fP, Namval_t *\fIvarnode\fP, char *\fIargv\fP[]); int sh_funscope(int \fIargc\fP,char *\fIargv\fP[],int(*\fIfn\fP)(void*),void *\fIarg\fP,int \fIflags\fP); @@ -103,7 +105,10 @@ at run time using the \f5builtin\fP(1) command. In this case the shell will look for a function named \f5lib_init\fP in your library and, if found, will execute this function with -argument \f50\fP when the library is loaded. +two arguments. The first +argument will be an \f5int\P with value \f50\fP when the library is loaded. +The second argument will contain a pointer to a structure of type +\f5Shbltin_t\fP. In addition, for each argument named on the \f5builtin\fP command line, it will look for a function named \f5b_\fP\fIname\fP\f5()\fP in your library and will \fIname\fP as a built-in. @@ -157,17 +162,20 @@ three arguments. The first two arguments give the number of arguments and the argument list and uses the same conventions as the \f5main()\fP function -of a program. The third argument is a pointer that +of a program. The third argument is a pointer to a structure +of type \f5Shbltin_t\fP. This structure contains \f5shp\P which is a pointer +to the shell interpreter, and \f5ptr\fP which is a pointer that can be associated with each built-in. The \f5sh_addbuiltin()\fP function is used to add, replace or delete built-in commands. It takes the name of the built-in, \fIname\fP, a pointer to the function that implements the built-in, \fIfn\fP, and -a pointer that will be passed to the function when +a pointer that will be passed to the function in the \f5ptr\fP field when it is invoked. If, \fIfn\fP is non-\f5NULL\fP the built-in command -is added or replaced. Otherwise, the given -built-in command will be deleted. +is added or replaced. Otherwise, \f5sh_addbuiltin()\fP will +return a pointer to the built-in if it exists or \f5NULL\fP otherwise. +If \fIarg\fP is \f5(void*)1\fP the built-in will be deleted. The \fIname\fP argument can be in the format of a pathname. It cannot be the name of any of the special built-in commands. If \fIname\fP contains a \f5/\fP, the built-in is the basename of @@ -268,6 +276,12 @@ within the string or file will not take effect until the next command is executed. .PP +The \f5sh_run()\fP function will run the command given by +by the argument list \fIargv\fP containing \fIargc\fP elements. +If \fIargv\fP\f5[0]\fP does not contain a \f5/\fP, it will +be checked to see if it is a built-in or function before +performing a path search. +.PP The \f5sh_eval()\fP function executes a string or file stream \fIsp\fP. If \fImode\fP is non-zero and the history file has Index: src/lib/libshell/common/data/bash_pre_rc.sh =================================================================== --- src/lib/libshell/common/data/bash_pre_rc.sh (revision 974) +++ src/lib/libshell/common/data/bash_pre_rc.sh (revision 1122) @@ -1,10 +1,10 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2007 AT&T Knowledge Ventures # +# Copyright (c) 1982-2008 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # -# by AT&T Knowledge Ventures # +# by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.opensource.org/licenses/cpl1.0.txt # Index: src/lib/libshell/common/data/signals.c =================================================================== --- src/lib/libshell/common/data/signals.c (revision 974) +++ src/lib/libshell/common/data/signals.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -25,7 +25,7 @@ # define SIGCHLD SIGCLD #endif -#define VAL(sig,mode) ((sig+1)|(mode)<<SH_SIGBITS) +#define VAL(sig,mode) ((sig+1)|((mode)<<SH_SIGBITS)) #define TRAP(n) (((n)|SH_TRAP)-1) #ifndef ERROR_dictionary @@ -55,6 +55,9 @@ #ifdef SIGBUS "BUS", VAL(SIGBUS,SH_SIGDONE), S("Bus error"), #endif /* SIGBUS */ +#ifdef SIGCANCEL + "CANCEL", VAL(SIGCANCEL,SH_SIGIGNORE), S("Thread cancellation"), +#endif /*SIGCANCEL */ #ifdef SIGCHLD "CHLD", VAL(SIGCHLD,SH_SIGFAULT), S("Death of Child"), # ifdef SIGCLD @@ -71,6 +74,9 @@ "CONT", VAL(SIGCONT,SH_SIGIGNORE), S("Stopped process continued"), #endif /* SIGCONT */ "DEBUG", VAL(TRAP(SH_DEBUGTRAP),0), "", +#ifdef SIGDANGER + "DANGER", VAL(SIGDANGER,0), S("System crash soon"), +#endif /* SIGDANGER */ #ifdef SIGDIL "DIL", VAL(SIGDIL,0), S("DIL signal"), #endif /* SIGDIL */ @@ -99,6 +105,12 @@ #ifdef SIGIOT "IOT", VAL(SIGIOT,SH_SIGDONE), S("Abort"), #endif /* SIGIOT */ +#ifdef SIGJVM1 + "JVM1", VAL(SIGJVM1,SH_SIGIGNORE), S("Special signal used by Java Virtual Machine"), +#endif /*SIGJVM1 */ +#ifdef SIGJVM2 + "JVM2", VAL(SIGJVM2,SH_SIGIGNORE), S("Special signal used by Java Virtual Machine"), +#endif /*SIGJVM2 */ "KEYBD", VAL(TRAP(SH_KEYTRAP),0), "", #ifdef SIGKILL "KILL", VAL(SIGKILL,0), S("Killed"), @@ -135,31 +147,13 @@ #endif /* SIGPWR */ #ifdef SIGQUIT "QUIT", VAL(SIGQUIT,SH_SIGDONE|SH_SIGINTERACTIVE), S("Quit"), -#ifdef __SIGRTMIN -#undef SIGRTMIN -#define SIGRTMIN __SIGRTMIN -#else -#ifdef _SIGRTMIN -#undef SIGRTMIN -#define SIGRTMIN _SIGRTMIN -#endif -#endif +#endif /* SIGQUIT */ #ifdef SIGRTMIN - "RTMIN", VAL(SIGRTMIN,0), S("Lowest priority realtime signal"), + "RTMIN", VAL(SH_SIGRTMIN,SH_SIGRUNTIME), S("Lowest priority realtime signal"), #endif /* SIGRTMIN */ -#ifdef __SIGRTMAX -#undef SIGRTMAX -#define SIGRTMAX __SIGRTMAX -#else -#ifdef _SIGRTMAX -#undef SIGRTMAX -#define SIGRTMAX _SIGRTMAX -#endif -#endif #ifdef SIGRTMAX - "RTMAX", VAL(SIGRTMAX,0), S("Highest priority realtime signal"), + "RTMAX", VAL(SH_SIGRTMAX,SH_SIGRUNTIME), S("Highest priority realtime signal"), #endif /* SIGRTMAX */ -#endif /* SIGQUIT */ "SEGV", VAL(SIGSEGV,0), S("Memory fault"), #ifdef SIGSTOP "STOP", VAL(SIGSTOP,0), S("Stopped (SIGSTOP)"), @@ -205,9 +199,6 @@ #ifdef SIGMIGRATE "MIGRATE", VAL(SIGMIGRATE,0), S("Migrate process"), #endif /* SIGMIGRATE */ -#ifdef SIGDANGER - "DANGER", VAL(SIGDANGER,0), S("System crash soon"), -#endif /* SIGDANGER */ #ifdef SIGSOUND "SOUND", VAL(SIGSOUND,0), S("Sound completed"), #endif /* SIGSOUND */ @@ -223,5 +214,8 @@ #ifdef SIGXFSZ "XFSZ", VAL(SIGXFSZ,SH_SIGDONE|SH_SIGINTERACTIVE), S("Exceeded file size limit"), #endif /* SIGXFSZ */ +#ifdef SIGXRES + "XRES", VAL(SIGXRES,SH_SIGDONE|SH_SIGINTERACTIVE), S("Exceeded resource control"), +#endif /* SIGRES */ "", 0, 0 }; Index: src/lib/libshell/common/data/solaris_cmdlist.h =================================================================== --- src/lib/libshell/common/data/solaris_cmdlist.h (revision 974) +++ src/lib/libshell/common/data/solaris_cmdlist.h (revision 1122) @@ -20,14 +20,14 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#ifndef _SOLARIS_CMDLIST_H -#define _SOLARIS_CMDLIST_H +#ifndef _SOLARIS_KSH_CMDLIST_H +#define _SOLARIS_KSH_CMDLIST_H -#pragma ident "@(#)solaris_cmdlist.h 1.1 07/07/17 SMI" +#pragma ident "%Z%%M% %I% %E% SMI" #ifdef __cplusplus extern "C" { @@ -42,19 +42,32 @@ /* POSIX compatible commands */ #ifdef _NOT_YET -#define XPG6CMDLIST(f) { "/usr/xpg6/bin/" #f, NV_BLTIN|NV_NOFREE, bltin(f) }, -#define XPG4CMDLIST(f) { "/usr/xpg4/bin/" #f, NV_BLTIN|NV_NOFREE, bltin(f) }, +#define XPG6CMDLIST(f) \ + { "/usr/xpg6/bin/" #f, NV_BLTIN|NV_BLTINOPT|NV_NOFREE, bltin(f) }, +#define XPG4CMDLIST(f) \ + { "/usr/xpg4/bin/" #f, NV_BLTIN|NV_BLTINOPT|NV_NOFREE, bltin(f) }, #else #define XPG6CMDLIST(f) #define XPG4CMDLIST(f) #endif /* NOT_YET */ /* * Commands which are 100% compatible with native Solaris versions (/bin is - * a softlink to ./usr/bin so both need to be listed here) + * a softlink to ./usr/bin, ksh93 takes care about the lookup) */ -#define BINCMDLIST(f) { "/bin/" #f, NV_BLTIN|NV_NOFREE, bltin(f) }, -/* Make all ksh93 builtins accessible when /usr/ast/bin was added to ${PATH} */ -#define ASTCMDLIST(f) { "/usr/ast/bin/" #f, NV_BLTIN|NV_NOFREE, bltin(f) }, +#define BINCMDLIST(f) \ + { "/bin/" #f, NV_BLTIN|NV_BLTINOPT|NV_NOFREE, bltin(f) }, +#define USRBINCMDLIST(f) \ + { "/usr/bin/" #f, NV_BLTIN|NV_BLTINOPT|NV_NOFREE, bltin(f) }, +#define SBINCMDLIST(f) \ + { "/sbin/" #f, NV_BLTIN|NV_BLTINOPT|NV_NOFREE, bltin(f) }, +#define SUSRBINCMDLIST(f) \ + { "/usr/sbin/" #f, NV_BLTIN|NV_BLTINOPT|NV_NOFREE, bltin(f) }, +/* + * Make all ksh93 builtins accessible when /usr/ast/bin was added to + * /usr/xpg6/bin:/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/bin:/opt/SUNWspro/bin + */ +#define ASTCMDLIST(f) \ + { "/usr/ast/bin/" #f, NV_BLTIN|NV_BLTINOPT|NV_NOFREE, bltin(f) }, /* undo ast_map.h #defines to avoid collision */ #undef basename @@ -91,14 +104,17 @@ ASTCMDLIST(join) XPG4CMDLIST(ln) ASTCMDLIST(ln) +BINCMDLIST(logname) ASTCMDLIST(logname) BINCMDLIST(mkdir) ASTCMDLIST(mkdir) +BINCMDLIST(mkfifo) ASTCMDLIST(mkfifo) XPG4CMDLIST(mv) ASTCMDLIST(mv) ASTCMDLIST(paste) ASTCMDLIST(pathchk) +BINCMDLIST(rev) ASTCMDLIST(rev) XPG4CMDLIST(rm) ASTCMDLIST(rm) @@ -106,17 +122,23 @@ ASTCMDLIST(rmdir) XPG4CMDLIST(stty) ASTCMDLIST(stty) +BINCMDLIST(sum) +ASTCMDLIST(sum) +SUSRBINCMDLIST(sync) +SBINCMDLIST(sync) +BINCMDLIST(sync) +ASTCMDLIST(sync) XPG4CMDLIST(tail) ASTCMDLIST(tail) BINCMDLIST(tee) ASTCMDLIST(tee) +BINCMDLIST(tty) ASTCMDLIST(tty) ASTCMDLIST(uname) BINCMDLIST(uniq) ASTCMDLIST(uniq) BINCMDLIST(wc) ASTCMDLIST(wc) -/* End-of-generated-data. */ /* Mandatory for ksh93 test suite and AST scripts */ BINCMDLIST(getconf) @@ -125,4 +147,4 @@ } #endif -#endif /* _SOLARIS_CMDLIST_H */ +#endif /* !_SOLARIS_KSH_CMDLIST_H */ Index: src/lib/libshell/common/data/aliases.c =================================================================== --- src/lib/libshell/common/data/aliases.c (revision 974) +++ src/lib/libshell/common/data/aliases.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/data/limits.c =================================================================== --- src/lib/libshell/common/data/limits.c (revision 974) +++ src/lib/libshell/common/data/limits.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/data/testops.c =================================================================== --- src/lib/libshell/common/data/testops.c (revision 974) +++ src/lib/libshell/common/data/testops.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/data/strdata.c =================================================================== --- src/lib/libshell/common/data/strdata.c (revision 974) +++ src/lib/libshell/common/data/strdata.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/data/msg.c =================================================================== --- src/lib/libshell/common/data/msg.c (revision 974) +++ src/lib/libshell/common/data/msg.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -96,6 +96,7 @@ const char e_badexport[] = "%s: invalid export name"; const char e_badref[] = "%s: reference variable cannot be an array"; const char e_noarray[] = "%s: cannot be an array"; +const char e_badappend[] = "%s: invalid append to associative array"; const char e_noref[] = "%s: no reference name"; const char e_selfref[] = "%s: invalid self reference"; const char e_noalias[] = "%s: alias not found\n"; Index: src/lib/libshell/common/data/keywords.c =================================================================== --- src/lib/libshell/common/data/keywords.c (revision 974) +++ src/lib/libshell/common/data/keywords.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/data/variables.c =================================================================== --- src/lib/libshell/common/data/variables.c (revision 974) +++ src/lib/libshell/common/data/variables.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -91,6 +91,7 @@ ".sh.fun", 0, (char*)0, ".sh.subshell", NV_INTEGER|NV_SHORT|NV_NOFREE, (char*)0, ".sh.level", 0, (char*)0, + ".sh.lineno", NV_INTEGER|NV_RDONLY, (char*)0, #if SHOPT_FS_3D "VPATH", 0, (char*)0, #endif /* SHOPT_FS_3D */ @@ -103,3 +104,5 @@ "", 0, (char*)0 }; + +const char *nv_discnames[] = { "get", "set", "append", "unset", 0 }; Index: src/lib/libshell/common/data/builtins.c =================================================================== --- src/lib/libshell/common/data/builtins.c (revision 974) +++ src/lib/libshell/common/data/builtins.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -37,14 +37,11 @@ # define bltin(x) 0 #endif -#ifndef SH_CMDLIB_DIR -# define SH_CMDLIB_DIR "/opt/ast/bin" -#endif #if defined(SHOPT_CMDLIB_DIR) && !defined(SHOPT_CMDLIB_HDR) # define SHOPT_CMDLIB_HDR <cmdlist.h> #endif #define Q(f) #f /* libpp cpp workaround -- fixed 2005-04-11 */ -#define CMDLIST(f) SH_CMDLIB_DIR "/" Q(f), NV_BLTIN|NV_NOFREE, bltin(f), +#define CMDLIST(f) SH_CMDLIB_DIR "/" Q(f), NV_BLTIN|NV_BLTINOPT|NV_NOFREE, bltin(f), #undef basename #undef dirname @@ -64,19 +61,20 @@ "break", NV_BLTIN|BLT_ENV|BLT_SPC, bltin(break), "continue", NV_BLTIN|BLT_ENV|BLT_SPC, bltin(break), "typeset", NV_BLTIN|BLT_ENV|BLT_SPC|BLT_DCL,bltin(typeset), - "test", NV_BLTIN|BLT_ENV|NV_NOFREE, bltin(test), + "test", NV_BLTIN|BLT_ENV, bltin(test), "[", NV_BLTIN|BLT_ENV, bltin(test), "let", NV_BLTIN|BLT_ENV, bltin(let), - "export", NV_BLTIN|BLT_SPC|BLT_DCL, bltin(readonly), + "export", NV_BLTIN|BLT_ENV|BLT_SPC|BLT_DCL,bltin(readonly), + ".", NV_BLTIN|BLT_ENV|BLT_SPC, bltin(dot_cmd), #if SHOPT_BASH "local", NV_BLTIN|BLT_ENV|BLT_SPC|BLT_DCL,bltin(typeset), #endif #if _bin_newgrp || _usr_bin_newgrp "newgrp", NV_BLTIN|BLT_ENV|BLT_SPC, Bltin(login), #endif /* _bin_newgrp || _usr_bin_newgrp */ - ".", NV_BLTIN|BLT_ENV|BLT_SPC, bltin(dot_cmd), "alias", NV_BLTIN|BLT_SPC|BLT_DCL, bltin(alias), "hash", NV_BLTIN|BLT_SPC|BLT_DCL, bltin(alias), + "enum", NV_BLTIN|BLT_ENV|BLT_SPC|BLT_DCL,bltin(enum), "exit", NV_BLTIN|BLT_ENV|BLT_SPC, bltin(return), "eval", NV_BLTIN|BLT_ENV|BLT_SPC|BLT_EXIT,bltin(eval), "fc", NV_BLTIN|BLT_ENV|BLT_EXIT, bltin(hist), @@ -98,20 +96,19 @@ "bg", NV_BLTIN|BLT_ENV, bltin(bg), "fg", NV_BLTIN|BLT_ENV|BLT_EXIT, bltin(bg), "disown", NV_BLTIN|BLT_ENV, bltin(bg), - "kill", NV_BLTIN|BLT_ENV|NV_NOFREE, bltin(kill), + "kill", NV_BLTIN|BLT_ENV, bltin(kill), # else - "/bin/kill", NV_BLTIN|BLT_ENV|NV_NOFREE, bltin(kill), + "/bin/kill", NV_BLTIN|BLT_ENV, bltin(kill), # endif /* SIGTSTP */ "jobs", NV_BLTIN|BLT_ENV, bltin(jobs), #endif /* JOBS */ "false", NV_BLTIN|BLT_ENV, bltin(false), -SH_CMDLIB_DIR "/getconf",NV_BLTIN|BLT_ENV, bltin(getconf), "getopts", NV_BLTIN|BLT_ENV, bltin(getopts), "print", NV_BLTIN|BLT_ENV, bltin(print), - "printf", NV_BLTIN|NV_NOFREE, bltin(printf), - "pwd", NV_BLTIN|NV_NOFREE, bltin(pwd), + "printf", NV_BLTIN|BLT_ENV, bltin(printf), + "pwd", NV_BLTIN, bltin(pwd), "read", NV_BLTIN|BLT_ENV, bltin(read), - "sleep", NV_BLTIN|NV_NOFREE, bltin(sleep), + "sleep", NV_BLTIN, bltin(sleep), "alarm", NV_BLTIN, bltin(alarm), "ulimit", NV_BLTIN|BLT_ENV, bltin(ulimit), "umask", NV_BLTIN|BLT_ENV, bltin(umask), @@ -131,6 +128,7 @@ CMDLIST(basename) CMDLIST(chmod) CMDLIST(dirname) + CMDLIST(getconf) CMDLIST(head) CMDLIST(mkdir) CMDLIST(logname) @@ -684,6 +682,8 @@ "[+i?Ignore this \aoptstring\a when generating help. Used when " "combining \aoptstring\a values from multiple passes.]" "[+l?Display only \alongname\a options in help messages.]" + "[+n?Associate -\anumber\a and +\anumber\a options with the first " + "option with numeric arguments.]" "[+o?The \b-\b option character prefix is optional (supports " "obsolete \bps\b(1) option syntax.)]" "[+p?\anumber\a specifies the number of \b-\b characters that must " @@ -1100,6 +1100,8 @@ "[s?Write the output as an entry in the shell history file instead of " "standard output.]" "[u]:[fd:=1?Write to file descriptor number \afd\a instead of standard output.]" +"[v?Treat each \astring\a as a variable name and write the value in \b%B\b " + "format. Cannot be used with \b-f\b.]" "\n" "\n[string ...]\n" "\n" @@ -1249,6 +1251,7 @@ "is a terminal or pipe.]" "[A?Unset \avar\a and then create an indexed array containing each field in " "the line starting at index 0.]" +"[C?Unset \avar\a and read \avar\a as a compound variable.]" "[d]:[delim?Read until delimiter \adelim\a instead of to the end of line.]" "[p?Read from the current co-process instead of standard input. An end of " "file causes \bread\b to disconnect the co-process so that another " @@ -1368,14 +1371,19 @@ "[D\f:dump-strings\f?Do not execute the script, but output the set of double " "quoted strings preceded by a \b$\b. These strings are needed for " "localization of the script to different locales.]" -"[E?Reads the file \b${ENV-$HOME/.kshrc}\b, if it exists, as a profile. " +"[E?Reads the file " +#if SHOPT_SYSRC + "\b/etc/ksh.kshrc\b, if it exists, as a profile, followed by " +#endif + "\b${ENV-$HOME/.kshrc}\b, if it exists, as a profile. " "On by default for interactive shells; use \b+E\b to disable.]" #if SHOPT_PFSH "[P?Invoke the shell as a profile shell. See \bpfexec\b(1).]" #endif #if SHOPT_KIA "[R]:[file?Do not execute the script, but create a cross reference database " - "in \afile\a that can be used a separate shell script browser.]" + "in \afile\a that can be used a separate shell script browser. The " + "-R option requires a script to be specified as the first operand.]" #endif /* SHOPT_KIA */ #if SHOPT_BASH "\fbash2\f" @@ -1424,6 +1432,9 @@ "[A]:[name?Assign the arguments sequentially to the array named by \aname\a " "starting at subscript 0 rather than to the positional parameters.]" "\fabc\f" +"[06:default?Restore all non-command line options to the default settings.]" +"[07:state?List the current option state in the form of a \bset\b command " + "that can be executed to restore the state.]" "\n" "\n[arg ...]\n" "\n" @@ -1534,7 +1545,7 @@ ; const char sh_opttypeset[] = -"+[-1c?\n@(#)$Id: typeset (AT&T Research) 2003-01-15 $\n]" +"+[-1c?\n@(#)$Id: typeset (AT&T Research) 2008-06-09 $\n]" USAGE_LICENSE "[+NAME?\f?\f - declare or display variables with attributes]" "[+DESCRIPTION?Without the \b-f\b option, \b\f?\f\b sets, unsets, " @@ -1571,10 +1582,12 @@ "[+?\b\f?\f\b is built-in to the shell as a declaration command so that " "field splitting and pathname expansion are not performed on " "the arguments. Tilde expansion occurs on \avalue\a.]" -#if SHOPT_BASH -"[a?Ignored, used for bash compatibility.]" +#if 1 +"[a]:?[type?Indexed array. This is the default. If \b[\b\atype\a\b]]\b is " + "specified, each subscript is interpreted as a value of type \atype\a.]" +#else +"[a?Indexed array. this is the default.]" #endif -"[a?Indexed array. this is the default.]" "[b?Each \aname\a may contain binary data. Its value is the mime " "base64 encoding of the data. It can be used with \b-Z\b, " "to specify fixed sized fields.]" @@ -1588,7 +1601,8 @@ "[p?Causes the output to be in a format that can be used as input to the " "shell to recreate the attributes for variables.]" "[r?Enables readonly. Once enabled it cannot be disabled. See " - "\breadonly\b(1).]" + "\breadonly\b(1). Within a type definition, this variable must be " + "specified when creating each instance.]" "[s?Used with \b-i\b to restrict integer size to short.]" "[t?When used with \b-f\b, enables tracing for each of the specified " "functions. Otherwise, \b-t\b is a user defined attribute and " @@ -1602,6 +1616,8 @@ "[A?Associative array. Each \aname\a will converted to an associate " "array. If a variable already exists, the current value will " "become index \b0\b.]" +"[C?Compound variable. Each \aname\a will be a compound variable. If " + "the variable already exists, it will first be unset.]" "[E]#?[n:=10?Floating point number represented in scientific notation. " "\an\a specifies the number of significant figures when the " "value is expanded.]" @@ -1617,6 +1633,19 @@ "[R]#?[n?Right justify. If \an\a is given it represents the field width. If " "the \b-Z\b attribute is also specified, then zeros will " "be used as the fill character. Otherwise, spaces are used.]" +"[X]#?[n:=10?Floating point number represented in hexadecimal notation. " + "\an\a specifies the number of significant figures when the " + "value is expanded.]" + +#ifdef SHOPT_TYPEDEF +"[h]:[string?Used within a type definition to provide a help string " + "for variable \aname\a. Otherwise, it is ignored.]" +"[S?Used with a type definition to indicate that the variable is shared by " + "each instance of the type. When used inside a function defined " + "with the \bfunction\b reserved word, the specified variables " + "will have function static scope. Otherwise, the variable is " + "unset prior to processing the assignment list.]" +#endif "[T]:[tname?\atname\a is the name of a type name given to each \aname\a.]" "[Z]#?[n?Zero fill. If \an\a is given it represents the field width.]" "\n" @@ -1784,7 +1813,7 @@ #endif /* SHOPT_FS_3D */ const char sh_optwhence[] = -"[-1c?\n@(#)$Id: whence (AT&T Research) 1999-07-07 $\n]" +"[-1c?\n@(#)$Id: whence (AT&T Research) 2007-04-24 $\n]" USAGE_LICENSE "[+NAME?whence - locate a command and describe its type]" "[+DESCRIPTION?Without \b-v\b, \bwhence\b writes on standard output an " @@ -1797,7 +1826,9 @@ "[a?Displays all uses for each \aname\a rather than the first.]" "[f?Do not check for functions.]" "[p?Do not check to see if \aname\a is a reserved word, a built-in, " - "an alias, or a function.]" + "an alias, or a function. This turns off the \b-v\b option.]" +"[q?Quiet mode. Returns 0 if all arguments are built-ins, functions, or are " + "programs found on the path.]" "[v?For each name you specify, the shell displays a line that indicates " "if that name is one of the following:]{" "[+?Reserved word]" @@ -1828,6 +1859,5 @@ const char e_nospace[] = "out of memory"; const char e_nofork[] = "cannot fork"; const char e_nosignal[] = "%s: unknown signal name"; -const char e_numeric[] = "*([0-9])?(.)*([0-9])"; const char e_condition[] = "condition(s) required"; const char e_cneedsarg[] = "-c requires argument"; Index: src/lib/libshell/common/data/options.c =================================================================== --- src/lib/libshell/common/data/options.c (revision 974) +++ src/lib/libshell/common/data/options.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -25,7 +25,7 @@ #include "shtable.h" #if SHOPT_BASH -# define bashopt(a,b) a, b|SH_BASHOPT, +# define bashopt(a,b) a, b|SH_BASHOPT, # define bashextra(a,b) a, b|SH_BASHEXTRA, #else # define bashopt(a,b) @@ -92,8 +92,15 @@ bashextra("physical", SH_PHYSICAL) bashextra("posix", SH_POSIX) "privileged", SH_PRIVILEGED, -#if SHOPT_PFSH +#if SHOPT_BASH + "profile", SH_LOGIN_SHELL|SH_COMMANDLINE, +# if SHOPT_PFSH + "pfsh", SH_PFSH|SH_COMMANDLINE, +# endif +#else +# if SHOPT_PFSH "profile", SH_PFSH|SH_COMMANDLINE, +# endif #endif bashopt("progcomp", SH_PROGCOMP) bashopt("promptvars", SH_PROMPTVARS) @@ -115,13 +122,15 @@ const Shtable_t shtab_attributes[] = { + {"-Sshared", NV_REF|NV_TAGGED}, {"-nnameref", NV_REF}, {"-xexport", NV_EXPORT}, {"-rreadonly", NV_RDONLY}, {"-ttagged", NV_TAGGED}, - {"-llong", (NV_INTEGER|NV_DOUBLE|NV_LONG)}, - {"-Eexponential",(NV_INTEGER|NV_DOUBLE|NV_EXPNOTE)}, - {"-Ffloat", (NV_INTEGER|NV_DOUBLE)}, + {"-llong", (NV_DOUBLE|NV_LONG)}, + {"-Eexponential",(NV_DOUBLE|NV_EXPNOTE)}, + {"-Xhexfloat", (NV_DOUBLE|NV_HEXFLOAT)}, + {"-Ffloat", NV_DOUBLE}, {"-llong", (NV_INTEGER|NV_LONG)}, {"-sshort", (NV_INTEGER|NV_SHORT)}, {"-uunsigned", (NV_INTEGER|NV_UNSIGN)}, Index: src/lib/libshell/common/data/lexstates.c =================================================================== --- src/lib/libshell/common/data/lexstates.c (revision 974) +++ src/lib/libshell/common/data/lexstates.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -56,7 +56,7 @@ S_NAME, S_RES, S_NAME, S_NAME, S_NAME, S_NAME, S_NAME, S_NAME, #endif /* SHOPT_NAMESPACE */ S_NAME, S_NAME, S_NAME, S_RES, S_RES, S_RES, S_NAME, S_RES, - S_NAME, S_NAME, S_NAME, S_REG, S_OP, S_REG, S_TILDE,S_REG, + S_NAME, S_NAME, S_NAME, S_BRACE,S_OP, S_BRACE,S_TILDE,S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, @@ -360,7 +360,7 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, S_QUOTE,0, S_DOL, 0, S_PAT, S_LIT, - S_PAT, S_PAT, S_PAT, 0, 0, 0, 0, S_SLASH, + S_PAT, S_PAT, S_PAT, 0, S_COM, 0, S_DOT, S_SLASH, 0, S_DIG, S_DIG, S_DIG, S_DIG, S_DIG, S_DIG, S_DIG, S_DIG, S_DIG, S_COLON,0, 0, S_EQ, 0, S_PAT, 0, 0, 0, 0, 0, 0, 0, 0, @@ -409,3 +409,4 @@ const char e_lexlongquote[] = "line %d: %c quote may be missing"; const char e_lexzerobyte[] = "zero byte"; const char e_lexemptyfor[] = "line %d: empty for list"; +const char e_lextypeset[] = "line %d: %s invalid typeset option order"; Index: src/lib/libshell/common/data/math.tab =================================================================== --- src/lib/libshell/common/data/math.tab (revision 974) +++ src/lib/libshell/common/data/math.tab (revision 1122) @@ -1,6 +1,6 @@ # <return type: i:integer f:floating-point> <#floating-point-args> <function-name> [<alias> ...] # <function-name>l variants are handled by features/math.sh -# @(#)math.tab (AT&T Research) 2006-10-18 +# @(#)math.tab (AT&T Research) 2008-05-22 f 1 acos f 1 acosh f 1 asin @@ -9,6 +9,7 @@ f 2 atan2 f 1 atanh f 1 cbrt +f 1 ceil f 2 copysign f 1 cos f 1 cosh Index: src/lib/libshell/common/COMPATIBILITY =================================================================== --- src/lib/libshell/common/COMPATIBILITY (revision 974) +++ src/lib/libshell/common/COMPATIBILITY (revision 1122) @@ -125,5 +125,10 @@ the stty lnext character is set to control-v or is unset. The sequence escape control-v will display the shell version. +29. In ksh88, DEBUG traps were executed. after each command. In ksh93 + DEBUG traps are exeucted before each command. + +30. In ksh88, a redirection to a file name given by an empty string was + ignored. In ksh93, this is an error. I am interested in expanding this list so please let me know if you uncover any others. Index: src/lib/libshell/common/sh.1 =================================================================== --- src/lib/libshell/common/sh.1 (revision 974) +++ src/lib/libshell/common/sh.1 (revision 1122) @@ -628,10 +628,12 @@ One or more variable assignments can start a simple command or can be arguments to the .BR typeset , +.BR enum , .BR export , or .B readonly -special built-in commands. +special built-in commands as well as +to other declaration commands created as types. The syntax for an \f2assignment\^\fP is of the form: .TP .PD 0 @@ -672,6 +674,16 @@ Nested variable assignment. Multiple assignments can be specified by separating each of them with a \f3;\fP. The previous value is unset before the assignment. +Other declaration commands such as +.BR readonly, +.BR enum , +and +other declaration commands can be used in place of +.BR typeset . +.TP +\f3\|.\fP \f2filename\^\fP +Include the assignment commands contained in +.IR filename . .PD .RE .P @@ -839,15 +851,20 @@ .B \(ap login name. .SS Command Substitution. -The standard output from a command enclosed in +The standard output from a command list enclosed in parentheses preceded by a dollar sign ( -.B $(\|) -) -or a pair of grave accents (\^\f3\*`\^\*`\fP\^) +\f3$(\fP\f2list\^\fP\f3)\fP +), +or in a brace group preceded by a dollar sign ( +\f3${ \fP\f2list\^\fP\f3;}\fP +), or in a pair of grave accents (\^\f3\*`\^\*`\fP\^) may be used as part or all of a word; trailing new-lines are removed. -In the second (obsolete) form, the string between the quotes is processed +In the second case, the \f3{\fP and \f3}\fP are treated as a reserved words +so that \f3{\fP must be followed by a \f2blank\^\fP and \f3}\fP must +appear at the beginning of the line or follow a \f3;\fP. +In the third (obsolete) form, the string between the quotes is processed for special quoting characters before the command is executed (see .I Quoting\^ below). @@ -859,6 +876,11 @@ \^\f3$(\^\fP\f2n\^\fP\f3<#\^)\fP will expand to the current byte offset for file descriptor .IR n . +Except for the second form, the command list is run in a subshell so that no +side effects are possible. +For the second form, the final +.B } +will be recognized as a reserved word after any token. .SS Arithmetic Substitution. An arithmetic expression enclosed in double parentheses preceded by a dollar sign ( @@ -982,7 +1004,7 @@ The value of all subscripts must be in the range of -0 through 1,048,575. +0 through 16,777,215. Indexed arrays need not be declared. Any reference to a variable with a valid subscript is @@ -1065,10 +1087,11 @@ name has been passed to the function. .sp .5 .PP -If either of the floating point attributes, +If any of the floating point attributes, .BR \-E , +.BR \-F , or -.BR \-F , +.BR \-X , or the integer attribute, .BR \-i , is set for @@ -1107,8 +1130,10 @@ .I parameter\^ is followed by a letter, digit, or underscore that is not to be interpreted as part of its name, -when the variable name contains a \fB\s+2.\s-2\fP, -or when a variable is subscripted. +when the variable name contains a \fB\s+2.\s-2\fP. +The braces are also required when a variable is subscripted +unless it is part of an Arithmetic Expression +or a Conditional Expression. If .I parameter\^ is one or more digits then it is a positional parameter. @@ -1129,12 +1154,22 @@ .I vname\^ with subscript .B \(** -or -.B @ +.BR @ , +or of the form +.I sub1\^ +.B .. +.IR sub2 . is used, then the value for each of the -elements +elements between +.I sub1\^ +and +.I sub2\^ +inclusive (or all elments for +.B \(** +and +.BR @ ) is substituted, separated by the first character of @@ -1163,6 +1198,13 @@ .I vname\^ is substituted. .TP +.PD 0 +\f3${@\fP\f2vname\^\fP\f3}\fP +Expands to the type name (See +.I "Type Variables"\^ +below) or attributes of the variable referred to by +.IR vname . +.TP \f3${!\fP\f2vname\^\fP\f3}\fP Expands to the name of the variable referred to by .IR vname . @@ -1176,9 +1218,12 @@ Expands to name of the subscript unless .I subscript\^ is -.B * -or +.BR * , .BR @ . +or of the form +.I sub1\^ +.B .. +.IR sub2 . When .I subscript\^ is @@ -1194,6 +1239,19 @@ same as above, except that when used in double quotes, each array subscript yields a separate argument. +When +.I subscript\^ +is of the form +.I sub1\^ +.B .. +.I sub2\^ +it expands +to the list of subscripts between +.I sub1\^ +and +.I sub2\^ +inclusive using the same quoting rules as +.BR @ . .TP \f3${!\fP\f2prefix\^\fP\f3*}\fP Expands to the names of the variables whose names begin with @@ -1449,6 +1507,16 @@ .B .SM MAIL file when checking for mail. +When a discipline function is invoked, +.B _ +is initialized as a reference to the variable associated with +the call to this function. +Finally when +.B _ +is used as the name of the first variable of a type definition, +the new type is derived from the type of the first variable (See +.I "Type Variables"\^ +below.). .TP .B ! The process number of the last background command invoked or @@ -1516,6 +1584,15 @@ .B .sh.fun The name of the current function that is being executed. .TP +.B .sh.level +Set to the current function depth. This can be changed +inside a DEBUG trap and will set the context to the specified +level. +.TP +.B .sh.lineno +Set during a DEBUG trap to the line number for the caller of +each function. +.TP .B .sh.match An indexed array which stores the most recent match and sub-pattern matches after conditional pattern matches that match and after @@ -1663,7 +1740,7 @@ the value to generate the pathname of the script that will be executed when the shell -is invoked +is invoked interactively (see .I Invocation\^ below). @@ -1673,6 +1750,15 @@ .B function definitions. The default value is \fB$HOME/.kshrc\fP. +On systems that support a system wide \fB/etc/ksh.kshrc\fP initialization file, +if the filename generated by the expansion of +.SM +.B ENV +begins with +.B /./ +or +.B .\^/.\^/ +the system wide initialization file will not be executed. .TP .B .SM FCEDIT @@ -2313,7 +2399,7 @@ and subdirectories. If followed by a .B / -than only directories and subdirectories will match. +then only directories and subdirectories will match. .TP .B ? Matches any single character. @@ -2417,7 +2503,7 @@ to cause the shortest match to the specified \f2pattern-list\^\fP to be used. .PP -When \f2pattern-list\^\fP is contained within parenthesis, +When \f2pattern-list\^\fP is contained within parentheses, the backslash character \f3\e\fP is treated specially even when inside a character class. All ANSI-C character escapes are recognized and match the specified character. In addition @@ -2511,9 +2597,9 @@ matches the same string as the sub-pattern itself. .PP Finally a pattern can contain sub-patterns of the form -\f3\(ap(\fP\f2options\^\fP\f3:\fP\f2pattern-list\^\fP\f3)\fP. +\f3\(ap(\fP\f2options\^\fP\f3:\fP\f2pattern-list\^\fP\f3)\fP, where either \f2options\^\fP or \f3:\fP\f2pattern-list\^\fP -can be omitted. Unlike, the other compound patterns, +can be omitted. Unlike the other compound patterns, these sub-patterns are not counted in the numbered sub-patterns. If \f2options\^\fP is present, it can consist of one or more of the following: @@ -2745,7 +2831,7 @@ In addition, the operator .B ** can be used for exponentiation. -It has higher precedence than multiplication as is left associative. +It has higher precedence than multiplication and is left associative. In addition, when the value of an arithmetic variable or sub-expression can be represented as a long integer, all C language integer arithmetic operations can be performed. @@ -2766,9 +2852,10 @@ An internal representation of a .I variable\^ as a double precision floating point can be specified with the -\f3\-E\fP \*(OK\f2n\^\fP\*(CK +\f3\-E\fP \*(OK\f2n\^\fP\*(CK, +\f3\-F\fP \*(OK\f2n\^\fP\*(CK, or -\f3\-F\fP \*(OK\f2n\^\fP\*(CK +\f3\-X\fP \*(OK\f2n\^\fP\*(CK option of the .B typeset special built-in command. @@ -2783,9 +2870,14 @@ .B \-F option causes the expansion to be represented as a floating decimal number when it is expanded. +The +.B \-X +option cause the expansion to be represented using the +.B %a +format defined by ISO C-99. The optional option argument .I n -defines the number of places after the decimal point in this case. +defines the number of places after the decimal (or radix) point in this case. .PP An internal integer representation of a .I variable\^ @@ -2804,6 +2896,7 @@ assignment to a variable with the .BR \-E , .BR \-F , +.BR \-X , or .B \-i attribute. @@ -3028,7 +3121,7 @@ .I string\^ does not match .IR pattern . -With the +When the .I string\^ matches the .I pattern\^ @@ -3330,7 +3423,7 @@ and the .B ># and -.B ># +.B <# forms, is preceded by .BI { varname } @@ -3344,7 +3437,7 @@ or the any of the .B ># and -.B ># +.B <# forms is preceded by .BI { varname } @@ -3534,7 +3627,7 @@ defines local variables whose scope includes the current function. They can be passed to functions that they call in the -variable assignment list the precedes the call or as arguments +variable assignment list that precedes the call or as arguments passed as name references. Errors within functions return control to the caller. .PP @@ -3591,7 +3684,8 @@ Each variable can have zero or more discipline functions associated with it. The shell initially understands the discipline names \f3get\fP, -\f3set\fP, \f3append\fP, and \f3unset\fP but on most systems +\f3set\fP, \f3append\fP, and \f3unset\fP but can be added +when defining new types. On most systems others can be added at run time via the C programming interface extension provided by the .B builtin @@ -3623,12 +3717,107 @@ is the subscript of the variable, and .B .sh.value will contain the value being assigned inside the -.B .set +.B set discipline function. +The variable +.B _ +is a reference to the variable including the subscript if any. For the \f3set\fP discipline, changing .B .sh.value will change the value that gets assigned. +Finally, the expansion \f3${\fP\f2var\^\fP\f3.\fP\f2name\^\fP\f3}\fP, +when \f2name\^\fP is the name of a discipline, and there is +no variable of this name, is equivalent to the command substitution +\f3${ \fP\f2var\^\fP\f3.\fP\f2name\^\fP\f3;}\fP. + +.SS Type Variables. +Typed variables provide a way to create data structure and objects. +A type can be defined either by a shared library, by the +.B enum +built-in command described below, or by using the new +.B \-T +option of the +.B typeset +built-in command. +With the +.B \-T +option of +.BR typeset , +the type name, specified as an option argument to +.BR \-T , +is set with a compound variable assignment that defines the type. +Function definitions can appear inside the compound variable +assignment and these become discipline functions for this type and +can be invoked or redefined by each instance of the type. +.PP +When a type is defined a special built-in command of that name +is added. These built-ins are declaration commands and follow the +same expansion rules as all the special built-in commands defined +below that are preceded by \(dg\(dg. These commands can subsequently +be used inside further type definitions. The man page for these commands can +be generated by using the +.B \-\-man +option or any of the other +.B \-\- +options described with +.BR getopts . +The +.BR \-r , +.BR \-a , +.BR \-A , +.BR \-h , +and +.B \-S +options of +.B typeset +are permitted with each of these new built-ins. +.PP +An instance of a type is created by invoking the type name +followed by one or more instance names. +Each instance of the type is initialized with a copy of the sub-variables +except for sub-variables that are defined with the +.B \-S +option. Variables defined with the +.B \-S +are shared by all instances of the type. +Each instance can change the value of any sub-variable and can also +define new discipline functions of the same names +as those defined by the type definition as well as any +standard discipline names. +No additional sub-variables can be defined for any instance. +.PP +The +.B \-r +attribute for a sub-variable with a type causes the sub-variable +to be a required sub-variable. +Whenever an instance of a type is created, all required sub-variables +must be specified. +These sub-variables become readonly in each instance. +.PP +When +.B unset +is invoked on a sub-variable within a type, +and the +.B \-r +attribute has not been specified for this field, +the value is reset to the default value associative with +the type. +Invoking +.B unset +on a type instance not contained within another type deletes +all sub-variables and the variable itself. +.PP +A type definition can be derived from another type definition +by defining the first sub-variable name as +.B _ +and defining its type as the base type. +Any remaining definitions will be additions and modifications +that apply to the new type. +If the new type name is the same is that of the base type, +the type will be replaced and the original type will +no longer be accessible. + .SS Jobs. .PP If the @@ -3829,7 +4018,7 @@ as described above. If not found, and the file .B .paths -is found, and the this file contains a line of the form +is found, and this file contains a line of the form .BI FPATH= path where .I path\^ @@ -4244,7 +4433,7 @@ (User defined literal next character as defined by the .IR stty (1) -command. +command, or .B ^V if not defined.) @@ -4375,7 +4564,13 @@ .PP .TP 10 .BI M-[A -Equivalent to +If the cursor is at the end of the line, it is equivalent to +.B ^R +with +.I string\^ +set to the contents of the current line. +Otherwise, it is +equivalent to .BR ^P. .PP .TP 10 @@ -4471,7 +4666,7 @@ .BI _\&_ letter and if an alias of this name is defined, its value will be inserted on the input queue. -The can be used to program functions keys on many terminals. +This can be used to program function keys on many terminals. .PP .TP 10 .B M-. @@ -4769,7 +4964,12 @@ .BR k . .TP 10 [\f2count\fP]\f3[A\fP -Equivalent to +If cursor is at the end of the line it is equivalent to +.B / +with +.I string^\ +set to the contents of the current line. +Otherwise, it is quivalent to .BR k . .TP 10 [\f2count\fP]\f3j\fP @@ -5070,6 +5270,9 @@ .B = sign and field splitting and file name generation are not performed. +These are called +.I declaration\^ +built-ins. .PD .TP \(dg \f3:\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK @@ -5425,6 +5628,16 @@ .IR echo (1) for usage and description. .TP +\(dg\(dg \f3enum\fP \*(OK \f3\-i\fP \*(CK \f2type\^\fP\*(OK=(\f2value\^\fP .\|.\|.) \*(CK +Creates a declaration command named \f2type\^\fP that is an +integer type that allows one of the specifed \f2value\fPs as +enumeration names. If \f3=(\fP\f2value\^\ .\|.\|.\|\fP\f3)\fP is +omitted, then \f2type\^\fP must be an indexed array variable with at +least two elements and the values are taken from this array variable. +If +.B -i +is specified the values are case insensitive. +.TP \(dg \f3eval\fP \*(OK \f2arg\^\fP .\|.\|. \*(CK The arguments are read as input to the shell @@ -5891,7 +6104,7 @@ .BR \-n . The .B \-e -causes the above escape conventions to be applied +causes the above escape conventions to be applied. This is the default behavior. It reverses the effect of an earlier .BR \-r . @@ -5961,7 +6174,7 @@ to cause characters in .I arg\^ that are special in HTML and XML -to be output to be output as their entity name. +to be output as their entity name. .LI A .B %P @@ -5978,7 +6191,7 @@ .B %s to cause .I arg\^ -interpreted as a shell pattern +to be interpreted as a shell pattern and to be printed as an extended regular expression. .LI A @@ -6051,7 +6264,7 @@ on the command line determines which method is used. .TP -\f3read\fP \*(OK \f3\-Aprs\^\fP \*(CK \*(OK \f3\-d\fP \f2delim\^\fP\*(CK \*(OK \f3\-n\fP \f2n\^\fP\*(CK \*(OK \*(OK \f3\-N\fP \f2n\^\fP\*(CK \*(OK \*(OK \f3\-t\fP \f2timeout\^\fP\*(CK \*(OK \f3\-u\fP \f2unit\^\fP\*(CK \*(OK \f2vname\f3?\f2prompt\^\f1 \*(CK \*(OK \f2vname\^\fP .\|.\|. \*(CK +\f3read\fP \*(OK \f3\-ACprsv\^\fP \*(CK \*(OK \f3\-d\fP \f2delim\^\fP\*(CK \*(OK \f3\-n\fP \f2n\^\fP\*(CK \*(OK \*(OK \f3\-N\fP \f2n\^\fP\*(CK \*(OK \*(OK \f3\-t\fP \f2timeout\^\fP\*(CK \*(OK \f3\-u\fP \f2unit\^\fP\*(CK \*(OK \f2vname\f3?\f2prompt\^\f1 \*(CK \*(OK \f2vname\^\fP .\|.\|. \*(CK The shell input mechanism. One line is read and is broken up into fields using the characters in @@ -6117,6 +6330,12 @@ successive elements of the indexed array .IR vname. The +.B \-C +option causes the variable +.I vname\^ +to be read as a compound variable. Blanks will be ignored when +finding the beginning open parenthesis. +The .B \-p option causes the input line to be taken from the input pipe @@ -6208,7 +6427,7 @@ then it behaves the same as .BR exit . .TP -\(dg \f3set\fP \*(OK \f3\(+-CGabefhkmnoprstuvx\fP \*(CK \*(OK \f3\(+-o\fP \*(OK \f2option\^\fP \*(CK \*(CK .\|.\|. \*(OK \f3\(+-A\fP \f2vname\^\fP \*(CK \*(OK \f2arg\^\fP .\|.\|. \*(CK +\(dg \f3set\fP \*(OK \f3\(+-BCGabefhkmnoprstuvx\fP \*(CK \*(OK \f3\(+-o\fP \*(OK \f2option\^\fP \*(CK \*(CK .\|.\|. \*(OK \f3\(+-A\fP \f2vname\^\fP \*(CK \*(OK \f2arg\^\fP .\|.\|. \*(CK The options for this command have meaning as follows: .RS .PD 0 @@ -6230,6 +6449,9 @@ Enable brace pattern field generation. This is the default behavior. .TP 8 +.B \-B +Enable brace group expansion. On by default. +.TP 8 .B \-C Prevents redirection .B > @@ -6256,7 +6478,18 @@ state rather than waiting for the next prompt. .TP 8 .B \-e -If a command has a non-zero exit status, +Unless contained in a +.B \(bv\(bv +or +.B && +command, or the command following an +.B if +.B while +or +.B until +command or in the pipeline following +.BR ! , +if a command has a non-zero exit status, execute the .SM .B ERR @@ -6303,8 +6536,8 @@ All background jobs are run at a lower priority. This is the default mode. .TP 8 -.B bracexpand -Sans as +.B braceexpand +Same as .BR \-B . .TP 8 .B emacs @@ -6372,10 +6605,10 @@ A pipeline will not complete until all components of the pipeline have completed, and the return value will be the value of the last non-zero command -to fail or zero of no command has failed. +to fail or zero if no command has failed. .TP 8 .B showme -When enabled, simple commands or pipelines preceded by a a semicolon +When enabled, simple commands or pipelines preceded by a semicolon .RB ( ; ) will be displayed as if the .B xtrace @@ -6628,7 +6861,7 @@ .B while for infinite loops. .TP -\(dg\(dg \f3typeset\fP \*(OK \f3\(+-AHflabnprtux\^\fP \*(CK \*(OK \f3\(+-EFLRZi\*(OK\f2n\^\fP\*(CK \*(CK \*(OK \f2vname\^\fP\*(OK\f3=\fP\f2value\^\fP \*(CK \^ \*(CK .\|.\|. +\(dg\(dg \f3typeset\fP \*(OK \f3\(+-ACHSflbnprtux\^\fP \*(CK \*(OK \f3\(+-EFLRXZi\*(OK\f2n\^\fP\*(CK \*(CK \*(OK \f3\-T \f2tname\fP=(\f2assign_list\fP) \*(CK \*(OK \f3\-h \f2str\fP \*(CK \*(OK \f3\-a\fP \*(OK\f2type\fP\*(CK \*(CK \*(OK \f2vname\^\fP\*(OK\f3=\fP\f2value\^\fP \*(CK \^ \*(CK .\|.\|. Sets attributes and values for shell variables and functions. When invoked inside a function defined with the .B function @@ -6650,11 +6883,22 @@ Subscripts are strings rather than arithmetic expressions. .TP +.B \-C +unsets each +.I vname\^ +causes each to be a compound variable. +.TP .B \-a Declares .I vname\^ to be an indexed array. -This is optional unless except for compound variable assignments. +If +.I type\^ +is specified, it must be the name of an enumeration +type created with the +.B enum +command and it allows enumeration constants to be used +as subscripts. .TP .B \-E Declares @@ -6713,6 +6957,38 @@ .B \-L option is turned off. .TP +.B \-S +When used within the +.I assign_list\^ +of a type definition, it causes the specified sub-variable +to be shared by all instances of the type. +When used inside a function defined with the +.B function +reserved word, the specified variables will have +.I "function static\^" +scope. +Otherwise, the variable is unset prior to processing the assignment list. +.TP +.B \-T +Creates a type named by \fItname\^\fP using the compound +assignment +.I assign_list\^ +to \f2tname\fP. +.TP +.B \-X +Declares +.I vname\^ +to be a double precision floating point number +and expands using the +.B %a +format of ISO-C99. +If +.I n\^ +is non-zero, it defines the number of hex digits after +the radix point that is used when expanding +.IR vname . +The default is 10. +.TP .B \-Z Right justify and fill with leading zeros if the first non-blank character is a digit and the @@ -6778,6 +7054,15 @@ can be used to output the actual data in this buffer instead of the base64 encoding of the data. .TP +.B \-h +Used within type definitions to add information when generating +information about the sub-variable on the man page. +It is ignored when used outside of a type definition. +When used with +.B \-f +the information is associated with the corresponding discipline +function. +.TP .B \-i Declares .I vname\^ @@ -6913,7 +7198,7 @@ .B H nor .B S -options is specified, the limit applies to both. +option is specified, the limit applies to both. The current resource limit is printed when .I limit\^ is omitted. @@ -7001,7 +7286,10 @@ .IR vname s are unassigned, i.e., +except for sub-variables within a type, their values and attributes are erased. +For sub-variables of a type, the values are reset to the +default value from the type definition. Readonly variables cannot be unset. If the .B \-f @@ -7078,7 +7366,7 @@ produces a more verbose report. The .B \-f -options skips the search for functions. +option skips the search for functions. The .B \-p option @@ -7086,6 +7374,11 @@ .I name\^ even if name is an alias, a function, or a reserved word. The +.B \-p +option turns off the +.B \-v +option. +The .B \-a option is similar to the @@ -7123,7 +7416,7 @@ .I arg\^ and a file by the name of .I arg\^ -exits, then it reads and executes this script. +exists, then it reads and executes this script. Otherwise, if the first .I arg\^ does not contain a @@ -7146,6 +7439,19 @@ when it is invoked: .PP .PD 0 +.TP 8 +.B \-D +Do not execute the script, but output the set of double quoted strings +preceded by a +.BR $ . +These strings are needed for localization of the script to different locales. +.TP 8 +.B \-E +Reads the file named by the +.B ENV +variable or by +\s-1$HOME\s+1/\f3.\fPkshrc +if not defined after the profiles. .TP 10 .BI \-c If the @@ -7451,3 +7757,4 @@ It is a good idea to leave a space after the comma operator in arithmetic expressions to prevent the comma from being interpreted as the decimal point character in certain locales. + Index: src/lib/libshell/common/sh/macro.c =================================================================== --- src/lib/libshell/common/sh/macro.c (revision 974) +++ src/lib/libshell/common/sh/macro.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -71,11 +71,12 @@ char arith; /* set for ((...)) */ char let; /* set when expanding let arguments */ char zeros; /* strip leading zeros when set */ + char arrayok; /* $x[] ok for arrays */ + char subcopy; /* set when copying subscript */ + int dotdot; /* set for .. in subscript */ void *nvwalk; /* for name space walking*/ } Mac_t; -#define mac (*((Mac_t*)(sh.mac_context))) - #undef ESCAPE #define ESCAPE '\\' #define isescchar(s) ((s)>S_QUOTE) @@ -95,12 +96,12 @@ static int substring(const char*, const char*, int[], int); static void copyto(Mac_t*, int, int); -static void comsubst(Mac_t*,int); +static void comsubst(Mac_t*, Shnode_t*, int); static int varsub(Mac_t*); static void mac_copy(Mac_t*,const char*, int); -static void tilde_expand2(int); -static char *sh_tilde(const char*); -static char *special(int); +static void tilde_expand2(Shell_t*,int); +static char *sh_tilde(Shell_t*,const char*); +static char *special(Shell_t *,int); static void endfield(Mac_t*,int); static void mac_error(Namval_t*); static char *mac_getstring(char*); @@ -120,19 +121,19 @@ /* * perform only parameter substitution and catch failures */ -char *sh_mactry(register char *string) +char *sh_mactry(Shell_t *shp,register char *string) { if(string) { int jmp_val; - int savexit = sh.savexit; + int savexit = shp->savexit; struct checkpt buff; sh_pushcontext(&buff,SH_JMPSUB); jmp_val = sigsetjmp(buff.buff,0); if(jmp_val == 0) - string = sh_mactrim(string,0); + string = sh_mactrim(shp,string,0); sh_popcontext(&buff); - sh.savexit = savexit; + shp->savexit = savexit; return(string); } return(""); @@ -145,28 +146,31 @@ * yields a single pathname. * If <mode> negative, than expansion rules for assignment are applied. */ -char *sh_mactrim(char *str, register int mode) +char *sh_mactrim(Shell_t *shp, char *str, register int mode) { - register Mac_t *mp = (Mac_t*)sh.mac_context; - Mac_t savemac; + register Mac_t *mp = (Mac_t*)shp->mac_context; + Stk_t *stkp = shp->stk; + Mac_t savemac; savemac = *mp; - stakseek(0); + stkseek(stkp,0); mp->arith = (mode==3); mp->let = 0; - sh.argaddr = 0; + shp->argaddr = 0; mp->pattern = (mode==1||mode==2); mp->patfound = 0; - mp->assign = (mode<0); + mp->assign = 0; + if(mode<0) + mp->assign = -mode; mp->quoted = mp->lit = mp->split = mp->quote = 0; mp->sp = 0; - if(mp->ifsp=nv_getval(nv_scoped(IFSNOD))) + if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD))) mp->ifs = *mp->ifsp; else mp->ifs = ' '; - stakseek(0); + stkseek(stkp,0); fcsopen(str); copyto(mp,0,mp->arith); - str = stakfreeze(1); + str = stkfreeze(stkp,1); if(mode==2) { /* expand only if unique */ @@ -184,23 +188,24 @@ /* * Perform all the expansions on the argument <argp> */ -int sh_macexpand(register struct argnod *argp, struct argnod **arghead,int flag) +int sh_macexpand(Shell_t* shp, register struct argnod *argp, struct argnod **arghead,int flag) { - register int flags = argp->argflag; - register char *str = argp->argval; - register Mac_t *mp = (Mac_t*)sh.mac_context; - char **saveargaddr = sh.argaddr; - Mac_t savemac; + register int flags = argp->argflag; + register char *str = argp->argval; + register Mac_t *mp = (Mac_t*)shp->mac_context; + char **saveargaddr = shp->argaddr; + Mac_t savemac; + Stk_t *stkp = shp->stk; savemac = *mp; mp->sp = 0; - if(mp->ifsp=nv_getval(nv_scoped(IFSNOD))) + if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD))) mp->ifs = *mp->ifsp; else mp->ifs = ' '; - if(flag&ARG_OPTIMIZE) - sh.argaddr = (char**)&argp->argchn.ap; + if((flag&ARG_OPTIMIZE) && !shp->indebug) + shp->argaddr = (char**)&argp->argchn.ap; else - sh.argaddr = 0; + shp->argaddr = 0; mp->arghead = arghead; mp->quoted = mp->lit = mp->quote = 0; mp->arith = ((flag&ARG_ARITH)!=0); @@ -208,6 +213,7 @@ mp->split = !(flag&ARG_ASSIGN); mp->assign = !mp->split; mp->pattern = mp->split && !(flag&ARG_NOGLOB) && !sh_isoption(SH_NOGLOB); + mp->arrayok = mp->arith || (flag&ARG_ARRAYOK); str = argp->argval; fcsopen(str); mp->fields = 0; @@ -215,29 +221,31 @@ { mp->split = 0; mp->pattern = ((flag&ARG_EXP)!=0); - stakseek(0); + stkseek(stkp,0); } else { - stakseek(ARGVAL); - *stakptr(ARGVAL-1) = 0; + stkseek(stkp,ARGVAL); + *stkptr(stkp,ARGVAL-1) = 0; } mp->patfound = 0; + if(mp->pattern) + mp->arrayok = 0; copyto(mp,0,mp->arith); if(!arghead) { - argp->argchn.cp = stakfreeze(1); - if(sh.argaddr) + argp->argchn.cp = stkfreeze(stkp,1); + if(shp->argaddr) argp->argflag |= ARG_MAKE; } else { endfield(mp,mp->quoted); flags = mp->fields; - if(flags==1 && sh.argaddr) + if(flags==1 && shp->argaddr) argp->argchn.ap = *arghead; } - sh.argaddr = saveargaddr; + shp->argaddr = saveargaddr; *mp = savemac; return(flags); } @@ -246,28 +254,30 @@ * Expand here document which is stored in <infile> or <string> * The result is written to <outfile> */ -void sh_machere(Sfio_t *infile, Sfio_t *outfile, char *string) +void sh_machere(Shell_t *shp,Sfio_t *infile, Sfio_t *outfile, char *string) { register int c,n; register const char *state = sh_lexstates[ST_QUOTE]; register char *cp; - register Mac_t *mp = (Mac_t*)sh.mac_context; + register Mac_t *mp = (Mac_t*)shp->mac_context; + Lex_t *lp = (Lex_t*)mp->shp->lex_context; Fcin_t save; Mac_t savemac; + Stk_t *stkp = shp->stk; savemac = *mp; - stakseek(0); - sh.argaddr = 0; + stkseek(stkp,0); + shp->argaddr = 0; mp->sp = outfile; mp->split = mp->assign = mp->pattern = mp->patfound = mp->lit = mp->arith = mp->let = 0; mp->quote = 1; - mp->ifsp = nv_getval(nv_scoped(IFSNOD)); + mp->ifsp = nv_getval(sh_scoped(shp,IFSNOD)); mp->ifs = ' '; fcsave(&save); if(infile) fcfopen(infile); else fcsopen(string); - fcnotify(0); + fcnotify(0,lp); cp = fcseek(0); while(1) { @@ -285,7 +295,7 @@ n=state[*(unsigned char*)cp++]; break; default: - /* use state of alpah character */ + /* use state of alpha character */ n=state['a']; cp += len; } @@ -323,7 +333,7 @@ sfputc(outfile,ESCAPE); continue; case S_GRAVE: - comsubst(mp,0); + comsubst(mp,(Shnode_t*)0,0); break; case S_DOL: c = fcget(); @@ -336,30 +346,30 @@ case S_DIG: case S_LBRA: { Fcin_t save2; - int offset = staktell(); + int offset = stktell(stkp); int offset2; - stakputc(c); + sfputc(stkp,c); if(n==S_LBRA) - sh_lexskip(RBRACE,1,ST_BRACE); + sh_lexskip(lp,RBRACE,1,ST_BRACE); else if(n==S_ALP) { while(fcgetc(c),isaname(c)) - stakputc(c); + sfputc(stkp,c); fcseek(-1); } - stakputc(0); - offset2 = staktell(); + sfputc(stkp,0); + offset2 = stktell(stkp); fcsave(&save2); - fcsopen(stakptr(offset)); + fcsopen(stkptr(stkp,offset)); varsub(mp); - if(c=staktell()-offset2) - sfwrite(outfile,(char*)stakptr(offset2),c); + if(c=stktell(stkp)-offset2) + sfwrite(outfile,(char*)stkptr(stkp,offset2),c); fcrestore(&save2); - stakseek(offset); + stkseek(stkp,offset); break; } case S_PAR: - comsubst(mp,1); + comsubst(mp,(Shnode_t*)0,1); break; case S_EOF: if((c=fcfill()) > 0) @@ -379,7 +389,7 @@ /* * expand argument but do not trim pattern characters */ -char *sh_macpat(register struct argnod *arg, int flags) +char *sh_macpat(Shell_t *shp,register struct argnod *arg, int flags) { register char *sp = arg->argval; if((arg->argflag&ARG_RAW)) @@ -388,14 +398,14 @@ arg->argchn.ap=0; if(!(sp=arg->argchn.cp)) { - sh_macexpand(arg,NIL(struct argnod**),flags); + sh_macexpand(shp,arg,NIL(struct argnod**),flags|ARG_ARRAYOK); sp = arg->argchn.cp; if(!(flags&ARG_OPTIMIZE) || !(arg->argflag&ARG_MAKE)) arg->argchn.cp = 0; arg->argflag &= ~ARG_MAKE; } else - sh.optcount++; + shp->optcount++; return(sp); } @@ -407,6 +417,7 @@ register int c,n; register const char *state = sh_lexstates[ST_MACRO]; register char *cp,*first; + Lex_t *lp = (Lex_t*)mp->shp->lex_context; int tilde = -1; int oldquote = mp->quote; int ansi_c = 0; @@ -414,11 +425,12 @@ int ere = 0; int brace = 0; Sfio_t *sp = mp->sp; + Stk_t *stkp = mp->shp->stk; mp->sp = NIL(Sfio_t*); mp->quote = newquote; first = cp = fcseek(0); if(!mp->quote && *cp=='~') - tilde = staktell(); + tilde = stktell(stkp); /* handle // operator specially */ if(mp->pattern==2 && *cp=='/') cp++; @@ -461,7 +473,7 @@ /* process ANSI-C escape character */ char *addr= --cp; if(c) - stakwrite(first,c); + sfwrite(stkp,first,c); c = chresc(cp,&addr); cp = addr; first = fcseek(cp-first); @@ -473,13 +485,13 @@ n = wctomb((char*)mb, c); for(i=0;i<n;i++) - stakputc(mb[i]); + sfputc(stkp,mb[i]); } else #endif /* SHOPT_MULTIBYTE */ - stakputc(c); + sfputc(stkp,c); if(c==ESCAPE && mp->pattern) - stakputc(ESCAPE); + sfputc(stkp,ESCAPE); break; } else if(sh_isoption(SH_BRACEEXPAND) && mp->pattern==4 && (*cp==',' || *cp==LBRACE || *cp==RBRACE || *cp=='.')) @@ -491,9 +503,9 @@ cp = fcseek(c+2); if(c= cp[-1]) { - stakputc(c); + sfputc(stkp,c); if(c==ESCAPE) - stakputc(ESCAPE); + sfputc(stkp,ESCAPE); } else cp--; @@ -514,12 +526,18 @@ (n==S_PAT||n==S_ENDCH||n==S_SLASH||n==S_BRACT||*cp=='-')))) { cp += (n!=S_EOF); + if(ere && n==S_ESC && *cp =='\\' && cp[1]=='$') + { + /* convert \\\$ into \$' */ + sfwrite(stkp,first,c+1); + cp = first = fcseek(c+3); + } break; } - if(mp->lit || (mp->quote && !isqescchar(n) && n!=S_ENDCH)) + if(!(ere && *cp=='$') && (mp->lit || (mp->quote && !isqescchar(n) && n!=S_ENDCH))) { /* add \ for file expansion */ - stakwrite(first,c+1); + sfwrite(stkp,first,c+1); first = fcseek(c); break; } @@ -530,7 +548,7 @@ { /* eliminate \ */ if(c) - stakwrite(first,c); + sfwrite(stkp,first,c); /* check new-line joining */ first = fcseek(c+1); } @@ -544,18 +562,18 @@ if(mp->split && !mp->quote && endch) mac_copy(mp,first,c); else - stakwrite(first,c); + sfwrite(stkp,first,c); } first = fcseek(c+1); c = mp->pattern; if(n==S_GRAVE) - comsubst(mp,0); + comsubst(mp,(Shnode_t*)0,0); else if((n= *cp)==0 || !varsub(mp)) { if(n=='\'' && !mp->quote) ansi_c = 1; else if(mp->quote || n!='"') - stakputc('$'); + sfputc(stkp,'$'); } cp = first = fcseek(0); if(*cp) @@ -572,12 +590,12 @@ if(mp->split && !mp->quote && !mp->lit && endch) mac_copy(mp,first,c); else - stakwrite(first,c); + sfwrite(stkp,first,c); } c += (n!=S_EOF); first = fcseek(c); if(tilde>=0) - tilde_expand2(tilde); + tilde_expand2(mp->shp,tilde); goto done; case S_QUOTE: if(mp->lit || mp->arith) @@ -596,7 +614,7 @@ if(mp->split && endch && !mp->quote && !mp->lit) mac_copy(mp,first,c); else - stakwrite(first,c); + sfwrite(stkp,first,c); } first = fcseek(c+1); if(n==S_LIT) @@ -613,26 +631,28 @@ mp->quoted++; break; case S_BRACT: - if(mp->arith || ((mp->assign==1 || endch==RBRACT) && + if(mp->arith || (((mp->assign&1) || endch==RBRACT) && !(mp->quote || mp->lit))) { int offset=0,oldpat = mp->pattern; - int oldarith = mp->arith; - stakwrite(first,++c); - if(mp->assign==1 && first[c-2]=='.') - offset = staktell(); + int oldarith = mp->arith, oldsub=mp->subcopy; + sfwrite(stkp,first,++c); + if((mp->assign&1) && first[c-2]=='.') + offset = stktell(stkp); first = fcseek(c); mp->pattern = 4; mp->arith = 0; + mp->subcopy = 0; copyto(mp,RBRACT,0); + mp->subcopy = oldsub; mp->arith = oldarith; mp->pattern = oldpat; - stakputc(RBRACT); + sfputc(stkp,RBRACT); if(offset) { - cp = stakptr(staktell()); - if(sh_checkid(stakptr(offset),cp)!=cp) - stakseek(staktell()-2); + cp = stkptr(stkp,stktell(stkp)); + if(sh_checkid(stkptr(stkp,offset),cp)!=cp) + stkseek(stkp,stktell(stkp)-2); } cp = first = fcseek(0); break; @@ -655,6 +675,17 @@ --paren; } goto pattern; + case S_COM: + if(mp->pattern==4 && (mp->quote || mp->lit)) + { + if(c) + { + sfwrite(stkp,first,c); + first = fcseek(c); + } + sfputc(stkp,ESCAPE); + } + break; case S_BRACE: if(!(mp->quote || mp->lit)) { @@ -674,15 +705,15 @@ if(mp->pattern==3) break; if(c) - stakwrite(first,c); + sfwrite(stkp,first,c); first = fcseek(c); - stakputc(ESCAPE); + sfputc(stkp,ESCAPE); break; case S_EQ: if(mp->assign==1) { if(*cp=='~' && !endch && !mp->quote && !mp->lit) - tilde = staktell()+(c+1); + tilde = stktell(stkp)+(c+1); mp->assign = 2; } break; @@ -691,14 +722,14 @@ if(tilde >=0) { if(c) - stakwrite(first,c); + sfwrite(stkp,first,c); first = fcseek(c); - tilde_expand2(tilde); + tilde_expand2(mp->shp,tilde); tilde = -1; c=0; } if(n==S_COLON && mp->assign==2 && *cp=='~' && endch==0 && !mp->quote &&!mp->lit) - tilde = staktell()+(c+1); + tilde = stktell(stkp)+(c+1); else if(n==S_SLASH && mp->pattern==2) #if 0 goto pattern; @@ -706,17 +737,26 @@ { if(mp->quote || mp->lit) goto pattern; - stakwrite(first,c+1); + sfwrite(stkp,first,c+1); first = fcseek(c+1); - c = staktell(); - sh_lexskip(RBRACE,0,ST_NESTED); - stakseek(c); + c = stktell(stkp); + sh_lexskip(lp,RBRACE,0,ST_NESTED); + stkseek(stkp,c); cp = fcseek(-1); - stakwrite(first,cp-first); + sfwrite(stkp,first,cp-first); first=cp; } #endif break; + case S_DOT: + if(*cp=='.' && mp->subcopy==1) + { + sfwrite(stkp,first,c); + sfputc(stkp,0); + mp->dotdot = stktell(stkp); + cp = first = fcseek(c+2); + } + break; } } done: @@ -729,26 +769,23 @@ */ static void mac_substitute(Mac_t *mp, register char *cp,char *str,register int subexp[],int subsize) { - register int c,n; -#if 0 - register char *first=cp; -#else + register int c,n; register char *first=fcseek(0); - char *ptr; - Mac_t savemac; - n = staktell(); + char *ptr; + Mac_t savemac; + Stk_t *stkp = mp->shp->stk; + n = stktell(stkp); savemac = *mp; mp->pattern = 3; mp->split = 0; fcsopen(cp); copyto(mp,0,0); - stakputc(0); - ptr = cp = strdup(stakptr(n)); - stakseek(n); + sfputc(stkp,0); + ptr = cp = strdup(stkptr(stkp,n)); + stkseek(stkp,n); *mp = savemac; fcsopen(first); first = cp; -#endif while(1) { while((c= *cp++) && c!=ESCAPE); @@ -776,9 +813,7 @@ } if(n=cp-first-1) mac_copy(mp,first,n); -#if 1 free(ptr); -#endif } #if SHOPT_FILESCAN @@ -844,14 +879,14 @@ /* * get the prefix after name reference resolution */ -static char *prefix(char *id) +static char *prefix(Shell_t *shp, char *id) { Namval_t *np; register char *cp = strchr(id,'.'); if(cp) { *cp = 0; - np = nv_search(id, sh.var_tree,0); + np = nv_search(id, shp->var_tree,0); *cp = '.'; if(isastchar(cp[1])) cp[1] = 0; @@ -859,7 +894,7 @@ { int n; char *sp; - sh.argaddr = 0; + shp->argaddr = 0; while(nv_isref(np)) np = nv_refnode(np); id = (char*)malloc(strlen(cp)+1+(n=strlen(sp=nv_name(np)))+1); @@ -878,22 +913,58 @@ { int split = mp->split; int xpattern = mp->pattern; - int loc = staktell(); + int loc = stktell(mp->shp->stk); int xarith = mp->arith; + int arrayok = mp->arrayok; mp->split = 0; mp->arith = 0; mp->pattern = flag?4:0; + mp->arrayok=1; + mp->subcopy++; + mp->dotdot = 0; copyto(mp,RBRACT,0); + mp->subcopy = 0; mp->pattern = xpattern; mp->split = split; mp->arith = xarith; + mp->arrayok = arrayok; return(loc); } +/* + * if name is a discipline function, run the function and put the results + * on the stack so that ${x.foo} behaves like ${ x.foo;} + */ +int sh_macfun(Shell_t *shp, const char *name, int offset) +{ + Namval_t *np, *nq; + np = nv_bfsearch(name,shp->fun_tree,&nq,(char**)0); + if(np) + { + /* treat ${x.foo} as ${x.foo;} */ + Shnode_t *tp; + char buff[sizeof(struct dolnod)+sizeof(char*)]; + struct comnod node; + struct dolnod *dp = (struct dolnod*)buff; + memset(&node,0,sizeof(node)); + memset(&buff,0,sizeof(buff)); + tp = (Shnode_t*)&node; + tp->com.comarg = (struct argnod*)dp; + tp->com.comline = shp->inlineno; + dp->dolnum = 2; + dp->dolval[0] = strdup(name); + stkseek(shp->stk,offset); + comsubst((Mac_t*)shp->mac_context,tp,2); + free(dp->dolval[0]); + return(1); + } + return(0); +} + static int namecount(Mac_t *mp,const char *prefix) { int count = 0; - mp->nvwalk = nv_diropen(prefix); + mp->nvwalk = nv_diropen((Namval_t*)0,prefix); while(nv_dirnext(mp->nvwalk)) count++; nv_dirclose(mp->nvwalk); @@ -905,7 +976,7 @@ char *cp; if(len==0) { - mp->nvwalk = nv_diropen(prefix); + mp->nvwalk = nv_diropen((Namval_t*)0,prefix); return((char*)mp->nvwalk); } if(!(cp=nv_dirnext(mp->nvwalk))) @@ -924,10 +995,12 @@ register char *v,*argp=0; register Namval_t *np = NIL(Namval_t*); register int dolg=0, mode=0; + Lex_t *lp = (Lex_t*)mp->shp->lex_context; Namarr_t *ap=0; int dolmax=0, vsize= -1, offset= -1, nulflg, replen=0, bysub=0; - char idbuff[3], *id = idbuff, *pattern=0, *repstr; - int oldpat=mp->pattern,idnum=0,flag=0,d; + char idbuff[3], *id = idbuff, *pattern=0, *repstr, *arrmax=0; + int addsub=0,oldpat=mp->pattern,idnum=0,flag=0,d; + Stk_t *stkp = mp->shp->stk; retry1: mp->zeros = 0; idbuff[0] = 0; @@ -971,19 +1044,19 @@ /* FALL THRU */ case S_SPC2: *id = c; - v = special(c); + v = special(mp->shp,c); if(isastchar(c)) { mode = c; #if SHOPT_FILESCAN - if(sh.cur_line) + if(mp->shp->cur_line) { v = getdolarg(&sh,1,(int*)0); dolmax = MAX_ARGN; } else #endif /* SHOPT_FILESCAN */ - dolmax = sh.st.dolc+1; + dolmax = mp->shp->st.dolc+1; dolg = (v!=0); } break; @@ -995,11 +1068,11 @@ case S_PAR: if(type) goto nosub; - comsubst(mp,1); + comsubst(mp,(Shnode_t*)0,1); return(1); case S_DIG: c -= '0'; - sh.argaddr = 0; + mp->shp->argaddr = 0; if(type) { register int d; @@ -1009,18 +1082,18 @@ } idnum = c; if(c==0) - v = special(c); + v = special(mp->shp,c); #if SHOPT_FILESCAN - else if(sh.cur_line) + else if(mp->shp->cur_line) { - sh.used_pos = 1; + mp->shp->used_pos = 1; v = getdolarg(&sh,c,&vsize); } #endif /* SHOPT_FILESCAN */ - else if(c <= sh.st.dolc) + else if(c <= mp->shp->st.dolc) { - sh.used_pos = 1; - v = sh.st.dolv[c]; + mp->shp->used_pos = 1; + v = mp->shp->st.dolv[c]; } else v = 0; @@ -1028,16 +1101,16 @@ case S_ALP: if(c=='.' && type==0) goto nosub; - offset = staktell(); + offset = stktell(stkp); do { np = 0; do - stakputc(c); + sfputc(stkp,c); while(((c=fcget()),(c>0x7f||isaname(c)))||type && c=='.'); - while(c==LBRACT && type) + while(c==LBRACT && (type||mp->arrayok)) { - sh.argaddr=0; + mp->shp->argaddr=0; if((c=fcget(),isastchar(c)) && fcpeek(0)==RBRACT) { if(type==M_VNAME) @@ -1047,9 +1120,9 @@ c = fcget(); if(c=='.' || c==LBRACT) { - stakputc(LBRACT); - stakputc(mode); - stakputc(RBRACT); + sfputc(stkp,LBRACT); + sfputc(stkp,mode); + sfputc(stkp,RBRACT); } else flag = NV_ARRAY; @@ -1058,23 +1131,43 @@ else { fcseek(-1); - if(type==M_VNAME) + c = stktell(stkp); + sfputc(stkp,LBRACT); + v = stkptr(stkp,subcopy(mp,1)); + if(type && mp->dotdot) + { + mode = '@'; + v[-1] = 0; + if(type==M_VNAME) + type = M_SUBNAME; + else if(type==M_SIZE) + goto nosub; + } + else + sfputc(stkp,RBRACT); + c = fcget(); + if(c==0 && type==M_VNAME) type = M_SUBNAME; - stakputc(LBRACT); - v = stakptr(subcopy(mp,1)); - stakputc(RBRACT); - c = fcget(); } } } while(type && c=='.'); if(c==RBRACE && type && fcpeek(-2)=='.') { - stakseek(staktell()-1); - type = M_TREE; + /* ${x.} or ${x..} */ + if(fcpeek(-3) == '.') + { + stkseek(stkp,stktell(stkp)-2); + nv_local = 1; + } + else + { + stkseek(stkp,stktell(stkp)-1); + type = M_TREE; + } } - stakputc(0); - id=stakptr(offset); + sfputc(stkp,0); + id=stkptr(stkp,offset); if(isastchar(c) && type) { if(type==M_VNAME || type==M_SIZE) @@ -1094,20 +1187,48 @@ if(c=='=' || c=='?' || (c==':' && ((d=fcpeek(0))=='=' || d=='?'))) flag &= ~NV_NOADD; #if SHOPT_FILESCAN - if(sh.cur_line && *id=='R' && strcmp(id,"REPLY")==0) + if(mp->shp->cur_line && *id=='R' && strcmp(id,"REPLY")==0) { - sh.argaddr=0; + mp->shp->argaddr=0; np = REPLYNOD; } else #endif /* SHOPT_FILESCAN */ - if(sh.argaddr) + if(mp->shp->argaddr) flag &= ~NV_NOADD; - np = nv_open(id,sh.var_tree,flag|NV_NOFAIL); + np = nv_open(id,mp->shp->var_tree,flag|NV_NOFAIL); + if((!np || nv_isnull(np)) && type==M_BRACE && c==RBRACE && !(flag&NV_ARRAY)) + { + if(sh_macfun(mp->shp,id,offset)) + { + fcget(); + return(1); + } + } ap = np?nv_arrayptr(np):0; if(type) { - if(ap && isastchar(mode) && !(ap->nelem&ARRAY_SCAN)) + if(mp->dotdot) + { + if(ap) + { + nv_putsub(np,v,ARRAY_SCAN); + v = stkptr(stkp,mp->dotdot); + dolmax =1; + if(array_assoc(ap)) + arrmax = strdup(v); + else + dolmax = (int)sh_arith(v); + if(type==M_SUBNAME) + bysub = 1; + } + else + { + if((int)sh_arith(v)) + np = 0; + } + } + else if(ap && (isastchar(mode)||type==M_TREE) && !(ap->nelem&ARRAY_SCAN) && type!=M_SIZE) nv_putsub(np,NIL(char*),ARRAY_SCAN); if(!isbracechar(c)) goto nosub; @@ -1116,37 +1237,41 @@ } else fcseek(-1); - if((type==M_VNAME||type==M_SUBNAME) && sh.argaddr && strcmp(nv_name(np),id)) - sh.argaddr = 0; + if((type==M_VNAME||type==M_SUBNAME) && mp->shp->argaddr && strcmp(nv_name(np),id)) + mp->shp->argaddr = 0; c = (type>M_BRACE && isastchar(mode)); - if(np && (!c || !ap)) + if(np && (type==M_TREE || !c || !ap)) { - if(type==M_VNAME) + if(type==M_VNAME || (type==M_SUBNAME && ap)) { type = M_BRACE; v = nv_name(np); + if(ap && !mp->dotdot && !(ap->nelem&ARRAY_UNDEF)) + addsub = 1; } #ifdef SHOPT_TYPEDEF else if(type==M_TYPE) { -#if 0 Namval_t *nq = nv_type(np); -#else - Namval_t *nq = 0; -#endif type = M_BRACE; if(nq) - v = nv_name(nq); + { + char *cp = nv_name(nq); + if(v=strrchr(cp,'.')) + v++; + else + v = cp; + } else { - nv_attribute(np,sh.strbuf,"typeset",1); - v = sfstruse(sh.strbuf); + nv_attribute(np,mp->shp->strbuf,"typeset",1); + v = sfstruse(mp->shp->strbuf); } } #endif /* SHOPT_TYPEDEF */ #if SHOPT_FILESCAN - else if(sh.cur_line && np==REPLYNOD) - v = sh.cur_line; + else if(mp->shp->cur_line && np==REPLYNOD) + v = mp->shp->cur_line; #endif /* SHOPT_FILESCAN */ else if(type==M_TREE) v = nv_getvtree(np,(Namfun_t*)0); @@ -1154,17 +1279,26 @@ { v = nv_getval(np); /* special case --- ignore leading zeros */ - if( (mp->arith||mp->let) && (np->nvfun || nv_isattr(np,(NV_LJUST|NV_RJUST|NV_ZFILL))) && (offset==0 || !isalnum(*((unsigned char*)stakptr(offset-1))))) + if( (mp->arith||mp->let) && (np->nvfun || nv_isattr(np,(NV_LJUST|NV_RJUST|NV_ZFILL))) && (offset==0 || !isalnum(*((unsigned char*)stkptr(stkp,offset-1))))) mp->zeros = 1; } } else + { v = 0; - stakseek(offset); + if(type==M_VNAME) + { + v = id; + type = M_BRACE; + } + else if(type==M_TYPE) + type = M_BRACE; + } + stkseek(stkp,offset); if(ap) { #if SHOPT_OPTIMIZE - if(sh.argaddr) + if(mp->shp->argaddr) nv_optimize(np); #endif if(isastchar(mode) && array_elem(ap)> !c) @@ -1185,8 +1319,8 @@ mac_error(np); if(type==M_NAMESCAN || type==M_NAMECOUNT) { - id = prefix(id); - stakseek(offset); + id = prefix(mp->shp,id); + stkseek(stkp,offset); if(type==M_NAMECOUNT) { c = namecount(mp,id); @@ -1222,14 +1356,14 @@ else if(dolg>0) { #if SHOPT_FILESCAN - if(sh.cur_line) + if(mp->shp->cur_line) { getdolarg(&sh,MAX_ARGN,(int*)0); - c = sh.offsets[0]; + c = mp->shp->offsets[0]; } else #endif /* SHOPT_FILESCAN */ - c = sh.st.dolc; + c = mp->shp->st.dolc; } else if(dolg<0) c = array_elem(ap); @@ -1264,7 +1398,7 @@ if(c!=RBRACE) { int newops = (c=='#' || c == '%' || c=='/'); - offset = staktell(); + offset = stktell(stkp); if(c=='/' ||c==':' || ((!v || (nulflg && *v==0)) ^ (c=='+'||c=='#'||c=='%'))) { int newquote = mp->quote; @@ -1300,15 +1434,15 @@ mp->arith = arith; mp->zeros = zeros; /* add null byte */ - stakputc(0); - stakseek(staktell()-1); + sfputc(stkp,0); + stkseek(stkp,stktell(stkp)-1); } else { - sh_lexskip(RBRACE,0,(!newops&&mp->quote)?ST_QUOTE:ST_NESTED); - stakseek(offset); + sh_lexskip(lp,RBRACE,0,(!newops&&mp->quote)?ST_QUOTE:ST_NESTED); + stkseek(stkp,offset); } - argp=stakptr(offset); + argp=stkptr(stkp,offset); } } else @@ -1327,9 +1461,9 @@ if(type<0 && (type+= dolmax)<0) type = 0; if(type==0) - v = special(dolg=0); + v = special(mp->shp,dolg=0); #if SHOPT_FILESCAN - else if(sh.cur_line) + else if(mp->shp->cur_line) { v = getdolarg(&sh,dolg=type,&vsize); if(!v) @@ -1337,7 +1471,7 @@ } #endif /* SHOPT_FILESCAN */ else if(type < dolmax) - v = sh.st.dolv[dolg=type]; + v = mp->shp->st.dolv[dolg=type]; else v = 0; } @@ -1426,7 +1560,7 @@ } if(*ptr) mac_error(np); - stakseek(offset); + stkseek(stkp,offset); argp = 0; } /* check for substring operations */ @@ -1454,7 +1588,7 @@ if((type=='/' || c=='/') && (repstr = mac_getstring(pattern))) replen = strlen(repstr); if(v || c=='/' && offset>=0) - stakseek(offset); + stkseek(stkp,offset); } /* check for quoted @ */ if(mode=='@' && mp->quote && !v && c!='-') @@ -1463,7 +1597,7 @@ if(v && (!nulflg || *v ) && c!='+') { register int d = (mode=='@'?' ':mp->ifs); - int match[2*(MATCH_MAX+1)], nmatch, vsize_last; + int match[2*(MATCH_MAX+1)], nmatch, nmatch_prev, vsize_last; char *vlast; while(1) { @@ -1471,12 +1605,14 @@ v= ""; if(c=='/' || c=='#' || c== '%') { - flag = (type || c=='/')?STR_GROUP|STR_MAXIMAL:STR_GROUP; + flag = (type || c=='/')?(STR_GROUP|STR_MAXIMAL):STR_GROUP; if(c!='/') flag |= STR_LEFT; + nmatch = 0; while(1) { vsize = strlen(v); + nmatch_prev = nmatch; if(c=='%') nmatch=substring(v,pattern,match,flag&STR_MAXIMAL); else @@ -1493,7 +1629,7 @@ vsize = 0; if(vsize) mac_copy(mp,v,vsize); - if(nmatch && replen>0) + if(nmatch && replen>0 && (match[1] || !nmatch_prev)) mac_substitute(mp,repstr,v,match,nmatch); if(nmatch==0) v += vsize; @@ -1503,7 +1639,11 @@ { /* avoid infinite loop */ if(nmatch && match[1]==0) + { + nmatch = 0; + mac_copy(mp,v,1); v++; + } continue; } vsize = -1; @@ -1514,14 +1654,39 @@ } if(vsize) mac_copy(mp,v,vsize>0?vsize:strlen(v)); + if(addsub) + { + sfprintf(mp->shp->strbuf,"[%s]",nv_getsub(np)); + v = sfstruse(mp->shp->strbuf); + mac_copy(mp, v, strlen(v)); + } if(dolg==0 && dolmax==0) break; - if(dolg>=0) + if(mp->dotdot) { + if(nv_nextsub(np) == 0) + break; + if(bysub) + v = nv_getsub(np); + else + v = nv_getval(np); + if(array_assoc(ap)) + { + if(strcmp(bysub?v:nv_getsub(np),arrmax)>0) + break; + } + else + { + if(nv_aindex(np) > dolmax) + break; + } + } + else if(dolg>=0) + { if(++dolg >= dolmax) break; #if SHOPT_FILESCAN - if(sh.cur_line) + if(mp->shp->cur_line) { if(dolmax==MAX_ARGN && isastchar(mode)) break; @@ -1533,7 +1698,7 @@ } else #endif /* SHOPT_FILESCAN */ - v = sh.st.dolv[dolg]; + v = mp->shp->st.dolv[dolg]; } else if(!np) { @@ -1547,6 +1712,8 @@ nv_putsub(np,NIL(char*),ARRAY_UNDEF); break; } + if(ap) + ap->nelem |= ARRAY_SCAN; if(nv_nextsub(np) == 0) break; if(bysub) @@ -1566,9 +1733,11 @@ if(mp->sp) sfputc(mp->sp,d); else - stakputc(d); + sfputc(stkp,d); } } + if(arrmax) + free((void*)arrmax); if(pattern) free((void*)pattern); } @@ -1584,7 +1753,7 @@ id = ltos(idnum); if(*argp) { - stakputc(0); + sfputc(stkp,0); errormsg(SH_DICT,ERROR_exit(1),"%s: %s",id,argp); } else if(v) @@ -1596,12 +1765,12 @@ { if(np) { - if(sh.subshell) + if(mp->shp->subshell) np = sh_assignok(np,1); nv_putval(np,argp,0); v = nv_getval(np); nulflg = 0; - stakseek(offset); + stkseek(stkp,offset); goto retry2; } else @@ -1614,9 +1783,8 @@ { if(nv_isarray(np)) { - sfprintf(sh.strbuf,"%s[%s]\0",nv_name(np),nv_getsub(np)); - id = nv_getsub(np); - id = sfstruse(sh.strbuf); + sfprintf(mp->shp->strbuf,"%s[%s]\0",nv_name(np),nv_getsub(np)); + id = sfstruse(mp->shp->strbuf); } else id = nv_name(np); @@ -1628,6 +1796,12 @@ nv_close(np); return(1); nosub: + if(type==M_BRACE && sh_lexstates[ST_NORM][c]==S_BREAK) + { + fcseek(-1); + comsubst(mp,(Shnode_t*)0,2); + return(1); + } if(type) mac_error(np); fcseek(-1); @@ -1639,47 +1813,50 @@ * This routine handles command substitution * <type> is 0 for older `...` version */ -static void comsubst(Mac_t *mp,int type) +static void comsubst(Mac_t *mp,register Shnode_t* t, int type) { Sfdouble_t num; register int c; register char *str; Sfio_t *sp; + Stk_t *stkp = mp->shp->stk; Fcin_t save; - struct slnod *saveslp = sh.st.staklist; + struct slnod *saveslp = mp->shp->st.staklist; struct _mac_ savemac; - int savtop = staktell(); - char lastc, *savptr = stakfreeze(0); + int savtop = stktell(stkp); + char lastc, *savptr = stkfreeze(stkp,0); int was_history = sh_isstate(SH_HISTORY); int was_verbose = sh_isstate(SH_VERBOSE); int newlines,bufsize; - register Shnode_t *t; Namval_t *np; - sh.argaddr = 0; + mp->shp->argaddr = 0; savemac = *mp; - sh.st.staklist=0; + mp->shp->st.staklist=0; if(type) { sp = 0; fcseek(-1); - t = sh_dolparen(); + if(!t) + t = sh_dolparen((Lex_t*)mp->shp->lex_context); if(t && t->tre.tretyp==TARITH) { - str = t->ar.arexpr->argval; fcsave(&save); - if(!(t->ar.arexpr->argflag&ARG_RAW)) - str = sh_mactrim(str,3); - num = sh_arith(str); + if((t->ar.arexpr->argflag&ARG_RAW)) + num = arith_exec(t->ar.arcomp); + else + num = sh_arith(sh_mactrim(mp->shp,t->ar.arexpr->argval,3)); out_offset: - stakset(savptr,savtop); + stkset(stkp,savptr,savtop); *mp = savemac; - if((Sflong_t)num==num) - sfprintf(sh.strbuf,"%lld",(Sflong_t)num); + if((Sflong_t)num!=num) + sfprintf(mp->shp->strbuf,"%.*Lg",LDBL_DIG,num); + else if(num) + sfprintf(mp->shp->strbuf,"%lld",(Sflong_t)num); else - sfprintf(sh.strbuf,"%.*Lg",LDBL_DIG,num); - str = sfstruse(sh.strbuf); + sfprintf(mp->shp->strbuf,"%Lg",num); + str = sfstruse(mp->shp->strbuf); mac_copy(mp,str,strlen(str)); - sh.st.staklist = saveslp; + mp->shp->st.staklist = saveslp; fcrestore(&save); return; } @@ -1692,30 +1869,31 @@ { fcgetc(c); if(!(isescchar(sh_lexstates[ST_QUOTE][c]) || - (c=='"' && mp->quote)) || (c=='$' && fcpeek(0)=='\'')) - stakputc(ESCAPE); + (c=='"' && mp->quote))) + sfputc(stkp,ESCAPE); } - stakputc(c); + sfputc(stkp,c); } - c = staktell(); - str=stakfreeze(1); + c = stktell(stkp); + str=stkfreeze(stkp,1); /* disable verbose and don't save in history file */ sh_offstate(SH_HISTORY); sh_offstate(SH_VERBOSE); if(mp->sp) sfsync(mp->sp); /* flush before executing command */ sp = sfnew(NIL(Sfio_t*),str,c,-1,SF_STRING|SF_READ); - c = sh.inlineno; - sh.inlineno = error_info.line+sh.st.firstline; + c = mp->shp->inlineno; + mp->shp->inlineno = error_info.line+mp->shp->st.firstline; t = (Shnode_t*)sh_parse(mp->shp, sp,SH_EOF|SH_NL); - sh.inlineno = c; + mp->shp->inlineno = c; + type = 1; } #if KSHELL if(t) { fcsave(&save); sfclose(sp); - if(t->tre.tretyp==0 && !t->com.comarg) + if(t->tre.tretyp==0 && !t->com.comarg && !t->com.comset) { /* special case $(<file) and $(<#file) */ register int fd; @@ -1726,13 +1904,13 @@ if((ip=t->tre.treio) && ((ip->iofile&IOLSEEK) || !(ip->iofile&IOUFD)) && (r=sigsetjmp(buff.buff,0))==0) - fd = sh_redirect(ip,3); + fd = sh_redirect(mp->shp,ip,3); else fd = sh_chkopen(e_devnull); sh_popcontext(&buff); if(r==0 && ip && (ip->iofile&IOLSEEK)) { - if(sp=sh.sftable[fd]) + if(sp=mp->shp->sftable[fd]) num = sftell(sp); else num = lseek(fd, (off_t)0, SEEK_CUR); @@ -1741,13 +1919,13 @@ sp = sfnew(NIL(Sfio_t*),(char*)malloc(IOBSIZE+1),IOBSIZE,fd,SF_READ|SF_MALLOC); } else - sp = sh_subshell(t,sh_isstate(SH_ERREXIT),1); + sp = sh_subshell(t,sh_isstate(SH_ERREXIT),type); fcrestore(&save); } else sp = sfopen(NIL(Sfio_t*),"","sr"); - sh_freeup(); - sh.st.staklist = saveslp; + sh_freeup(mp->shp); + mp->shp->st.staklist = saveslp; if(was_history) sh_onstate(SH_HISTORY); if(was_verbose) @@ -1756,10 +1934,10 @@ sp = sfpopen(NIL(Sfio_t*),str,"r"); #endif *mp = savemac; - np = nv_scoped(IFSNOD); - nv_putval(np,mp->ifsp,0); + np = sh_scoped(mp->shp,IFSNOD); + nv_putval(np,mp->ifsp,NV_RDONLY); mp->ifsp = nv_getval(np); - stakset(savptr,savtop); + stkset(stkp,savptr,savtop); newlines = 0; lastc = 0; sfsetbuf(sp,(void*)sp,0); @@ -1798,10 +1976,10 @@ { if(mp->sp) sfnputc(mp->sp,'\n',newlines); - else if(!mp->quote && mp->split && sh.ifstable['\n']) + else if(!mp->quote && mp->split && mp->shp->ifstable['\n']) endfield(mp,0); else while(newlines--) - stakputc('\n'); + sfputc(stkp,'\n'); newlines = 0; } else if(lastc) @@ -1809,8 +1987,10 @@ mac_copy(mp,&lastc,1); lastc = 0; } + if(c <= 0) + continue; /* delay appending trailing new-lines */ - while(str[--c]=='\n') + while(c-->=0 && str[c]=='\n') newlines++; if(++c < bufsize) str[c] = 0; @@ -1822,14 +2002,14 @@ } mac_copy(mp,str,c); } - if(--newlines>0 && sh.ifstable['\n']==S_DELIM) + if(--newlines>0 && mp->shp->ifstable['\n']==S_DELIM) { if(mp->sp) sfnputc(mp->sp,'\n',newlines); - else if(!mp->quote && mp->split && sh.ifstable['\n']) + else if(!mp->quote && mp->split && mp->shp->ifstable['\n']) endfield(mp,0); else while(newlines--) - stakputc('\n'); + sfputc(stkp,'\n'); } if(lastc) mac_copy(mp,&lastc,1); @@ -1844,7 +2024,8 @@ { register char *state; register const char *cp=str; - register int c,n,nopat; + register int c,n,nopat,len; + Stk_t *stkp=mp->shp->stk; nopat = (mp->quote||mp->assign==1||mp->arith); if(mp->zeros) { @@ -1862,6 +2043,14 @@ /* insert \ before file expansion characters */ while(size-->0) { +#if SHOPT_MULTIBYTE + if(mbwide() && (len=mbsize(cp))>1) + { + cp += len; + size -= (len-1); + continue; + } +#endif c = state[n= *(unsigned char*)cp++]; if(nopat&&(c==S_PAT||c==S_ESC||c==S_BRACT||c==S_ENDCH) && mp->pattern!=3) c=1; @@ -1879,18 +2068,18 @@ if(c) { if(c = (cp-1) - str) - stakwrite(str,c); - stakputc(ESCAPE); + sfwrite(stkp,str,c); + sfputc(stkp,ESCAPE); str = cp-1; } } if(c = cp-str) - stakwrite(str,c); + sfwrite(stkp,str,c); } else if(!mp->quote && mp->split && (mp->ifs||mp->pattern)) { /* split words at ifs characters */ - state = sh.ifstable; + state = mp->shp->ifstable; if(mp->pattern) { char *sp = "&|()"; @@ -1910,11 +2099,21 @@ } while(size-->0) { - if((n=state[c= *(unsigned char*)cp++])==S_ESC || n==S_EPAT) + n=state[c= *(unsigned char*)cp++]; +#if SHOPT_MULTIBYTE + if(mbwide() && n!=S_MBYTE && (len=mbsize(cp-1))>1) { + sfwrite(stkp,cp-1, len); + cp += --len; + size -= len; + continue; + } +#endif + if(n==S_ESC || n==S_EPAT) + { /* don't allow extended patterns in this case */ mp->patfound = mp->pattern; - stakputc(ESCAPE); + sfputc(stkp,ESCAPE); } else if(n==S_PAT) mp->patfound = mp->pattern; @@ -1963,7 +2162,7 @@ continue; } - stakputc(c); + sfputc(stkp,c); } if(mp->pattern) { @@ -1979,12 +2178,12 @@ if(state[c]==S_PAT) state[c] = 0; } - if(sh.ifstable[ESCAPE]==S_ESC) - sh.ifstable[ESCAPE] = 0; + if(mp->shp->ifstable[ESCAPE]==S_ESC) + mp->shp->ifstable[ESCAPE] = 0; } } else - stakwrite(str,size); + sfwrite(stkp,str,size); } /* @@ -1994,16 +2193,17 @@ */ static void endfield(register Mac_t *mp,int split) { - register struct argnod *argp; - register int count=0; - if(staktell() > ARGVAL || split) + register struct argnod *argp; + register int count=0; + Stk_t *stkp = mp->shp->stk; + if(stktell(stkp) > ARGVAL || split) { - argp = (struct argnod*)stakfreeze(1); + argp = (struct argnod*)stkfreeze(stkp,1); argp->argnxt.cp = 0; argp->argflag = 0; if(mp->patfound) { - sh.argaddr = 0; + mp->shp->argaddr = 0; #if SHOPT_BRACEPAT count = path_generate(argp,mp->arghead); #else @@ -2028,7 +2228,7 @@ if(mp->assign || sh_isoption(SH_NOGLOB)) argp->argflag |= ARG_RAW|ARG_EXP; } - stakseek(ARGVAL); + stkseek(stkp,ARGVAL); } mp->quoted = mp->quote; } @@ -2129,9 +2329,9 @@ */ static int sh_btilde(int argc, char *argv[], void *context) { - char *cp = sh_tilde(argv[1]); + Shell_t *shp = ((Shbltin_t*)context)->shp; + char *cp = sh_tilde(shp,argv[1]); NOT_USED(argc); - NOT_USED(context); if(!cp) cp = argv[1]; sfputr(sfstdout, cp, '\n'); @@ -2141,14 +2341,14 @@ /* * <offset> is byte offset for beginning of tilde string */ -static void tilde_expand2(register int offset) +static void tilde_expand2(Shell_t *shp, register int offset) { - char shtilde[10], *av[3], *ptr=stakfreeze(1); + char shtilde[10], *av[3], *ptr=stkfreeze(shp->stk,1); Sfio_t *iop, *save=sfstdout; Namval_t *np; static int beenhere=0; strcpy(shtilde,".sh.tilde"); - np = nv_open(shtilde,sh.fun_tree, NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOFAIL); + np = nv_open(shtilde,shp->fun_tree, NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOFAIL); if(np && !beenhere) { beenhere = 1; @@ -2165,7 +2365,7 @@ else sh_btilde(2, av, &sh); sfstdout = save; - stakset(ptr, offset); + stkset(shp->stk,ptr, offset); sfseek(iop,(Sfoff_t)0,SEEK_SET); sfset(iop,SF_READ,1); if(ptr = sfreserve(iop, SF_UNBOUND, -1)) @@ -2176,10 +2376,10 @@ if(n==1 && fcpeek(0)=='/' && ptr[n-1]) n--; if(n) - stakwrite(ptr,n); + sfwrite(shp->stk,ptr,n); } else - stakputs(av[1]); + sfputr(shp->stk,av[1],0); sfclose(iop); } @@ -2192,7 +2392,7 @@ * If string doesn't start with ~ or ~... not found then 0 returned. */ -static char *sh_tilde(register const char *string) +static char *sh_tilde(Shell_t *shp,register const char *string) { register char *cp; register int c; @@ -2203,16 +2403,16 @@ return(NIL(char*)); if((c = *string)==0) { - if(!(cp=nv_getval(nv_scoped(HOME)))) + if(!(cp=nv_getval(sh_scoped(shp,HOME)))) cp = getlogin(); return(cp); } if((c=='-' || c=='+') && string[1]==0) { if(c=='+') - cp = nv_getval(nv_scoped(PWDNOD)); + cp = nv_getval(sh_scoped(shp,PWDNOD)); else - cp = nv_getval(nv_scoped(OLDPWDNOD)); + cp = nv_getval(sh_scoped(shp,OLDPWDNOD)); return(cp); } if(logins_tree && (np=nv_search(string,logins_tree,0))) @@ -2229,40 +2429,40 @@ /* * return values for special macros */ -static char *special(register int c) +static char *special(Shell_t *shp,register int c) { register Namval_t *np; if(c!='$') - sh.argaddr = 0; + shp->argaddr = 0; switch(c) { case '@': case '*': - return(sh.st.dolc>0?sh.st.dolv[1]:NIL(char*)); + return(shp->st.dolc>0?shp->st.dolv[1]:NIL(char*)); case '#': #if SHOPT_FILESCAN - if(sh.cur_line) + if(shp->cur_line) { - getdolarg(&sh,MAX_ARGN,(int*)0); - return(ltos(sh.offsets[0])); + getdolarg(shp,MAX_ARGN,(int*)0); + return(ltos(shp->offsets[0])); } #endif /* SHOPT_FILESCAN */ - return(ltos(sh.st.dolc)); + return(ltos(shp->st.dolc)); case '!': - if(sh.bckpid) - return(ltos(sh.bckpid)); + if(shp->bckpid) + return(ltos(shp->bckpid)); break; case '$': if(nv_isnull(SH_DOLLARNOD)) - return(ltos(sh.pid)); + return(ltos(shp->pid)); return(nv_getval(SH_DOLLARNOD)); case '-': - return(sh_argdolminus()); + return(sh_argdolminus(shp->arg_context)); case '?': - return(ltos(sh.savexit)); + return(ltos(shp->savexit)); case 0: - if(sh_isstate(SH_PROFILE) || !error_info.id || ((np=nv_search(error_info.id,sh.bltin_tree,0)) && nv_isattr(np,BLT_SPC))) - return(sh.shname); + if(sh_isstate(SH_PROFILE) || !error_info.id || ((np=nv_search(error_info.id,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC))) + return(shp->shname); else return(error_info.id); } @@ -2281,21 +2481,29 @@ /* * Given pattern/string, replace / with 0 and return pointer to string - * \ characters are stripped from string. + * \ characters are stripped from string. The \ are stripped in the + * replacement string unless followed by a digit or \. */ static char *mac_getstring(char *pattern) { - register char *cp = pattern; - register int c; + register char *cp=pattern, *rep=0, *dp; + register int c; while(c = *cp++) { - if(c==ESCAPE) - cp++; - else if(c=='/') + if(c==ESCAPE && (!rep || (*cp && strchr("&|()[]*?",*cp)))) { + c = *cp++; + } + else if(!rep && c=='/') + { cp[-1] = 0; - return(cp); + rep = dp = cp; + continue; } + if(rep) + *dp++ = c; } - return(NIL(char*)); + if(rep) + *dp = 0; + return(rep); } Index: src/lib/libshell/common/sh/timers.c =================================================================== --- src/lib/libshell/common/sh/timers.c (revision 974) +++ src/lib/libshell/common/sh/timers.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/sh/nvtree.c =================================================================== --- src/lib/libshell/common/sh/nvtree.c (revision 974) +++ src/lib/libshell/common/sh/nvtree.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -36,17 +36,34 @@ Dt_t *root; Namval_t *hp; Namval_t *table; + Namval_t *otable; Namval_t *(*nextnode)(Namval_t*,Dt_t*,Namfun_t*); Namfun_t *fun; struct nvdir *prev; int len; - int offset; char data[1]; }; char *nv_getvtree(Namval_t*, Namfun_t *); static void put_tree(Namval_t*, const char*, int,Namfun_t*); +static int read_tree(Namval_t* np, Sfio_t *iop, int n, Namfun_t *dp) +{ + Sfio_t *sp; + char *cp; + int c; + if(n>=0) + return(-1); + while((c = sfgetc(iop)) && isblank(c)); + sfungetc(iop,c); + sfprintf(sh.strbuf,"%s=%c",nv_name(np),0); + cp = sfstruse(sh.strbuf); + sp = sfopen((Sfio_t*)0,cp,"s"); + sfstack(iop,sp); + c=sh_eval(iop,SH_READEVAL); + return(c); +} + static Namval_t *create_tree(Namval_t *np,const char *name,int flag,Namfun_t *dp) { register Namfun_t *fp=dp; @@ -70,6 +87,8 @@ 0, 0, create_tree + ,0,0,0,0, + read_tree }; static char *nextdot(const char *str) @@ -99,13 +118,13 @@ return(0); } -void *nv_diropen(const char *name) +void *nv_diropen(Namval_t *np,const char *name) { char *next,*last; int c,len=strlen(name); struct nvdir *save, *dp = new_of(struct nvdir,len); - Namval_t *np, fake; - Namfun_t *nfp; + Namval_t *nq,fake; + Namfun_t *nfp=0; if(!dp) return(0); memset((void*)dp, 0, sizeof(*dp)); @@ -115,7 +134,7 @@ name = memcpy(last,name,len); last[len] = 0; dp->len = len; - dp->root = sh.var_tree; + dp->root = sh.last_root?sh.last_root:sh.var_tree; dp->table = sh.last_table; if(*name) { @@ -125,12 +144,24 @@ } else dp->hp = (Namval_t*)dtfirst(dp->root); - while(next= nextdot(last)) + while(1) { - c = *next; - *next = 0; - np = nv_search(last,dp->root,0); - *next = c; + if(next= nextdot(last)) + { + c = *next; + *next = 0; + } + if(!np) + { + if(nfp && nfp->disc && nfp->disc->createf) + np = (*nfp->disc->createf)(nq,last,0,nfp); + else + np = nv_search(last,dp->root,0); + } + if(next) + *next = c; + if(np==dp->hp && !next) + dp->hp = (Namval_t*)dtnext(dp->root,dp->hp); if(np && ((nfp=nextdisc(np)) || nv_istable(np))) { if(!(save = new_of(struct nvdir,0))) @@ -141,15 +172,11 @@ dp->root = nv_dict(np); else dp->root = (Dt_t*)dp; - dp->offset = last-(char*)name; - if(dp->offset<len) - dp->len = len-dp->offset; - else - dp->len = 0; if(nfp) { dp->nextnode = nfp->disc->nextf; dp->table = np; + dp->otable = sh.last_table; dp->fun = nfp; dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp); } @@ -158,7 +185,11 @@ } else break; + if(!next || next[1]==0) + break; last = next+1; + nq = np; + np = 0; } return((void*)dp); } @@ -183,16 +214,26 @@ { while(np=dp->hp) { + char *sptr; dp->hp = nextnode(dp); - if(nv_isnull(np)) + if(nv_isnull(np) && !nv_isarray(np)) continue; last_table = sh.last_table; + if(dp->table && dp->otable && !nv_isattr(dp->table,NV_MINIMAL)) + { + sptr = dp->table->nvenv; + dp->table->nvenv = (char*)dp->otable; + } sh.last_table = dp->table; cp = nv_name(np); + if(dp->table && dp->otable && !nv_isattr(dp->table,NV_MINIMAL)) + dp->table->nvenv = sptr; sh.last_table = last_table; - if(!dp->len || memcmp(cp+dp->offset,dp->data,dp->len)==0) + if(!dp->len || memcmp(cp,dp->data,dp->len)==0) { - if((nfp=nextdisc(np)) || nv_istable(np)) + if((nfp=nextdisc(np)) && (nfp->disc->getval||nfp->disc->getnum) && nv_isvtree(np) && strcmp(cp,dp->data)) + nfp = 0; + if(nfp || nv_istable(np)) { Dt_t *root; if(nv_istable(np)) @@ -216,6 +257,7 @@ if(nfp && np->nvfun) { dp->nextnode = nfp->disc->nextf; + dp->otable = dp->table; dp->table = np; dp->fun = nfp; dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp); @@ -228,9 +270,6 @@ } if(!(save=dp->prev)) break; -#if 0 - sh.last_table = dp->table; -#endif *dp = *save; free((void*)save); } @@ -264,7 +303,14 @@ else if(!prefix) type = "type"; if(type) - sfprintf(out,"%s %s ",type,tp->nvname); + { + char *cp=tp->nvname; + if(cp=strrchr(cp,'.')) + cp++; + else + cp = tp->nvname; + sfprintf(out,"%s %s ",type,cp); + } } /* @@ -274,13 +320,13 @@ { register const Shtable_t *tp; register char *cp; - register unsigned val; - register unsigned mask; - register unsigned attr; + register unsigned val,mask,attr; + char *ip=0; Namfun_t *fp=0; + Namval_t *typep=0; for(fp=np->nvfun;fp;fp=fp->next) { - if(fp->type || (fp->disc && fp->disc->typef &&(*fp->disc->typef)(np,fp))) + if((typep=fp->type) || (fp->disc && fp->disc->typef && (typep=(*fp->disc->typef)(np,fp)))) break; } #if 0 @@ -296,11 +342,31 @@ if ((attr=nv_isattr(np,~NV_NOFREE)) || fp) { - if((attr&NV_NOPRINT)==NV_NOPRINT) + if((attr&NV_NOPRINT|NV_INTEGER)==NV_NOPRINT) attr &= ~NV_NOPRINT; if(!attr && !fp) return; - if(prefix) +#if 1 + if(fp) + { + prefix = Empty; + attr &= NV_RDONLY|NV_ARRAY; + if(nv_isattr(np,NV_REF|NV_TAGGED)==(NV_REF|NV_TAGGED)) + attr |= (NV_REF|NV_TAGGED); + if(typep) + { + char *cp = typep->nvname; + if(cp = strrchr(cp,'.')) + cp++; + else + cp = typep->nvname; + sfputr(out,cp,' '); + fp = 0; + } + } + else +#endif + if(prefix && *prefix) sfputr(out,prefix,' '); for(tp = shtab_attributes; *tp->sh_name;tp++) { @@ -313,7 +379,7 @@ * with E attribute from being given the F * attribute as well */ - if(val==(NV_INTEGER|NV_DOUBLE) && (attr&NV_EXPNOTE)) + if(val==NV_DOUBLE && (attr&(NV_EXPNOTE|NV_HEXFLOAT))) continue; if(val&NV_INTEGER) mask |= NV_DOUBLE; @@ -324,38 +390,39 @@ if(val==NV_ARRAY) { Namarr_t *ap = nv_arrayptr(np); - if(array_assoc(ap)) + char **xp=0; + if(ap && array_assoc(ap)) { if(tp->sh_name[1]!='A') continue; } else if(tp->sh_name[1]=='A') continue; -#if 0 - cp = "associative"; - else - cp = "indexed"; - if(!prefix) - sfputr(out,cp,' '); - else if(*cp=='i') - tp++; -#endif + if(ap && !array_assoc(ap) && (xp=(char**)(ap+1)) && *xp) + ip = nv_namptr(*xp,0)->nvname; } if(prefix) { if(*tp->sh_name=='-') sfprintf(out,"%.2s ",tp->sh_name); + if(ip) + { + sfprintf(out,"[%s] ",ip); + ip = 0; + } } else sfputr(out,tp->sh_name+2,' '); if ((val&(NV_LJUST|NV_RJUST|NV_ZFILL)) && !(val&NV_INTEGER) && val!=NV_HOST) sfprintf(out,"%d ",nv_size(np)); + if(val==(NV_REF|NV_TAGGED)) + attr &= ~(NV_REF|NV_TAGGED); } if(val==NV_INTEGER && nv_isattr(np,NV_INTEGER)) { if(nv_size(np) != 10) { - if(nv_isattr(np, NV_DOUBLE)) + if(nv_isattr(np, NV_DOUBLE)== NV_DOUBLE) cp = "precision"; else cp = "base"; @@ -380,31 +447,63 @@ Dt_t *root; int noscope; int indent; + int nofollow; }; static void outval(char *name, const char *vname, struct Walk *wp) { register Namval_t *np, *nq; register Namfun_t *fp; - int isarray=0, associative=0, special=0; - if(!(np=nv_open(vname,wp->root,NV_ARRAY|NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope))) + int isarray=0, associative=0, special=0,mode=0; +#if 1 + if(*name!='.' || vname[strlen(vname)-1]==']') + mode = NV_ARRAY; +#endif + if(!(np=nv_open(vname,wp->root,mode|NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL|wp->noscope))) return; - if(nv_isarray(np) && *name=='.') - special = 1; - if(!special && (fp=nv_hasdisc(np,&treedisc))) + fp = nv_hasdisc(np,&treedisc); + if(*name=='.') { + if(nv_isattr(np,NV_BINARY)) + return; +#if 1 + if(fp && np->nvalue.cp && np->nvalue.cp!=Empty) + { + nv_local = 1; + fp = 0; + } +#endif + if(fp) + return; + if(nv_isarray(np)) +#if 1 + return; +#else + special = 1; +#endif + } + if(!special && fp) + { + Namfun_t *xp; if(!wp->out) { fp = nv_stack(np,fp); if(fp = nv_stack(np,NIL(Namfun_t*))) free((void*)fp); np->nvfun = 0; + return; } - return; + for(xp=fp->next; xp; xp = xp->next) + { + if(xp->disc && (xp->disc->getval || xp->disc->getnum)) + break; + } + if(!xp) + return; } - if(nv_isnull(np)) + if((nv_isnull(np) || np->nvalue.cp==Empty) && !nv_isarray(np)) return; - if(special || nv_isarray(np)) + if(special || (nv_isarray(np) && nv_arrayptr(np))) { isarray=1; associative= nv_aindex(np)<0; @@ -421,15 +520,21 @@ } if(isarray==1 && !nq) return; + if(isarray==0 && nv_isarray(np) && nv_isnull(np)) /* empty array */ + isarray = 2; + special |= wp->nofollow; if(special) { +#if 0 associative = 1; +#endif sfnputc(wp->out,'\t',wp->indent); } else { sfnputc(wp->out,'\t',wp->indent); - nv_attribute(np,wp->out,"typeset",'='); + if(*name!='.') + nv_attribute(np,wp->out,"typeset",'='); nv_outname(wp->out,name,-1); sfputc(wp->out,(isarray==2?'\n':'=')); if(isarray) @@ -440,17 +545,49 @@ sfnputc(wp->out,'\t',++wp->indent); } } + fp = np->nvfun; +#if 0 + if(*name=='.') +#else + if(*name=='.' && !isarray) +#endif + np->nvfun = 0; while(1) { - char *fmtq,*ep; + char *fmtq,*ep,*xp; +#if 1 + Namval_t *mp; + if(special && (mp=nv_opensub(np)) && nv_isvtree(mp)) + { + if(!nv_nextsub(np)) + break; + continue; + } + if(isarray && (associative||special)) +#else if(isarray && associative) +#endif { if(!(fmtq = nv_getsub(np))) break; sfprintf(wp->out,"[%s]",sh_fmtq(fmtq)); sfputc(wp->out,'='); } - if(!(fmtq = sh_fmtq(nv_getval(np)))) + if(!(ep=nv_getval(np))) + continue; + xp = 0; + if(nv_isattr(np,NV_INTEGER|NV_LJUST)==NV_LJUST) + { + xp = ep+nv_size(np); + while(--xp>ep && *xp==' '); + if(xp>ep || *xp!=' ') + xp++; + if(xp < (ep+nv_size(np))) + *xp = 0; + else + xp = 0; + } + if(!(fmtq = sh_fmtq(ep))) fmtq = ""; else if(!associative && (ep=strchr(fmtq,'='))) { @@ -466,10 +603,19 @@ sfprintf(wp->out,"(%s)\n",fmtq); else sfputr(wp->out,fmtq,'\n'); + if(xp) + *xp = ' '; if(!nv_nextsub(np)) break; - sfnputc(wp->out,'\t',wp->indent); + if(!special || !(mp=nv_opensub(np)) || !nv_isvtree(mp)) + sfnputc(wp->out,'\t',wp->indent); } +#if 0 + if(*name=='.') +#else + if(*name=='.' && !isarray) +#endif + np->nvfun = fp; if(isarray && !special) { sfnputc(wp->out,'\t',--wp->indent); @@ -483,8 +629,8 @@ static char **genvalue(char **argv, const char *prefix, int n, struct Walk *wp) { register char *cp,*nextcp,*arg; - register int m,r; register Sfio_t *outfile = wp->out; + register int m,r,l; if(n==0) m = strlen(prefix); else if(cp=nextdot(prefix)) @@ -514,18 +660,37 @@ { if(outfile) { + Namval_t *np,*tp; + *nextcp = 0; + np=nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL|wp->noscope); + if(!np || (nv_isarray(np) && (!(tp=nv_opensub(np)) || !nv_isvtree(tp)))) + { + *nextcp = '.'; + continue; + } sfnputc(outfile,'\t',wp->indent); + if(tp = nv_type(np)) + { + char *sp; + if(sp = strrchr(tp->nvname,'.')) + sp++; + else + sp = tp->nvname; + sfputr(outfile,sp,' '); + } nv_outname(outfile,cp,nextcp-cp); sfputc(outfile,'='); + *nextcp = '.'; } + else + continue; argv = genvalue(argv,cp,n+m+r,wp); - if(outfile) - sfputc(outfile,'\n'); + sfputc(outfile,'\n'); if(*argv) continue; break; } - else if(outfile && argv[1] && memcmp(arg,argv[1],r=strlen(arg))==0 && argv[1][r]=='[') + else if(outfile && !wp->nofollow && argv[1] && memcmp(arg,argv[1],l=strlen(arg))==0 && argv[1][l]=='[') { Namval_t *np = nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope); if(!np) @@ -533,8 +698,9 @@ sfnputc(outfile,'\t',wp->indent); nv_attribute(np,outfile,"typeset",1); nv_close(np); - sfputr(outfile,arg+m+(n?n+1:0),'='); - argv = genvalue(++argv,cp,cp-arg ,wp); + sfputr(outfile,arg+m+r+(n?n:0),'='); + wp->nofollow=1; + argv = genvalue(argv,cp,cp-arg ,wp); sfputc(outfile,'\n'); } else if(outfile && *cp=='[') @@ -549,6 +715,7 @@ } else break; + wp->nofollow = 0; } if(outfile) { @@ -559,7 +726,7 @@ outval(".",prefix-n,wp); if(c=='.') cp[m-1] = c; - sfnputc(outfile,'\t',wp->indent-1); + sfnputc(outfile,'\t',--wp->indent); sfputc(outfile,')'); } return(--argv); @@ -581,16 +748,30 @@ char *subscript=0; void *dir; int n=0, noscope=(dlete&NV_NOSCOPE); + Namarr_t *arp = nv_arrayptr(np); + Dt_t *save_tree = sh.var_tree; + Namval_t *mp=0; + if(sh.last_root) + sh.var_tree = sh.last_root; stakputs(nv_name(np)); - if(subscript = nv_getsub(np)) + if(arp && !(arp->nelem&ARRAY_SCAN) && (subscript = nv_getsub(np))) { +#if 1 + mp = nv_opensub(np); +#endif stakputc('['); stakputs(subscript); stakputc(']'); stakputc('.'); } +#if 1 + else if(*stakptr(staktell()-1) == ']') + mp = np; +#endif name = stakfreeze(1); - dir = nv_diropen(name); + sh.last_root = 0; + dir = nv_diropen(mp,name); + walk.root = sh.last_root; if(subscript) name[strlen(name)-1] = 0; while(cp = nv_dirnext(dir)) @@ -616,26 +797,39 @@ else sfseek(outfile,0L,SEEK_SET); walk.out = outfile; - walk.root = sh.last_root; walk.indent = 0; + walk.nofollow = 0; walk.noscope = noscope; genvalue(argv,name,0,&walk); stakset(savptr,savtop); + sh.var_tree = save_tree; if(!outfile) return((char*)0); sfputc(out,0); return((char*)out->_data); } +Namfun_t *nv_isvtree(Namval_t *np) +{ + if(np) + return(nv_hasdisc(np,&treedisc)); + return(0); +} + /* * get discipline for compound initializations */ char *nv_getvtree(register Namval_t *np, Namfun_t *fp) { - NOT_USED(fp); - if(nv_isattr(np,NV_BINARY) && nv_isattr(np,NV_RAW)) + + for(; fp && fp->next; fp=fp->next) + { + if(fp->next->disc && (fp->next->disc->getnum || fp->next->disc->getval)) + return(nv_getv(np,fp)); + } + if(nv_isattr(np,NV_BINARY) && !nv_isattr(np,NV_RAW)) return(nv_getv(np,fp)); - if(nv_isattr(np,NV_ARRAY) && nv_arraychild(np,(Namval_t*)0,0)==np) + if(nv_isattr(np,NV_ARRAY) && !nv_type(np) && nv_arraychild(np,(Namval_t*)0,0)==np) return(nv_getv(np,fp)); return(walk_tree(np,0)); } @@ -647,10 +841,12 @@ { struct Namarray *ap; int nleft = 0; - if(!nv_isattr(np,NV_INTEGER)) + if(!val && !fp->next && nv_isattr(np,NV_NOFREE)) + return; + if(!nv_isattr(np,(NV_INTEGER|NV_BINARY))) walk_tree(np,(flags&NV_NOSCOPE)|1); nv_putv(np, val, flags,fp); - if(nv_isattr(np,NV_INTEGER)) + if(val && nv_isattr(np,(NV_INTEGER|NV_BINARY))) return; if(ap= nv_arrayptr(np)) nleft = array_elem(ap); @@ -658,9 +854,7 @@ { fp = nv_stack(np,fp); if(fp = nv_stack(np,NIL(Namfun_t*))) - { free((void*)fp); - } } } @@ -670,6 +864,8 @@ void nv_setvtree(register Namval_t *np) { register Namfun_t *nfp; + if(sh.subshell) + sh_assignok(np,1); if(nv_hasdisc(np, &treedisc)) return; nfp = newof(NIL(void*),Namfun_t,1,0); Index: src/lib/libshell/common/sh/init.c =================================================================== --- src/lib/libshell/common/sh/init.c (revision 974) +++ src/lib/libshell/common/sh/init.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -53,7 +53,7 @@ #endif /* SHOPT_MULTIBYTE */ #if SHOPT_BASH - extern void bash_init(int); + extern void bash_init(Shell_t*,int); #endif #define RANDMASK 0x7fff @@ -77,23 +77,15 @@ struct rand { Namfun_t hdr; - Shell_t *sh; int32_t rand_last; }; struct ifs { Namfun_t hdr; - Shell_t *sh; Namval_t *ifsnp; }; -struct shell -{ - Namfun_t hdr; - Shell_t *sh; -}; - struct match { Namfun_t hdr; @@ -112,28 +104,28 @@ Namfun_t VPATH_init; #endif /* SHOPT_FS_3D */ struct ifs IFS_init; - struct shell PATH_init; -#ifdef PATH_BFPATH - struct shell FPATH_init; - struct shell CDPATH_init; -#endif - struct shell SHELL_init; - struct shell ENV_init; - struct shell VISUAL_init; - struct shell EDITOR_init; - struct shell OPTINDEX_init; + Namfun_t PATH_init; + Namfun_t FPATH_init; + Namfun_t CDPATH_init; + Namfun_t SHELL_init; + Namfun_t ENV_init; + Namfun_t VISUAL_init; + Namfun_t EDITOR_init; + Namfun_t HISTFILE_init; + Namfun_t HISTSIZE_init; + Namfun_t OPTINDEX_init; struct seconds SECONDS_init; struct rand RAND_init; - struct shell LINENO_init; - struct shell L_ARG_init; + Namfun_t LINENO_init; + Namfun_t L_ARG_init; struct match SH_MATCH_init; #ifdef _hdr_locale - struct shell LC_TYPE_init; - struct shell LC_NUM_init; - struct shell LC_COLL_init; - struct shell LC_MSG_init; - struct shell LC_ALL_init; - struct shell LANG_init; + Namfun_t LC_TYPE_init; + Namfun_t LC_NUM_init; + Namfun_t LC_COLL_init; + Namfun_t LC_MSG_init; + Namfun_t LC_ALL_init; + Namfun_t LANG_init; #endif /* _hdr_locale */ } Init_t; @@ -173,12 +165,13 @@ static void put_ed(register Namval_t* np,const char *val,int flags,Namfun_t *fp) { register const char *cp, *name=nv_name(np); - if(*name=='E' && nv_getval(nv_scoped(VISINOD))) + Shell_t *shp = nv_shell(np); + if(*name=='E' && nv_getval(sh_scoped(shp,VISINOD))) goto done; sh_offoption(SH_VI); sh_offoption(SH_EMACS); sh_offoption(SH_GMACS); - if(!(cp=val) && (*name=='E' || !(cp=nv_getval(nv_scoped(EDITNOD))))) + if(!(cp=val) && (*name=='E' || !(cp=nv_getval(sh_scoped(shp,EDITNOD))))) goto done; /* turn on vi or emacs option if editor name is either*/ cp = path_basename(cp); @@ -192,12 +185,33 @@ nv_putv(np, val, flags, fp); } +/* Trap for HISTFILE and HISTSIZE variables */ +static void put_history(register Namval_t* np,const char *val,int flags,Namfun_t *fp) +{ + Shell_t *shp = nv_shell(np); + char *old; + void *histopen = shp->hist_ptr; + if(val && histopen) + { + if(np==HISTFILE && strcmp(val,nv_getval(HISTFILE))==0) + return; + if(np==HISTSIZE && sh_arith(val)==nv_getnum(HISTSIZE)) + return; + hist_close(shp->hist_ptr); + } + nv_putv(np, val, flags, fp); + if(val && histopen) + sh_histinit(shp); +} + /* Trap for OPTINDEX */ static void put_optindex(Namval_t* np,const char *val,int flags,Namfun_t *fp) { - Shell_t *shp = ((struct shell*)fp)->sh; + Shell_t *shp = nv_shell(np); shp->st.opterror = shp->st.optchar = 0; nv_putv(np, val, flags, fp); + if(!val) + nv_disc(np,fp,NV_POP); } static Sfdouble_t nget_optindex(register Namval_t* np, Namfun_t *fp) @@ -205,34 +219,37 @@ return((Sfdouble_t)*np->nvalue.lp); } +static Namfun_t *clone_optindex(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp) +{ + Namfun_t *dp = (Namfun_t*)malloc(sizeof(Namfun_t)); + memcpy((void*)dp,(void*)fp,sizeof(Namfun_t)); + mp->nvalue.lp = np->nvalue.lp; + dp->nofree = 0; + return(dp); +} + + /* Trap for restricted variables FPATH, PATH, SHELL, ENV */ static void put_restricted(register Namval_t* np,const char *val,int flags,Namfun_t *fp) { - Shell_t *shp = ((struct shell*)fp)->sh; - int path_scoped = 0; -#ifdef PATH_BFPATH + Shell_t *shp = nv_shell(np); + int path_scoped = 0; Pathcomp_t *pp; char *name = nv_name(np); -#endif if(!(flags&NV_RDONLY) && sh_isoption(SH_RESTRICTED)) errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np)); if(np==PATHNOD || (path_scoped=(strcmp(name,PATHNOD->nvname)==0))) { -#ifndef PATH_BFPATH - shp->lastpath = 0; -#endif nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED); if(path_scoped && !val) val = PATHNOD->nvalue.cp; } if(val && !(flags&NV_RDONLY) && np->nvalue.cp && strcmp(val,np->nvalue.cp)==0) return; -#ifdef PATH_BFPATH - if(shp->pathlist && np==FPATHNOD) + if(np==FPATHNOD) shp->pathlist = (void*)path_unsetfpath((Pathcomp_t*)shp->pathlist); -#endif nv_putv(np, val, flags, fp); -#ifdef PATH_BFPATH + shp->universe = 0; if(shp->pathlist) { val = np->nvalue.cp; @@ -255,14 +272,12 @@ path_dump((Pathcomp_t*)shp->pathlist); #endif } -#endif } -#ifdef PATH_BFPATH static void put_cdpath(register Namval_t* np,const char *val,int flags,Namfun_t *fp) { Pathcomp_t *pp; - Shell_t *shp = ((struct shell*)fp)->sh; + Shell_t *shp = nv_shell(np); nv_putv(np, val, flags, fp); if(!shp->cdpathlist) return; @@ -271,7 +286,6 @@ if(shp->cdpathlist = (void*)pp) pp->shp = shp; } -#endif #ifdef _hdr_locale /* @@ -295,6 +309,7 @@ /* Trap for LC_ALL, LC_TYPE, LC_MESSAGES, LC_COLLATE and LANG */ static void put_lang(Namval_t* np,const char *val,int flags,Namfun_t *fp) { + Shell_t *shp = nv_shell(np); int type; char *lc_all = nv_getval(LCALLNOD); char *name = nv_name(np); @@ -318,7 +333,7 @@ { if(!setlocale(type,val?val:"")) { - if(!sh_isstate(SH_INIT) || sh.login_sh==0) + if(!sh_isstate(SH_INIT) || shp->login_sh==0) errormsg(SH_DICT,0,e_badlocale,val); return; } @@ -397,7 +412,7 @@ register struct ifs *ip = (struct ifs*)fp; register char *cp, *value; register int c,n; - register Shell_t *shp = ip->sh; + register Shell_t *shp = nv_shell(np); value = nv_getv(np,fp); if(np!=ip->ifsnp) { @@ -463,6 +478,7 @@ if(!np->nvalue.dp) { nv_setsize(np,3); + nv_onattr(np,NV_DOUBLE); np->nvalue.dp = new_of(double,0); } nv_putv(np, val, flags, fp); @@ -473,14 +489,15 @@ static char* get_seconds(register Namval_t* np, Namfun_t *fp) { + Shell_t *shp = nv_shell(np); register int places = nv_size(np); struct tms tp; double d, offset = (np->nvalue.dp?*np->nvalue.dp:0); NOT_USED(fp); timeofday(&tp); d = dtime(&tp)- offset; - sfprintf(sh.strbuf,"%.*f",places,d); - return(sfstruse(sh.strbuf)); + sfprintf(shp->strbuf,"%.*f",places,d); + return(sfstruse(shp->strbuf)); } static Sfdouble_t nget_seconds(register Namval_t* np, Namfun_t *fp) @@ -554,7 +571,7 @@ static void put_lineno(Namval_t* np,const char *val,int flags,Namfun_t *fp) { register long n; - Shell_t *shp = ((struct shell*)fp)->sh; + Shell_t *shp = nv_shell(np); if(!val) { nv_stack(np, NIL(Namfun_t*)); @@ -576,25 +593,27 @@ static char* get_lastarg(Namval_t* np, Namfun_t *fp) { + Shell_t *shp = nv_shell(np); NOT_USED(np); - return(sh.lastarg); + return(shp->lastarg); } static void put_lastarg(Namval_t* np,const char *val,int flags,Namfun_t *fp) { + Shell_t *shp = nv_shell(np); if(flags&NV_INTEGER) { - sfprintf(sh.strbuf,"%.*g",12,*((double*)val)); - val = sfstruse(sh.strbuf); + sfprintf(shp->strbuf,"%.*g",12,*((double*)val)); + val = sfstruse(shp->strbuf); } - if(sh.lastarg && !nv_isattr(np,NV_NOFREE)) - free((void*)sh.lastarg); + if(shp->lastarg && !nv_isattr(np,NV_NOFREE)) + free((void*)shp->lastarg); else nv_offattr(np,NV_NOFREE); if(val) - sh.lastarg = strdup(val); + shp->lastarg = strdup(val); else - sh.lastarg = 0; + shp->lastarg = 0; } static int hasgetdisc(register Namfun_t *fp) @@ -635,7 +654,7 @@ } memcpy(mp->val,v,vsize); mp->val[vsize] = 0; - nv_putsub(SH_MATCHNOD, NIL(char*), nmatch|ARRAY_FILL); + nv_putsub(SH_MATCHNOD, NIL(char*), (nmatch-1)|ARRAY_FILL); mp->lastsub = -1; } } @@ -709,16 +728,15 @@ static const Namdisc_t IFS_disc = { sizeof(struct ifs), put_ifs, get_ifs }; -const Namdisc_t RESTRICTED_disc = { sizeof(struct shell), put_restricted }; -#ifdef PATH_BFPATH -static const Namdisc_t CDPATH_disc = { sizeof(struct shell), put_cdpath }; -#endif -static const Namdisc_t EDITOR_disc = { sizeof(struct shell), put_ed }; -static const Namdisc_t OPTINDEX_disc = { sizeof(struct shell), put_optindex, 0, nget_optindex }; +const Namdisc_t RESTRICTED_disc = { sizeof(Namfun_t), put_restricted }; +static const Namdisc_t CDPATH_disc = { sizeof(Namfun_t), put_cdpath }; +static const Namdisc_t EDITOR_disc = { sizeof(Namfun_t), put_ed }; +static const Namdisc_t HISTFILE_disc = { sizeof(Namfun_t), put_history }; +static const Namdisc_t OPTINDEX_disc = { sizeof(Namfun_t), put_optindex, 0, nget_optindex, 0, 0, clone_optindex }; static const Namdisc_t SECONDS_disc = { sizeof(struct seconds), put_seconds, get_seconds, nget_seconds }; static const Namdisc_t RAND_disc = { sizeof(struct rand), put_rand, get_rand, nget_rand }; -static const Namdisc_t LINENO_disc = { sizeof(struct shell), put_lineno, get_lineno, nget_lineno }; -static const Namdisc_t L_ARG_disc = { sizeof(struct shell), put_lastarg, get_lastarg }; +static const Namdisc_t LINENO_disc = { sizeof(Namfun_t), put_lineno, get_lineno, nget_lineno }; +static const Namdisc_t L_ARG_disc = { sizeof(Namfun_t), put_lastarg, get_lastarg }; #if SHOPT_NAMESPACE static char* get_nspace(Namval_t* np, Namfun_t *fp) @@ -732,7 +750,7 @@ #endif /* SHOPT_NAMESPACE */ #ifdef _hdr_locale - static const Namdisc_t LC_disc = { sizeof(struct shell), put_lang }; + static const Namdisc_t LC_disc = { sizeof(Namfun_t), put_lang }; #endif /* _hdr_locale */ /* @@ -841,25 +859,66 @@ } break; } - if (*s++ != 's' || *s++ != 'h') - return 0; - t |= SH_TYPE_SH; - if ((t & SH_TYPE_KSH) && *s == '9' && *(s+1) == '3') - s += 2; + if (*s++ == 's' && (*s == 'h' || *s == 'u')) + { + s++; + t |= SH_TYPE_SH; + if ((t & SH_TYPE_KSH) && *s == '9' && *(s+1) == '3') + s += 2; #if _WINIX - if (*s == '.' && *(s+1) == 'e' && *(s+2) == 'x' && *(s+3) == 'e') - s += 4; + if (*s == '.' && *(s+1) == 'e' && *(s+2) == 'x' && *(s+3) == 'e') + s += 4; #endif - if (*s) - t &= ~(SH_TYPE_PROFILE|SH_TYPE_RESTRICTED); - return t; + if (!isalnum(*s)) + return t; + } + return t & ~(SH_TYPE_BASH|SH_TYPE_KSH|SH_TYPE_PROFILE|SH_TYPE_RESTRICTED); } + +static char *get_mode(Namval_t* np, Namfun_t* nfp) +{ + mode_t mode = nv_getn(np,nfp); + return(fmtperm(mode)); +} + +static void put_mode(Namval_t* np, const char* val, int flag, Namfun_t* nfp) +{ + if(val) + { + mode_t mode; + char *last; + if(flag&NV_INTEGER) + { + if(flag&NV_LONG) + mode = *(Sfdouble_t*)val; + else + mode = *(double*)val; + } + else + mode = strperm(val, &last,0); + if(*last) + errormsg(SH_DICT,ERROR_exit(1),"%s: invalid mode string",val); + nv_putv(np,(char*)&mode,NV_INTEGER,nfp); + } + else + nv_putv(np,val,flag,nfp); +} + +static const Namdisc_t modedisc = +{ + 0, + put_mode, + get_mode, +}; + + /* * initialize the shell */ Shell_t *sh_init(register int argc,register char *argv[], void(*userinit)(int)) { + Shell_t *shp = &sh; register int n; int type; static char *login_files[3]; @@ -871,25 +930,26 @@ #else init_ebcdic(); #endif - umask(umask(0)); - sh.mac_context = sh_macopen(&sh); - sh.arg_context = sh_argopen(&sh); - sh.lex_context = (void*)sh_lexopen(0,&sh,1); - sh.ed_context = (void*)ed_open(&sh); - sh.strbuf = sfstropen(); - sfsetbuf(sh.strbuf,(char*)0,64); + umask(shp->mask=umask(0)); + shp->mac_context = sh_macopen(shp); + shp->arg_context = sh_argopen(shp); + shp->lex_context = (void*)sh_lexopen(0,shp,1); + shp->ed_context = (void*)ed_open(shp); + shp->strbuf = sfstropen(); + shp->stk = stkstd; + sfsetbuf(shp->strbuf,(char*)0,64); sh_onstate(SH_INIT); error_info.exit = sh_exit; error_info.id = path_basename(argv[0]); #if ERROR_VERSION >= 20000102L error_info.catalog = e_dict; #endif - sh.cpipe[0] = -1; - sh.coutpipe = -1; - sh.userid=getuid(); - sh.euserid=geteuid(); - sh.groupid=getgid(); - sh.egroupid=getegid(); + shp->cpipe[0] = -1; + shp->coutpipe = -1; + shp->userid=getuid(); + shp->euserid=geteuid(); + shp->groupid=getgid(); + shp->egroupid=getegid(); for(n=0;n < 10; n++) { /* don't use lower bits when rand() generates large numbers */ @@ -899,41 +959,41 @@ break; } } - sh.lim.clk_tck = getconf("CLK_TCK"); - sh.lim.arg_max = getconf("ARG_MAX"); - sh.lim.open_max = getconf("OPEN_MAX"); - sh.lim.child_max = getconf("CHILD_MAX"); - sh.lim.ngroups_max = getconf("NGROUPS_MAX"); - sh.lim.posix_version = getconf("VERSION"); - sh.lim.posix_jobcontrol = getconf("JOB_CONTROL"); - if(sh.lim.arg_max <=0) - sh.lim.arg_max = ARG_MAX; - if(sh.lim.child_max <=0) - sh.lim.child_max = CHILD_MAX; - if(sh.lim.open_max <0) - sh.lim.open_max = OPEN_MAX; - if(sh.lim.open_max > (SHRT_MAX-2)) - sh.lim.open_max = SHRT_MAX-2; - if(sh.lim.clk_tck <=0) - sh.lim.clk_tck = CLK_TCK; + shp->lim.clk_tck = getconf("CLK_TCK"); + shp->lim.arg_max = getconf("ARG_MAX"); + shp->lim.open_max = getconf("OPEN_MAX"); + shp->lim.child_max = getconf("CHILD_MAX"); + shp->lim.ngroups_max = getconf("NGROUPS_MAX"); + shp->lim.posix_version = getconf("VERSION"); + shp->lim.posix_jobcontrol = getconf("JOB_CONTROL"); + if(shp->lim.arg_max <=0) + shp->lim.arg_max = ARG_MAX; + if(shp->lim.child_max <=0) + shp->lim.child_max = CHILD_MAX; + if(shp->lim.open_max <0) + shp->lim.open_max = OPEN_MAX; + if(shp->lim.open_max > (SHRT_MAX-2)) + shp->lim.open_max = SHRT_MAX-2; + if(shp->lim.clk_tck <=0) + shp->lim.clk_tck = CLK_TCK; #if SHOPT_FS_3D if(fs3d(FS3D_TEST)) - sh.lim.fs3d = 1; + shp->lim.fs3d = 1; #endif /* SHOPT_FS_3D */ - sh_ioinit(); + sh_ioinit(shp); /* initialize signal handling */ - sh_siginit(); + sh_siginit(shp); stakinstall(NIL(Stak_t*),nospace); /* set up memory for name-value pairs */ - sh.init_context = nv_init(&sh); + shp->init_context = nv_init(shp); /* read the environment */ if(argc>0) { type = sh_type(*argv); if(type&SH_TYPE_LOGIN) - sh.login_sh = 2; + shp->login_sh = 2; } - env_init(&sh); + env_init(shp); #if SHOPT_SPAWN { /* @@ -942,17 +1002,17 @@ */ char *last, *cp=nv_getval(L_ARGNOD); char buff[PATH_MAX+1]; - sh.shpath = 0; - sfprintf(sh.strbuf,"/proc/%d/exe",getpid()); - if((n=readlink(sfstruse(sh.strbuf),buff,sizeof(buff)-1))>0) + shp->shpath = 0; + sfprintf(shp->strbuf,"/proc/%d/exe",getpid()); + if((n=readlink(sfstruse(shp->strbuf),buff,sizeof(buff)-1))>0) { buff[n] = 0; - sh.shpath = strdup(buff); + shp->shpath = strdup(buff); } else if((cp && (sh_type(cp)&SH_TYPE_SH)) || (argc>0 && strchr(cp= *argv,'/'))) { if(*cp=='/') - sh.shpath = strdup(cp); + shp->shpath = strdup(cp); else if(cp = nv_getval(PWDNOD)) { int offset = staktell(); @@ -960,7 +1020,7 @@ stakputc('/'); stakputs(argv[0]); pathcanon(stakptr(offset),PATH_DOTDOT); - sh.shpath = strdup(stakptr(offset)); + shp->shpath = strdup(stakptr(offset)); stakseek(offset); } } @@ -972,7 +1032,7 @@ #endif /* SHOPT_FS_3D */ astconfdisc(newconf); #if SHOPT_TIMEOUT - sh.st.tmout = SHOPT_TIMEOUT; + shp->st.tmout = SHOPT_TIMEOUT; #endif /* SHOPT_TIMEOUT */ /* initialize jobs table */ job_clear(); @@ -990,7 +1050,7 @@ /* check for invocation as bash */ if(type&SH_TYPE_BASH) { - sh.userinit = userinit = bash_init; + shp->userinit = userinit = bash_init; sh_onoption(SH_BASH); sh_onstate(SH_PREINIT); (*userinit)(0); @@ -998,25 +1058,25 @@ } #endif /* look for options */ - /* sh.st.dolc is $# */ - if((sh.st.dolc = sh_argopts(-argc,argv)) < 0) + /* shp->st.dolc is $# */ + if((shp->st.dolc = sh_argopts(-argc,argv,shp)) < 0) { - sh.exitval = 2; - sh_done(0); + shp->exitval = 2; + sh_done(shp,0); } opt_info.disc = 0; - sh.st.dolv=argv+(argc-1)-sh.st.dolc; - sh.st.dolv[0] = argv[0]; - if(sh.st.dolc < 1) + shp->st.dolv=argv+(argc-1)-shp->st.dolc; + shp->st.dolv[0] = argv[0]; + if(shp->st.dolc < 1) sh_onoption(SH_SFLAG); if(!sh_isoption(SH_SFLAG)) { - sh.st.dolc--; - sh.st.dolv++; + shp->st.dolc--; + shp->st.dolv++; #if _WINIX { char* name; - name = sh.st.dolv[0]; + name = shp->st.dolv[0]; if(name[1]==':' && (name[2]=='/' || name[2]=='\\')) { #if _lib_pathposix @@ -1041,21 +1101,21 @@ #if SHOPT_PFSH if (sh_isoption(SH_PFSH)) { - struct passwd *pw = getpwuid(sh.userid); + struct passwd *pw = getpwuid(shp->userid); if(pw) - sh.user = strdup(pw->pw_name); + shp->user = strdup(pw->pw_name); } #endif /* set[ug]id scripts require the -p flag */ - if(sh.userid!=sh.euserid || sh.groupid!=sh.egroupid) + if(shp->userid!=shp->euserid || shp->groupid!=shp->egroupid) { #if SHOPT_P_SUID /* require sh -p to run setuid and/or setgid */ - if(!sh_isoption(SH_PRIVILEGED) && sh.euserid < SHOPT_P_SUID) + if(!sh_isoption(SH_PRIVILEGED) && shp->euserid < SHOPT_P_SUID) { - setuid(sh.euserid=sh.userid); - setgid(sh.egroupid=sh.groupid); + setuid(shp->euserid=shp->userid); + setgid(shp->egroupid=shp->groupid); } else #else @@ -1063,7 +1123,7 @@ #endif /* SHOPT_P_SUID */ #ifdef SHELLMAGIC /* careful of #! setuid scripts with name beginning with - */ - if(sh.login_sh && argv[1] && strcmp(argv[0],argv[1])==0) + if(shp->login_sh && argv[1] && strcmp(argv[0],argv[1])==0) errormsg(SH_DICT,ERROR_exit(1),e_prohibited); #endif /*SHELLMAGIC*/ } @@ -1071,25 +1131,47 @@ sh_offoption(SH_PRIVILEGED); /* shname for $0 in profiles and . scripts */ if(strmatch(argv[1],e_devfdNN)) - sh.shname = strdup(argv[0]); + shp->shname = strdup(argv[0]); else - sh.shname = strdup(sh.st.dolv[0]); + shp->shname = strdup(shp->st.dolv[0]); /* * return here for shell script execution * but not for parenthesis subshells */ - error_info.id = strdup(sh.st.dolv[0]); /* error_info.id is $0 */ - sh.jmpbuffer = (void*)&sh.checkbase; - sh_pushcontext(&sh.checkbase,SH_JMPSCRIPT); - sh.st.self = &sh.global; - sh.topscope = (Shscope_t*)sh.st.self; + error_info.id = strdup(shp->st.dolv[0]); /* error_info.id is $0 */ + shp->jmpbuffer = (void*)&shp->checkbase; + sh_pushcontext(&shp->checkbase,SH_JMPSCRIPT); + shp->st.self = &shp->global; + shp->topscope = (Shscope_t*)shp->st.self; sh_offstate(SH_INIT); login_files[0] = (char*)e_profile; login_files[1] = ".profile"; - sh.login_files = login_files; - if(sh.userinit=userinit) + shp->login_files = login_files; + shp->bltindata.version = SH_VERSION; + shp->bltindata.shp = shp; + shp->bltindata.shrun = sh_run; + shp->bltindata.shtrap = sh_trap; + shp->bltindata.shexit = sh_exit; + shp->bltindata.shbltin = sh_addbuiltin; +#if 0 +#define NV_MKINTTYPE(x,y,z) nv_mkinttype(#x,sizeof(x),(x)-1<0,(y),(Namdisc_t*)z); + NV_MKINTTYPE(pid_t,"process id",0); + NV_MKINTTYPE(gid_t,"group id",0); + NV_MKINTTYPE(uid_t,"user id",0); + NV_MKINTTYPE(size_t,(const char*)0,0); + NV_MKINTTYPE(ssize_t,(const char*)0,0); + NV_MKINTTYPE(off_t,"offset in bytes",0); + NV_MKINTTYPE(ino_t,"\ai-\anode number",0); + NV_MKINTTYPE(mode_t,(const char*)0,&modedisc); + NV_MKINTTYPE(dev_t,"device id",0); + NV_MKINTTYPE(nlink_t,"hard link count",0); + NV_MKINTTYPE(blkcnt_t,"block count",0); + NV_MKINTTYPE(time_t,"seconds since the epoch",0); + nv_mkstat(); +#endif + if(shp->userinit=userinit) (*userinit)(0); - return(&sh); + return(shp); } Shell_t *sh_getinterp(void) @@ -1102,25 +1184,27 @@ */ int sh_reinit(char *argv[]) { + Shell_t *shp = &sh; Shopt_t opt; - dtclear(sh.fun_tree); - dtclose(sh.alias_tree); - sh.alias_tree = inittree(&sh,shtab_aliases); - sh.namespace = 0; - sh.inuse_bits = 0; - if(sh.userinit) - (*sh.userinit)(1); - if(sh.heredocs) + dtclear(shp->fun_tree); + dtclose(shp->alias_tree); + shp->alias_tree = inittree(shp,shtab_aliases); + shp->last_root = shp->var_tree; + shp->namespace = 0; + shp->inuse_bits = 0; + if(shp->userinit) + (*shp->userinit)(1); + if(shp->heredocs) { - sfclose(sh.heredocs); - sh.heredocs = 0; + sfclose(shp->heredocs); + shp->heredocs = 0; } /* remove locals */ sh_onstate(SH_INIT); - nv_scan(sh.var_tree,sh_envnolocal,(void*)0,NV_EXPORT,0); - nv_scan(sh.var_tree,sh_envnolocal,(void*)0,NV_ARRAY,NV_ARRAY); + nv_scan(shp->var_tree,sh_envnolocal,(void*)0,NV_EXPORT,0); + nv_scan(shp->var_tree,sh_envnolocal,(void*)0,NV_ARRAY,NV_ARRAY); sh_offstate(SH_INIT); - memset(sh.st.trapcom,0,(sh.st.trapmax+1)*sizeof(char*)); + memset(shp->st.trapcom,0,(shp->st.trapmax+1)*sizeof(char*)); memset((void*)&opt,0,sizeof(opt)); if(sh_isoption(SH_TRACKALL)) on_option(&opt,SH_TRACKALL); @@ -1132,17 +1216,17 @@ on_option(&opt,SH_VI); if(sh_isoption(SH_VIRAW)) on_option(&opt,SH_VIRAW); - sh.options = opt; + shp->options = opt; /* set up new args */ if(argv) - sh.arglist = sh_argcreate(argv); - if(sh.arglist) - sh_argreset(sh.arglist,NIL(struct dolnod*)); - sh.envlist=0; - sh.curenv = 0; - sh.shname = error_info.id = strdup(sh.st.dolv[0]); + shp->arglist = sh_argcreate(argv); + if(shp->arglist) + sh_argreset(shp,shp->arglist,NIL(struct dolnod*)); + shp->envlist=0; + shp->curenv = 0; + shp->shname = error_info.id = strdup(shp->st.dolv[0]); sh_offstate(SH_FORKED); - sh.fn_depth = sh.dot_depth = 0; + shp->fn_depth = shp->dot_depth = 0; sh_sigreset(0); return(1); } @@ -1152,11 +1236,7 @@ */ Namfun_t *nv_cover(register Namval_t *np) { -#ifdef PATH_BFPATH if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==FPATHNOD || np==CDPNOD || np==SECONDS) -#else - if(np==IFSNOD || np==PATHNOD || np==SHELLNOD || np==SECONDS) -#endif return(np->nvfun); #ifdef _hdr_locale if(np==LCALLNOD || np==LCTYPENOD || np==LCMSGNOD || np==LCCOLLNOD || np==LCNUMNOD || np==LANGNOD) @@ -1165,7 +1245,6 @@ return(0); } -static Namtype_t typeset; static const char *shdiscnames[] = { "tilde", 0}; /* @@ -1179,96 +1258,84 @@ ip = newof(0,Init_t,1,0); if(!ip) return(0); + shp->nvfun.last = (char*)shp; + shp->nvfun.nofree = 1; ip->sh = shp; shp->var_base = shp->var_tree = inittree(shp,shtab_variables); ip->IFS_init.hdr.disc = &IFS_disc; ip->IFS_init.hdr.nofree = 1; - ip->IFS_init.sh = shp; - ip->PATH_init.hdr.disc = &RESTRICTED_disc; - ip->PATH_init.hdr.nofree = 1; - ip->PATH_init.sh = shp; -#ifdef PATH_BFPATH - ip->FPATH_init.hdr.disc = &RESTRICTED_disc; - ip->FPATH_init.hdr.nofree = 1; - ip->FPATH_init.sh = shp; - ip->CDPATH_init.hdr.disc = &CDPATH_disc; - ip->CDPATH_init.hdr.nofree = 1; - ip->CDPATH_init.sh = shp; -#endif - ip->SHELL_init.hdr.disc = &RESTRICTED_disc; - ip->SHELL_init.sh = shp; - ip->SHELL_init.hdr.nofree = 1; - ip->ENV_init.hdr.disc = &RESTRICTED_disc; - ip->ENV_init.hdr.nofree = 1; - ip->ENV_init.sh = shp; - ip->VISUAL_init.hdr.disc = &EDITOR_disc; - ip->VISUAL_init.hdr.nofree = 1; - ip->VISUAL_init.sh = shp; - ip->EDITOR_init.hdr.disc = &EDITOR_disc; - ip->EDITOR_init.hdr.nofree = 1; - ip->EDITOR_init.sh = shp; - ip->OPTINDEX_init.hdr.disc = &OPTINDEX_disc; - ip->OPTINDEX_init.hdr.nofree = 1; - ip->OPTINDEX_init.sh = shp; + ip->PATH_init.disc = &RESTRICTED_disc; + ip->PATH_init.nofree = 1; + ip->FPATH_init.disc = &RESTRICTED_disc; + ip->FPATH_init.nofree = 1; + ip->CDPATH_init.disc = &CDPATH_disc; + ip->CDPATH_init.nofree = 1; + ip->SHELL_init.disc = &RESTRICTED_disc; + ip->SHELL_init.nofree = 1; + ip->ENV_init.disc = &RESTRICTED_disc; + ip->ENV_init.nofree = 1; + ip->VISUAL_init.disc = &EDITOR_disc; + ip->VISUAL_init.nofree = 1; + ip->EDITOR_init.disc = &EDITOR_disc; + ip->EDITOR_init.nofree = 1; + ip->HISTFILE_init.disc = &HISTFILE_disc; + ip->HISTFILE_init.nofree = 1; + ip->HISTSIZE_init.disc = &HISTFILE_disc; + ip->HISTSIZE_init.nofree = 1; + ip->OPTINDEX_init.disc = &OPTINDEX_disc; + ip->OPTINDEX_init.nofree = 1; ip->SECONDS_init.hdr.disc = &SECONDS_disc; ip->SECONDS_init.hdr.nofree = 1; - ip->SECONDS_init.sh = shp; ip->RAND_init.hdr.disc = &RAND_disc; ip->RAND_init.hdr.nofree = 1; ip->SH_MATCH_init.hdr.disc = &SH_MATCH_disc; ip->SH_MATCH_init.hdr.nofree = 1; - ip->LINENO_init.hdr.disc = &LINENO_disc; - ip->LINENO_init.hdr.nofree = 1; - ip->LINENO_init.sh = shp; - ip->L_ARG_init.hdr.disc = &L_ARG_disc; - ip->L_ARG_init.hdr.nofree = 1; + ip->LINENO_init.disc = &LINENO_disc; + ip->LINENO_init.nofree = 1; + ip->L_ARG_init.disc = &L_ARG_disc; + ip->L_ARG_init.nofree = 1; #ifdef _hdr_locale - ip->LC_TYPE_init.hdr.disc = &LC_disc; - ip->LC_TYPE_init.hdr.nofree = 1; - ip->LC_NUM_init.hdr.disc = &LC_disc; - ip->LC_NUM_init.hdr.nofree = 1; - ip->LC_COLL_init.hdr.disc = &LC_disc; - ip->LC_COLL_init.hdr.nofree = 1; - ip->LC_MSG_init.hdr.disc = &LC_disc; - ip->LC_MSG_init.hdr.nofree = 1; - ip->LC_ALL_init.hdr.disc = &LC_disc; - ip->LC_ALL_init.hdr.nofree = 1; - ip->LANG_init.hdr.disc = &LC_disc; - ip->LANG_init.hdr.nofree = 1; - ip->LC_TYPE_init.sh = shp; - ip->LC_NUM_init.sh = shp; - ip->LC_COLL_init.sh = shp; - ip->LC_MSG_init.sh = shp; - ip->LANG_init.sh = shp; + ip->LC_TYPE_init.disc = &LC_disc; + ip->LC_TYPE_init.nofree = 1; + ip->LC_NUM_init.disc = &LC_disc; + ip->LC_NUM_init.nofree = 1; + ip->LC_COLL_init.disc = &LC_disc; + ip->LC_COLL_init.nofree = 1; + ip->LC_MSG_init.disc = &LC_disc; + ip->LC_MSG_init.nofree = 1; + ip->LC_ALL_init.disc = &LC_disc; + ip->LC_ALL_init.nofree = 1; + ip->LANG_init.disc = &LC_disc; + ip->LANG_init.nofree = 1; #endif /* _hdr_locale */ nv_stack(IFSNOD, &ip->IFS_init.hdr); - nv_stack(PATHNOD, &ip->PATH_init.hdr); -#ifdef PATH_BFPATH - nv_stack(FPATHNOD, &ip->FPATH_init.hdr); - nv_stack(CDPNOD, &ip->CDPATH_init.hdr); -#endif - nv_stack(SHELLNOD, &ip->SHELL_init.hdr); - nv_stack(ENVNOD, &ip->ENV_init.hdr); - nv_stack(VISINOD, &ip->VISUAL_init.hdr); - nv_stack(EDITNOD, &ip->EDITOR_init.hdr); - nv_stack(OPTINDNOD, &ip->OPTINDEX_init.hdr); + nv_stack(PATHNOD, &ip->PATH_init); + nv_stack(FPATHNOD, &ip->FPATH_init); + nv_stack(CDPNOD, &ip->CDPATH_init); + nv_stack(SHELLNOD, &ip->SHELL_init); + nv_stack(ENVNOD, &ip->ENV_init); + nv_stack(VISINOD, &ip->VISUAL_init); + nv_stack(EDITNOD, &ip->EDITOR_init); + nv_stack(HISTFILE, &ip->HISTFILE_init); + nv_stack(HISTSIZE, &ip->HISTSIZE_init); + nv_stack(OPTINDNOD, &ip->OPTINDEX_init); nv_stack(SECONDS, &ip->SECONDS_init.hdr); - nv_stack(L_ARGNOD, &ip->L_ARG_init.hdr); - nv_putval(SECONDS, (char*)&d, NV_INTEGER|NV_DOUBLE); + nv_stack(L_ARGNOD, &ip->L_ARG_init); + nv_putval(SECONDS, (char*)&d, NV_DOUBLE); nv_stack(RANDNOD, &ip->RAND_init.hdr); d = (shp->pid&RANDMASK); - nv_putval(RANDNOD, (char*)&d, NV_INTEGER|NV_DOUBLE); - nv_stack(LINENO, &ip->LINENO_init.hdr); + nv_putval(RANDNOD, (char*)&d, NV_DOUBLE); + nv_stack(LINENO, &ip->LINENO_init); nv_putsub(SH_MATCHNOD,(char*)0,10); nv_onattr(SH_MATCHNOD,NV_RDONLY); nv_stack(SH_MATCHNOD, &ip->SH_MATCH_init.hdr); #ifdef _hdr_locale - nv_stack(LCTYPENOD, &ip->LC_TYPE_init.hdr); - nv_stack(LCALLNOD, &ip->LC_ALL_init.hdr); - nv_stack(LCMSGNOD, &ip->LC_MSG_init.hdr); - nv_stack(LCCOLLNOD, &ip->LC_COLL_init.hdr); - nv_stack(LCNUMNOD, &ip->LC_NUM_init.hdr); - nv_stack(LANGNOD, &ip->LANG_init.hdr); + nv_stack(LCTYPENOD, &ip->LC_TYPE_init); + nv_stack(LCALLNOD, &ip->LC_ALL_init); + nv_stack(LCMSGNOD, &ip->LC_MSG_init); + nv_stack(LCCOLLNOD, &ip->LC_COLL_init); + nv_stack(LCNUMNOD, &ip->LC_NUM_init); + nv_stack(LANGNOD, &ip->LANG_init); #endif /* _hdr_locale */ (PPIDNOD)->nvalue.lp = (&shp->ppid); (TMOUTNOD)->nvalue.lp = (&shp->st.tmout); @@ -1278,12 +1345,6 @@ shp->alias_tree = inittree(shp,shtab_aliases); shp->track_tree = dtopen(&_Nvdisc,Dtset); shp->bltin_tree = inittree(shp,(const struct shtable2*)shtab_builtins); - typeset.shp = shp; - typeset.optstring = sh_opttypeset; - nv_search("typeset",shp->bltin_tree,0)->nvfun = (void*)&typeset; -#if SHOPT_BASH - nv_search("local",shp->bltin_tree,0)->nvfun = (void*)&typeset; -#endif shp->fun_tree = dtopen(&_Nvdisc,Dtoset); dtview(shp->fun_tree,shp->bltin_tree); #if SHOPT_NAMESPACE @@ -1295,6 +1356,7 @@ #endif /* SHOPT_NAMESPACE */ np = nv_mount(DOTSHNOD, "type", dtopen(&_Nvdisc,Dtoset)); nv_adddisc(DOTSHNOD, shdiscnames, (Namval_t**)0); + SH_LINENO->nvalue.ip = &shp->st.lineno; return(ip); } @@ -1313,10 +1375,14 @@ n++; np = (Namval_t*)calloc(n,sizeof(Namval_t)); if(!shp->bltin_nodes) + { shp->bltin_nodes = np; + shp->bltin_nnodes = n; + } else if(name_vals==(const struct shtable2*)shtab_builtins) shp->bltin_cmds = np; base_treep = treep = dtopen(&_Nvdisc,Dtoset); + treep->user = (void*)shp; for(tp=name_vals;*tp->sh_name;tp++,np++) { if((np->nvname = strrchr(tp->sh_name,'.')) && np->nvname!=((char*)tp->sh_name)) @@ -1330,7 +1396,11 @@ if(name_vals==(const struct shtable2*)shtab_builtins) np->nvalue.bfp = ((struct shtable3*)tp)->sh_value; else + { + if(name_vals == shtab_variables) + np->nvfun = &sh.nvfun; np->nvalue.cp = (char*)tp->sh_value; + } nv_setattr(np,tp->sh_number); if(nv_istable(np)) nv_mount(np,(const char*)0,dict=dtopen(&_Nvdisc,Dtoset)); @@ -1412,7 +1482,7 @@ } } #ifdef _ENV_H - env_delete(sh.env,e_envmarker); + env_delete(shp->env,e_envmarker); #endif if(nv_isnull(PWDNOD) || nv_isattr(PWDNOD,NV_TAGGED)) { Index: src/lib/libshell/common/sh/waitevent.c =================================================================== --- src/lib/libshell/common/sh/waitevent.c (revision 974) +++ src/lib/libshell/common/sh/waitevent.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * Index: src/lib/libshell/common/sh/string.c =================================================================== --- src/lib/libshell/common/sh/string.c (revision 974) +++ src/lib/libshell/common/sh/string.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -256,6 +256,7 @@ int len; if(mbwide() && (len=mbsize(sp))>1) { + memmove(dp, sp, len); dp += len; sp += len; continue; @@ -300,7 +301,7 @@ */ char *sh_fmtq(const char *string) { - register const char *cp = string; + register const char *cp = string, *op; register int c, state; int offset; if(!cp) @@ -343,14 +344,12 @@ #endif { #if SHOPT_MULTIBYTE - if(c>=0x200) - continue; if(c=='\'' || !iswprint(c)) #else if(c=='\'' || !isprint(c)) #endif /* SHOPT_MULTIBYTE */ state = 2; - else if(c==']' || (c!=':' && (c=sh_lexstates[ST_NORM][c]) && c!=S_EPAT)) + else if(c==']' || (c!=':' && c<=0xff && (c=sh_lexstates[ST_NORM][c]) && c!=S_EPAT)) state |=1; } if(state<2) @@ -367,9 +366,9 @@ stakwrite("$'",2); cp = string; #if SHOPT_MULTIBYTE - while(c= mbchar(cp)) + while(op = cp, c= mbchar(cp)) #else - while(c= *(unsigned char*)cp++) + while(op = cp, c= *(unsigned char*)cp++) #endif { state=1; @@ -401,19 +400,28 @@ default: #if SHOPT_MULTIBYTE if(!iswprint(c)) + { + while(op<cp) + sfprintf(staksp,"\\%.3o",*(unsigned char*)op++); + continue; + } #else if(!isprint(c)) -#endif { sfprintf(staksp,"\\%.3o",c); continue; } +#endif state=0; break; } if(state) + { stakputc('\\'); - stakputc(c); + stakputc(c); + } + else + stakwrite(op, cp-op); } stakputc('\''); } Index: src/lib/libshell/common/sh/io.c =================================================================== --- src/lib/libshell/common/sh/io.c (revision 974) +++ src/lib/libshell/common/sh/io.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * -* by AT&T Knowledge Ventures * +* by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * @@ -308,6 +308,7 @@ int orig_fd; /* original file descriptor */ int save_fd; /* saved file descriptor */ int subshell; /* saved for subshell */ + char *tname; /* name used with >; */ }; static int subexcept(Sfio_t*, int, void*, Sfdisc_t*); @@ -319,11 +320,11 @@ static ssize_t subread(Sfio_t*, void*, size_t, Sfdisc_t*); static ssize_t tee_write(Sfio_t*,const void*,size_t,Sfdisc_t*); static int io_prompt(Sfio_t*,int); -static int io_heredoc(register struct ionod*, const char*, int); +static int io_heredoc(Shell_t*,register struct ionod*, const char*, int); static void sftrack(Sfio_t*,int,int); static const Sfdisc_t eval_disc = { NULL, NULL, NULL, eval_exceptf, NULL}; static Sfdisc_t tee_disc = {NULL,tee_write,NULL,NULL,NULL}; -static Sfio_t *subopen(Sfio_t*, off_t, long); +static Sfio_t *subopen(Shell_t *,Sfio_t*, off_t, long); static const Sfdisc_t sub_disc = { subread, 0, 0, subexcept, 0 }; struct subfile @@ -376,36 +377,38 @@ /* ======== input output and file copying ======== */ -void sh_ioinit(void) +void sh_ioinit(Shell_t *shp) { register int n; filemapsize = 8; - filemap = (struct fdsave*)malloc(8*sizeof(struct fdsave)); + filemap = (struct fdsave*)malloc(filemapsize*sizeof(struct fdsave)); #if SHOPT_FASTPIPE - n = sh.lim.open_max+2; + n = shp->lim.open_max+2; #else - n = sh.lim.open_max; + n = shp->lim.open_max; #endif /* SHOPT_FASTPIPE */ - sh.fdstatus = (unsigned char*)malloc((unsigned)n); - memset((char*)sh.fdstatus,0,n); - sh.fdptrs = (int**)malloc(n*sizeof(int*)); - memset((char*)sh.fdptrs,0,n*sizeof(int*)); - sh.sftable = (Sfio_t**)malloc(n*sizeof(Sfio_t*)); - memset((char*)sh.sftable,0,n*sizeof(Sfio_t*)); - sh.sftable[0] = sfstdin; - sh.sftable[1] = sfstdout; - sh.sftable[2] = sfstderr; + shp->fdstatus = (unsigned char*)malloc((unsigned)n); + memset((char*)shp->fdstatus,0,n); + shp->fdptrs = (int**)malloc(n*sizeof(int*)); + memset((char*)shp->fdptrs,0,n*sizeof(int*)); + shp->sftable = (Sfio_t**)malloc(n*sizeof(Sfio_t*)); + memset((char*)shp->sftable,0,n*sizeof(Sfio_t*)); + shp->sftable[0] = sfstdin; + shp->sftable[1] = sfstdout; + shp->sftable[2] = sfstderr; sfnotify(sftrack); - sh_iostream(0); + sh_iostream(shp,0); /* all write steams are in the same pool and share outbuff */ - sh.outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw"); /* pool identifier */ - sh.outbuff = (char*)malloc(IOBSIZE); - sh.errbuff = (char*)malloc(IOBSIZE/4); - sfsetbuf(sfstderr,sh.errbuff,IOBSIZE/4); - sfsetbuf(sfstdout,sh.outbuff,IOBSIZE); - sfpool(sfstdout,sh.outpool,SF_WRITE); - sfpool(sfstderr,sh.outpool,SF_WRITE); + shp->outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw"); /* pool identifier */ + shp->outbuff = (char*)malloc(IOBSIZE); + shp->errbuff = (char*)malloc(IOBSIZE/4); + sfsetbuf(sfstderr,shp->errbuff,IOBSIZE/4); + sfsetbuf(sfstdout,shp->outbuff,IOBSIZE); + sfpool(sfstdout,shp->outpool,SF_WRITE); + sfpool(sfstderr,shp->outpool,SF_WRITE); sfset(sfstdout,SF_LINE,0); + sfset(sfstderr,SF_LINE,0); + sfset(sfstdin,SF_SHARE|SF_PUBLIC,1); } /* @@ -415,15 +418,15 @@ * For output streams, the buffer is set to sh.output and put into * the sh.outpool synchronization pool */ -Sfio_t *sh_iostream(register int fd) +Sfio_t *sh_iostream(Shell_t *shp, register int fd) { register Sfio_t *iop; - register int status = sh_iocheckfd(fd); + register int status = sh_iocheckfd(shp,fd); register int flags = SF_WRITE; char *bp; #if SHOPT_FASTPIPE - if(fd>=sh.lim.open_max) - return(sh.sftable[fd]); + if(fd>=shp->lim.open_max) + return(shp->sftable[fd]); #endif /* SHOPT_FASTPIPE */ if(status==IOCLOSE) { @@ -447,10 +450,10 @@ flags &= ~SF_WRITE; } else - bp = sh.outbuff; + bp = shp->outbuff; if(status&IODUP) flags |= SF_SHARE|SF_PUBLIC; - if((iop = sh.sftable[fd]) && sffileno(iop)>=0) + if((iop = shp->sftable[fd]) && sffileno(iop)>=0) sfsetbuf(iop, bp, IOBSIZE); else if(!(iop=sfnew((fd<=2?iop:0),bp,IOBSIZE,fd,flags))) return(NIL(Sfio_t*)); @@ -458,6 +461,8 @@ { Sfdisc_t *dp; sfset(iop,SF_MALLOC,1); + if(!(status&IOWRITE)) + sfset(iop,SF_IOCHECK,1); { dp = newof(0,Sfdisc_t,1,0); dp->exceptf = slowexcept; @@ -476,40 +481,40 @@ } } else - sfpool(iop,sh.outpool,SF_WRITE); - sh.sftable[fd] = iop; + sfpool(iop,shp->outpool,SF_WRITE); + shp->sftable[fd] = iop; return(iop); } /* * preserve the file descriptor or stream by moving it */ -static void io_preserve(register Sfio_t *sp, register int f2) +static void io_preserve(Shell_t* shp, register Sfio_t *sp, register int f2) { register int fd; if(sp) fd = sfsetfd(sp,10); else fd = sh_fcntl(f2,F_DUPFD,10); - if(f2==sh.infd) - sh.infd = fd; + if(f2==shp->infd) + shp->infd = fd; if(fd<0) errormsg(SH_DICT,ERROR_system(1),e_toomany); - if(sh.fdptrs[fd]=sh.fdptrs[f2]) + if(shp->fdptrs[fd]=shp->fdptrs[f2]) { if(f2==job.fd) job.fd=fd; - *sh.fdptrs[fd] = fd; - sh.fdptrs[f2] = 0; + *shp->fdptrs[fd] = fd; + shp->fdptrs[f2] = 0; } - sh.sftable[fd] = sp; - sh.fdstatus[fd] = sh.fdstatus[f2]; + shp->sftable[fd] = sp; + shp->fdstatus[fd] = shp->fdstatus[f2]; if(fcntl(f2,F_GETFD,0)&1) { fcntl(fd,F_SETFD,FD_CLOEXEC); - sh.fdstatus[fd] |= IOCLEX; + shp->fdstatus[fd] |= IOCLEX; } - sh.sftable[f2] = 0; + shp->sftable[f2] = 0; } /* @@ -518,39 +523,39 @@ * The original stream <f1> is closed. * The new file descriptor <f2> is returned; */ -int sh_iorenumber(register int f1,register int f2) +int sh_iorenumber(Shell_t *shp, register int f1,register int f2) { - register Sfio_t *sp = sh.sftable[f2]; + register Sfio_t *sp = shp->sftable[f2]; if(f1!=f2) { /* see whether file descriptor is in use */ if(sh_inuse(f2) || (f2>2 && sp)) { - if(!(sh.inuse_bits&(1<<f2))) - io_preserve(sp,f2); + if(!(shp->inuse_bits&(1<<f2))) + io_preserve(shp,sp,f2); sp = 0; } else if(f2==0) - sh.st.ioset = 1; + shp->st.ioset = 1; sh_close(f2); if(f2<=2 && sp) { - register Sfio_t *spnew = sh_iostream(f1); - sh.fdstatus[f2] = (sh.fdstatus[f1]&~IOCLEX); + register Sfio_t *spnew = sh_iostream(shp,f1); + shp->fdstatus[f2] = (shp->fdstatus[f1]&~IOCLEX); sfsetfd(spnew,f2); sfswap(spnew,sp); sfset(sp,SF_SHARE|SF_PUBLIC,1); } else { - sh.fdstatus[f2] = (sh.fdstatus[f1]&~IOCLEX); + shp->fdstatus[f2] = (shp->fdstatus[f1]&~IOCLEX); if((f2 = sh_fcntl(f1,F_DUPFD, f2)) < 0) errormsg(SH_DICT,ERROR_system(1),e_file+4); else if(f2 <= 2) - sh_iostream(f2); + sh_iostream(shp,f2); } if(sp) - sh.sftable[f1] = 0; + shp->sftable[f1] = 0; sh_close(f1); } return(f2); @@ -603,6 +608,7 @@ */ int sh_open(register const char *path, int flags, ...) { + Shell_t *shp = &sh; register int fd = -1; mode_t mode; char *e; @@ -658,7 +664,7 @@ } if (fd >= 0) { - if((mode=sh_iocheckfd(fd))==IOCLOSE) + if((mode=sh_iocheckfd(shp,fd))==IOCLOSE) return(-1); flags &= O_ACCMODE; if(!(mode&IOWRITE) && ((flags==O_WRONLY) || (flags==O_RDWR))) @@ -748,13 +754,13 @@ return(cp-buff); } -static int io_patseek(regex_t *rp, Sfio_t* sp, int flags) +static int io_patseek(Shell_t *shp, regex_t *rp, Sfio_t* sp, int flags) { char *cp, *match; - int r, fd=sffileno(sp), close_exec = sh.fdstatus[fd]&IOCLEX; + int r, fd=sffileno(sp), close_exec = shp->fdstatus[fd]&IOCLEX; int was_share,s=(PIPE_BUF>SF_BUFSIZE?SF_BUFSIZE:PIPE_BUF); size_t n,m; - sh.fdstatus[sffileno(sp)] |= IOCLEX; + shp->fdstatus[sffileno(sp)] |= IOCLEX; if(fd==0) was_share = sfset(sp,SF_SHARE,1); while((cp=sfreserve(sp, -s, SF_LOCKR)) || (cp=sfreserve(sp,SF_UNBOUND, SF_LOCKR))) @@ -779,20 +785,20 @@ break; } if(!close_exec) - sh.fdstatus[sffileno(sp)] &= ~IOCLEX; + shp->fdstatus[sffileno(sp)] &= ~IOCLEX; if(fd==0 && !(was_share&SF_SHARE)) sfset(sp, SF_SHARE,0); return(0); } -static Sfoff_t file_offset(int fn, char *fname) +static Sfoff_t file_offset(Shell_t *shp, int fn, char *fname) { - Sfio_t *sp = sh.sftable[fn]; + Sfio_t *sp = shp->sftable[fn]; char *cp; Sfoff_t off; struct Eof endf; - Namval_t *mp = nv_open("EOF",sh.var_tree,0); - Namval_t *pp = nv_open("CUR",sh.var_tree,0); + Namval_t *mp = nv_open("EOF",shp->var_tree,0); + Namval_t *pp = nv_open("CUR",shp->var_tree,0); memset(&endf,0,sizeof(struct Eof)); endf.fd = fn; endf.hdr.disc = &EOF_disc; @@ -823,6 +829,48 @@ pv[0] = pv[1] = -1; } +static char *io_usename(char *name, int *perm, int mode) +{ + struct stat statb; + char *tname, *sp, *ep; + int fd,len,n=0; + if(mode==0) + { + if((fd = sh_open(name,O_RDONLY,0)) > 0) + { + if(fstat(fd,&statb) < 0) + return(0); + if(!S_ISREG(statb.st_mode)) + return(0); + *perm = statb.st_mode&(RW_ALL|(S_IXUSR|S_IXGRP|S_IXOTH)); + } + else if(fd < 0 && errno!=ENOENT) + return(0); + } + tname = sp = (char*)stakalloc((len=strlen(name)) + 5); + if(ep = strrchr(name,'/')) + { + memcpy(sp,name,n=++ep-name); + len -=n; + sp += n; + } + else + ep = name; + *sp++ = '.'; + memcpy(sp,ep,len); + strcpy(sp+len,".tmp"); + switch(mode) + { + case 1: + rename(tname,name); + break; + case 2: + unlink(tname); + break; + } + return(tname); +} + /* * I/O redirection * flag = 0 if files are to be restored @@ -830,7 +878,7 @@ * flag = 3 when called from $( < ...), just open file and return * flag = SH_SHOWME for trace only */ -int sh_redirect(struct ionod *iop, int flag) +int sh_redirect(Shell_t *shp,struct ionod *iop, int flag) { Sfoff_t off; register char *fname; @@ -839,8 +887,8 @@ int o_mode; /* mode flag for open */ static char io_op[7]; /* used for -x trace info */ int clexec=0, fn, traceon; - int r, indx = sh.topfd; - char *after="", *trace = sh.st.trap[SH_DEBUGTRAP]; + int r, indx = shp->topfd, perm= -1; + char *tname=0, *after="", *trace = shp->st.trap[SH_DEBUGTRAP]; Namval_t *np=0; if(flag==2) clexec = 1; @@ -850,6 +898,8 @@ { iof=iop->iofile; fn = (iof&IOUFD); + if(fn==1 && flag==2 && shp->subshell) + sh_subfork(); io_op[0] = '0'+(iof&IOUFD); if(iof&IOPUT) { @@ -873,19 +923,20 @@ memset(ap, 0, ARGVAL); ap->argflag = ARG_MAC; strcpy(ap->argval,iop->ioname); - fname=sh_macpat(ap,(iof&IOARITH)?ARG_ARITH:ARG_EXP); + fname=sh_macpat(shp,ap,(iof&IOARITH)?ARG_ARITH:ARG_EXP); } else - fname=sh_mactrim(fname,(!sh_isoption(SH_NOGLOB)&&sh_isoption(SH_INTERACTIVE))?2:0); + fname=sh_mactrim(shp,fname,(!sh_isoption(SH_NOGLOB)&&sh_isoption(SH_INTERACTIVE))?2:0); } errno=0; + np = 0; if(iop->iovname) { - np = nv_open(iop->iovname,sh.var_tree,NV_NOASSIGN|NV_VARNAME); + np = nv_open(iop->iovname,shp->var_tree,NV_NOASSIGN|NV_VARNAME); if(nv_isattr(np,NV_RDONLY)) errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np)); io_op[0] = '}'; - if((iof&IOMOV) && *fname=='-') + if((iof&IOLSEEK) || ((iof&IOMOV) && *fname=='-')) fn = nv_getnum(np); } if(iof&IOLSEEK) @@ -906,7 +957,7 @@ { if(traceon) sfputr(sfstderr,io_op,'<'); - fd = io_heredoc(iop,fname,traceon); + fd = io_heredoc(shp,iop,fname,traceon); if(traceon && (flag==SH_SHOWME)) sh_close(fd); fname = 0; @@ -929,13 +980,13 @@ message = e_file; goto fail; } - if(sh.subshell && dupfd==1) + if(shp->subshell && dupfd==1) { sh_subtmpfile(); dupfd = sffileno(sfstdout); } - else if(sh.sftable[dupfd]) - sfsync(sh.sftable[dupfd]); + else if(shp->sftable[dupfd]) + sfsync(shp->sftable[dupfd]); } else if(fd=='-' && fname[1]==0) { @@ -945,9 +996,9 @@ else if(fd=='p' && fname[1]==0) { if(iof&IOPUT) - dupfd = sh.coutpipe; + dupfd = shp->coutpipe; else - dupfd = sh.cpipe[0]; + dupfd = shp->cpipe[0]; if(flag) toclose = dupfd; } @@ -960,16 +1011,16 @@ goto traceit; if((fd=sh_fcntl(dupfd,F_DUPFD,3))<0) goto fail; - sh_iocheckfd(dupfd); - sh.fdstatus[fd] = (sh.fdstatus[dupfd]&~IOCLEX); - if(toclose<0 && sh.fdstatus[fd]&IOREAD) - sh.fdstatus[fd] |= IODUP; - else if(dupfd==sh.cpipe[0]) - sh_pclose(sh.cpipe); + sh_iocheckfd(shp,dupfd); + shp->fdstatus[fd] = (shp->fdstatus[dupfd]&~IOCLEX); + if(toclose<0 && shp->fdstatus[fd]&IOREAD) + shp->fdstatus[fd] |= IODUP; + else if(dupfd==shp->cpipe[0]) + sh_pclose(shp->cpipe); else if(toclose>=0) { if(flag==0) - sh_iosave(toclose,indx); /* save file descriptor */ + sh_iosave(shp,toclose,indx,(char*)0); /* save file descriptor */ sh_close(toclose); } } @@ -996,6 +1047,12 @@ io_op[2] = '>'; o_mode |= O_APPEND; } + else if((iof&IOREWRITE) && (flag==0 || flag==1 || sh_subsavefd(fn))) + { + io_op[2] = ';'; + o_mode |= O_TRUNC; + tname = io_usename(fname,&perm,0); + } else { o_mode |= O_TRUNC; @@ -1008,7 +1065,7 @@ { #if SHOPT_FS_3D if(S_ISREG(sb.st_mode)&& - (!sh.lim.fs3d || iview(&sb)==0)) + (!shp->lim.fs3d || iview(&sb)==0)) #else if(S_ISREG(sb.st_mode)) #endif /* SHOPT_FS_3D */ @@ -1024,8 +1081,14 @@ openit: if(flag!=SH_SHOWME) { - if((fd=sh_open(fname,o_mode,RW_ALL)) <0) + if((fd=sh_open(tname?tname:fname,o_mode,RW_ALL)) <0) errormsg(SH_DICT,ERROR_system(1),((o_mode&O_CREAT)?e_create:e_open),fname); + if(perm>0) +#if _lib_fchmod + fchmod(fd,perm); +#else + chmod(tname,perm); +#endif } } traceit: @@ -1054,14 +1117,14 @@ } else av +=3; - sh_debug(trace,(char*)0,(char*)0,av,ARG_NOGLOB); + sh_debug(shp,trace,(char*)0,(char*)0,av,ARG_NOGLOB); } if(iof&IOLSEEK) { - Sfio_t *sp = sh.sftable[fn]; - r = sh.fdstatus[fn]; + Sfio_t *sp = shp->sftable[fn]; + r = shp->fdstatus[fn]; if(!(r&(IOSEEK|IONOSEEK))) - r = sh_iocheckfd(fn); + r = sh_iocheckfd(shp,fn); sfsprintf(io_op,sizeof(io_op),"%d\0",fn); if(r==IOCLOSE) { @@ -1078,7 +1141,7 @@ goto fail; } message = e_badseek; - if((off = file_offset(fn,fname))<0) + if((off = file_offset(shp,fn,fname))<0) goto fail; if(sp) r=sfseek(sp, off, SEEK_SET); @@ -1100,8 +1163,8 @@ goto fail; } if(!sp) - sp = sh_iostream(fn); - r=io_patseek(rp,sp,iof); + sp = sh_iostream(shp,fn); + r=io_patseek(shp,rp,sp,iof); if(sp && flag==3) { /* close stream but not fn */ @@ -1117,7 +1180,7 @@ } if(!np) { - if(flag==0) + if(flag==0 || tname) { if(fd==fn) { @@ -1127,17 +1190,17 @@ sh_close(fn); } } - sh_iosave(fn,indx); + sh_iosave(shp,fn,indx,tname?fname:0); } else if(sh_subsavefd(fn)) - sh_iosave(fn,indx|IOSUBSHELL); + sh_iosave(shp,fn,indx|IOSUBSHELL,tname?fname:0); } if(fd<0) { - if(sh_inuse(fn) || fn==sh.infd) + if(sh_inuse(fn) || fn==shp->infd) { - if(fn>9 || !(sh.inuse_bits&(1<<fn))) - io_preserve(sh.sftable[fn],fn); + if(fn>9 || !(shp->inuse_bits&(1<<fn))) + io_preserve(shp,shp->sftable[fn],fn); } sh_close(fn); } @@ -1153,7 +1216,7 @@ { if((fn=fcntl(fd,F_DUPFD,10)) < 0) goto fail; - sh.fdstatus[fn] = sh.fdstatus[fd]; + shp->fdstatus[fn] = shp->fdstatus[fd]; sh_close(fd); fd = fn; } @@ -1161,19 +1224,19 @@ nv_onattr(np,NV_INT32); v = fn; nv_putval(np,(char*)&v, NV_INT32); - sh_iocheckfd(fd); + sh_iocheckfd(shp,fd); } else { - fd = sh_iorenumber(sh_iomovefd(fd),fn); + fd = sh_iorenumber(shp,sh_iomovefd(fd),fn); if(fn>2 && fn<10) - sh.inuse_bits |= (1<<fn); + shp->inuse_bits |= (1<<fn); } } if(fd >2 && clexec) { fcntl(fd,F_SETFD,FD_CLOEXEC); - sh.fdstatus[fd] |= IOCLEX; + shp->fdstatus[fd] |= IOCLEX; } } else @@ -1188,11 +1251,11 @@ /* * Create a tmp file for the here-document */ -static int io_heredoc(register struct ionod *iop, const char *name, int traceon) +static int io_heredoc(Shell_t *shp,register struct ionod *iop, const char *name, int traceon) { register Sfio_t *infile = 0, *outfile; register int fd; - if(!(iop->iofile&IOSTRG) && (!sh.heredocs || iop->iosize==0)) + if(!(iop->iofile&IOSTRG) && (!shp->heredocs || iop->iosize==0)) return(sh_open(e_devnull,O_RDONLY)); /* create an unnamed temporary file */ if(!(outfile=sftmp(0))) @@ -1205,7 +1268,7 @@ } else { - infile = subopen(sh.heredocs,iop->iooffset,iop->iosize); + infile = subopen(shp,shp->heredocs,iop->iooffset,iop->iosize); if(traceon) { char *cp = sh_fmtq(iop->iodelim); @@ -1221,9 +1284,9 @@ } else { - char *lastpath = sh.lastpath; - sh_machere(infile,outfile,iop->ioname); - sh.lastpath = lastpath; + char *lastpath = shp->lastpath; + sh_machere(shp,infile,outfile,iop->ioname); + shp->lastpath = lastpath; if(infile) sfclose(infile); } @@ -1235,7 +1298,7 @@ if(traceon && !(iop->iofile&IOSTRG)) sfputr(sfstderr,iop->ioname,'\n'); lseek(fd,(off_t)0,SEEK_SET); - sh.fdstatus[fd] = IOREAD; + shp->fdstatus[fd] = IOREAD; return(fd); } @@ -1256,28 +1319,43 @@ * if <origfd> < 0, then -origfd is saved, but not duped so that it * will be closed with sh_iorestore. */ -void sh_iosave(register int origfd, int oldtop) +void sh_iosave(Shell_t *shp, register int origfd, int oldtop, char *name) { /*@ - assume oldtop>=0 && oldtop<sh.lim.open_max; + assume oldtop>=0 && oldtop<shp->lim.open_max; @*/ register int savefd; int flag = (oldtop&IOSUBSHELL); oldtop &= ~IOSUBSHELL; /* see if already saved, only save once */ - for(savefd=sh.topfd; --savefd>=oldtop; ) + for(savefd=shp->topfd; --savefd>=oldtop; ) { if(filemap[savefd].orig_fd == origfd) return; } /* make sure table is large enough */ - if(sh.topfd >= filemapsize) + if(shp->topfd >= filemapsize) { + char *cp, *oldptr = (char*)filemap; + char *oldend = (char*)&filemap[filemapsize]; + long moved; filemapsize += 8; if(!(filemap = (struct fdsave*)realloc(filemap,filemapsize*sizeof(struct fdsave)))) errormsg(SH_DICT,ERROR_exit(4),e_nospace); - + if(moved = (char*)filemap - oldptr) + { +#if SHOPT_FASTPIPE + for(savefd=shp->lim.open_max+2; --savefd>=0; ) +#else + for(savefd=shp->lim.open_max; --savefd>=0; ) +#endif /* SHOPT_FASTPIPE */ + { + cp = (char*)shp->fdptrs[savefd]; + if(cp >= oldptr && cp < oldend) + shp->fdptrs[savefd] = (int*)(oldptr+moved); + } + } } #if SHOPT_DEVFD if(origfd <0) @@ -1291,60 +1369,61 @@ if((savefd = sh_fcntl(origfd, F_DUPFD, 10)) < 0 && errno!=EBADF) errormsg(SH_DICT,ERROR_system(1),e_toomany); } - filemap[sh.topfd].subshell = flag; - filemap[sh.topfd].orig_fd = origfd; - filemap[sh.topfd++].save_fd = savefd; + filemap[shp->topfd].tname = name; + filemap[shp->topfd].subshell = flag; + filemap[shp->topfd].orig_fd = origfd; + filemap[shp->topfd++].save_fd = savefd; if(savefd >=0) { - register Sfio_t* sp = sh.sftable[origfd]; + register Sfio_t* sp = shp->sftable[origfd]; /* make saved file close-on-exec */ sh_fcntl(savefd,F_SETFD,FD_CLOEXEC); if(origfd==job.fd) job.fd = savefd; - sh.fdstatus[savefd] = sh.fdstatus[origfd]; - sh.fdptrs[savefd] = &filemap[sh.topfd-1].save_fd; - if(!(sh.sftable[savefd]=sp)) + shp->fdstatus[savefd] = shp->fdstatus[origfd]; + shp->fdptrs[savefd] = &filemap[shp->topfd-1].save_fd; + if(!(shp->sftable[savefd]=sp)) return; sfsync(sp); if(origfd <=2) { /* copy standard stream to new stream */ sp = sfswap(sp,NIL(Sfio_t*)); - sh.sftable[savefd] = sp; + shp->sftable[savefd] = sp; } else - sh.sftable[origfd] = 0; + shp->sftable[origfd] = 0; } } /* * close all saved file descriptors */ -void sh_iounsave(void) +void sh_iounsave(Shell_t* shp) { register int fd, savefd, newfd; - for(newfd=fd=0; fd < sh.topfd; fd++) + for(newfd=fd=0; fd < shp->topfd; fd++) { if((savefd = filemap[fd].save_fd)< 0) filemap[newfd++] = filemap[fd]; else { - sh.sftable[savefd] = 0; + shp->sftable[savefd] = 0; sh_close(savefd); } } - sh.topfd = newfd; + shp->topfd = newfd; } /* * restore saved file descriptors from <last> on */ -void sh_iorestore(int last, int jmpval) +void sh_iorestore(Shell_t *shp, int last, int jmpval) { register int origfd, savefd, fd; int flag = (last&IOSUBSHELL); last &= ~IOSUBSHELL; - for (fd = sh.topfd - 1; fd >= last; fd--) + for (fd = shp->topfd - 1; fd >= last; fd--) { if(!flag && filemap[fd].subshell) continue; @@ -1352,47 +1431,49 @@ { if ((savefd = filemap[fd].save_fd) >= 0) { - sh.sftable[savefd] = 0; + shp->sftable[savefd] = 0; sh_close(savefd); } continue; } origfd = filemap[fd].orig_fd; + if(filemap[fd].tname) + io_usename(filemap[fd].tname,(int*)0,shp->exitval?2:1); sh_close(origfd); if ((savefd = filemap[fd].save_fd) >= 0) { sh_fcntl(savefd, F_DUPFD, origfd); if(savefd==job.fd) job.fd=origfd; - sh.fdstatus[origfd] = sh.fdstatus[savefd]; + shp->fdstatus[origfd] = shp->fdstatus[savefd]; /* turn off close-on-exec if flag if necessary */ - if(sh.fdstatus[origfd]&IOCLEX) + if(shp->fdstatus[origfd]&IOCLEX) fcntl(origfd,F_SETFD,FD_CLOEXEC); if(origfd<=2) { - sfswap(sh.sftable[savefd],sh.sftable[origfd]); + sfswap(shp->sftable[savefd],shp->sftable[origfd]); if(origfd==0) - sh.st.ioset = 0; + shp->st.ioset = 0; } else - sh.sftable[origfd] = sh.sftable[savefd]; - sh.sftable[savefd] = 0; + shp->sftable[origfd] = shp->sftable[savefd]; + shp->sftable[savefd] = 0; sh_close(savefd); } else - sh.fdstatus[origfd] = IOCLOSE; + shp->fdstatus[origfd] = IOCLOSE; } if(!flag) { /* keep file descriptors for subshell restore */ - for (fd = last ; fd < sh.topfd; fd++) + for (fd = last ; fd < shp->topfd; fd++) { if(filemap[fd].subshell) filemap[last++] = filemap[fd]; } } - if(last < sh.topfd) - sh.topfd = last; + if(last < shp->topfd) + shp->topfd = last; } /* @@ -1402,10 +1483,11 @@ */ int sh_ioaccess(int fd,register int mode) { + Shell_t *shp = &sh; register int flags; if(mode==X_OK) return(-1); - if((flags=sh_iocheckfd(fd))!=IOCLOSE) + if((flags=sh_iocheckfd(shp,fd))!=IOCLOSE) { if(mode==F_OK) return(0); @@ -1455,7 +1537,12 @@ if(errno!=EINTR) return(0); n=1; + sh_onstate(SH_TTYWAIT); } + else + n = 0; + if(sh.bltinfun && sh.bltindata.sigset) + return(-1); errno = 0; if(sh.trapnote&SH_SIGSET) { @@ -1495,6 +1582,8 @@ { int fd = sffileno(iop); NOT_USED(handle); + if(job.waitsafe && job.savesig) + job_reap(job.savesig); if(sh.trapnote) { errno = EINTR; @@ -1502,10 +1591,12 @@ } if(sh_isstate(SH_INTERACTIVE) && io_prompt(iop,sh.nextprompt)<0 && errno==EIO) return(0); + sh_onstate(SH_TTYWAIT); if(!(sh.fdstatus[sffileno(iop)]&IOCLEX) && (sfset(iop,0,0)&SF_SHARE)) size = ed_read(sh.ed_context, fd, (char*)buff, size,0); else size = sfrd(iop,buff,size,handle); + sh_offstate(SH_TTYWAIT); return(size); } /* @@ -1594,7 +1685,7 @@ * check and return the attributes for a file descriptor */ -int sh_iocheckfd(register int fd) +int sh_iocheckfd(Shell_t *shp, register int fd) { register int flags, n; if((n=sh.fdstatus[fd])&IOCLOSE) @@ -1661,6 +1752,7 @@ static int io_prompt(Sfio_t *iop,register int flag) { + Shell_t *shp = &sh; register char *cp; char buff[1]; char *endprompt; @@ -1691,7 +1783,7 @@ ioctl(sffileno(sfstderr),TIOCLBIC,&mode); } #endif /* TIOCLBIC */ - cp = sh_mactry(nv_getval(nv_scoped(PS1NOD))); + cp = sh_mactry(shp,nv_getval(sh_scoped(shp,PS1NOD))); for(;c= *cp;cp++) { if(c==HIST_CHAR) @@ -1711,10 +1803,10 @@ goto done; } case 2: - cp = nv_getval(nv_scoped(PS2NOD)); + cp = nv_getval(sh_scoped(shp,PS2NOD)); break; case 3: - cp = nv_getval(nv_scoped(PS3NOD)); + cp = nv_getval(sh_scoped(shp,PS3NOD)); break; default: goto done; @@ -1747,6 +1839,7 @@ */ static void sftrack(Sfio_t* sp,int flag, int newfd) { + Shell_t *shp = &sh; register int fd = sffileno(sp); register struct checkpt *pp; register int mode; @@ -1772,12 +1865,12 @@ return; } #endif - if((unsigned)fd >= sh.lim.open_max) + if((unsigned)fd >= shp->lim.open_max) return; if(sh_isstate(SH_NOTRACK)) return; mode = sfset(sp,0,0); - if(sp==sh.heredocs && fd < 10 && flag==SF_NEW) + if(sp==shp->heredocs && fd < 10 && flag==SF_NEW) { fd = sfsetfd(sp,10); fcntl(fd,F_SETFD,FD_CLOEXEC); @@ -1786,23 +1879,23 @@ return; if(flag==SF_NEW) { - if(!sh.sftable[fd] && sh.fdstatus[fd]==IOCLOSE) + if(!shp->sftable[fd] && shp->fdstatus[fd]==IOCLOSE) { - sh.sftable[fd] = sp; + shp->sftable[fd] = sp; flag = (mode&SF_WRITE)?IOWRITE:0; if(mode&SF_READ) flag |= IOREAD; - sh.fdstatus[fd] = flag; + shp->fdstatus[fd] = flag; #if 0 if(flag==IOWRITE) - sfpool(sp,sh.outpool,SF_WRITE); + sfpool(sp,shp->outpool,SF_WRITE); else #else if(flag!=IOWRITE) #endif - sh_iostream(fd); + sh_iostream(shp,fd); } - if((pp=(struct checkpt*)sh.jmplist) && pp->mode==SH_JMPCMD) + if((pp=(struct checkpt*)shp->jmplist) && pp->mode==SH_JMPCMD) { struct openlist *item; /* @@ -1820,9 +1913,9 @@ } else if(flag==SF_CLOSING || (flag==SF_SETFD && newfd<=2)) { - sh.sftable[fd] = 0; - sh.fdstatus[fd]=IOCLOSE; - if(pp=(struct checkpt*)sh.jmplist) + shp->sftable[fd] = 0; + shp->fdstatus[fd]=IOCLOSE; + if(pp=(struct checkpt*)shp->jmplist) { struct openlist *item; for(item=pp->olist; item; item=item->next) @@ -1916,7 +2009,7 @@ * The stream can be read with the normal stream operations */ -static Sfio_t *subopen(Sfio_t* sp, off_t offset, long size) +static Sfio_t *subopen(Shell_t *shp,Sfio_t* sp, off_t offset, long size) { register struct subfile *disp; if(sfseek(sp,offset,SEEK_SET) <0) @@ -1927,7 +2020,7 @@ disp->oldsp = sp; disp->offset = offset; disp->size = disp->left = size; - sp = sfnew(NIL(Sfio_t*),(char*)(disp+1),IOBSIZE,sh.lim.open_max,SF_READ); + sp = sfnew(NIL(Sfio_t*),(char*)(disp+1),IOBSIZE,shp->lim.open_max,SF_READ); sfdisc(sp,&disp->disc); return(sp); } @@ -1982,11 +2075,12 @@ */ void sh_menu(Sfio_t *outfile,int argn,char *argv[]) { + Shell_t *shp = &sh; register int i,j; register char **arg; int nrow, ncol=1, ndigits=1; int fldsize, wsize = ed_window(); - char *cp = nv_getval(nv_scoped(LINES)); + char *cp = nv_getval(sh_scoped(shp,LINES)); nrow = (cp?1+2*((int)strtol(cp, (char**)0, 10)/3):NROW); for(i=argn;i >= 10;i /= 10) ndigits++; @@ -2132,6 +2226,7 @@ Sfio_t *sh_iogetiop(int fd, int mode) { + Shell_t *shp = &sh; int n; Sfio_t *iop=0; if(mode!=SF_READ && mode!=SF_WRITE) @@ -2142,18 +2237,18 @@ switch(fd) { case SH_IOHISTFILE: - if(!sh_histinit()) + if(!sh_histinit((void*)shp)) return(iop); - fd = sffileno(sh.hist_ptr->histfp); + fd = sffileno(shp->hist_ptr->histfp); break; case SH_IOCOPROCESS: if(mode==SF_WRITE) - fd = sh.coutpipe; + fd = shp->coutpipe; else - fd = sh.cpipe[0]; + fd = shp->cpipe[0]; break; default: - if(fd<0 || fd >= sh.lim.open_max) + if(fd<0 || fd >= shp->lim.open_max) fd = -1; } if(fd<0) @@ -2161,14 +2256,14 @@ errno = EBADF; return(iop); } - if(!(n=sh.fdstatus[fd])) - n = sh_iocheckfd(fd); + if(!(n=shp->fdstatus[fd])) + n = sh_iocheckfd(shp,fd); if(mode==SF_WRITE && !(n&IOWRITE)) return(iop); if(mode==SF_READ && !(n&IOREAD)) return(iop); - if(!(iop = sh.sftable[fd])) - iop=sh_iostream(fd); + if(!(iop = shp->sftable[fd])) + iop=sh_iostream(shp,fd); return(iop); } @@ -2184,9 +2279,10 @@ Sfio_t *sh_fd2sfio(int fd) { + Shell_t *shp = &sh; register int status; Sfio_t *sp = sh.sftable[fd]; - if(!sp && (status = sh_iocheckfd(fd))!=IOCLOSE) + if(!sp && (status = sh_iocheckfd(shp,fd))!=IOCLOSE) { register int flags=0; if(status&IOREAD) @@ -2201,6 +2297,7 @@ Sfio_t *sh_pathopen(const char *cp) { + Shell_t *shp = &sh; int n; #ifdef PATH_BFPATH if((n=path_open(cp,path_get(cp))) < 0) @@ -2211,5 +2308,5 @@ #endif if(n < 0) errormsg(SH_DICT,ERROR_system(1),e_open,cp); - return(sh_iostream(n)); + return(sh_iostream(shp,n)); } Index: src/lib/libshell/common/sh/fault.c =================================================================== --- src/lib/libshell/common/sh/fault.c (revision 974) +++ src/lib/libshell/common/sh/fault.c (revision 1122) @@ -1,10 +1,10 @@ /*********************************************************************** * * * This software is part of the ast package * -* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* Copyright (c) 1982-2008 AT&T Intellectual Pr