xref: /titanic_44/usr/src/lib/libshell/common/scripts/numtree1.sh (revision f169c0eae91b2ee787cf8d6dcf8edd9159d4c9e2)
1#!/usr/bin/ksh93
2
3#
4# CDDL HEADER START
5#
6# The contents of this file are subject to the terms of the
7# Common Development and Distribution License (the "License").
8# You may not use this file except in compliance with the License.
9#
10# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11# or http://www.opensolaris.org/os/licensing.
12# See the License for the specific language governing permissions
13# and limitations under the License.
14#
15# When distributing Covered Code, include this CDDL HEADER in each
16# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17# If applicable, add the following below this CDDL HEADER, with the
18# fields enclosed by brackets "[]" replaced with your own identifying
19# information: Portions Copyright [yyyy] [name of copyright owner]
20#
21# CDDL HEADER END
22#
23
24#
25# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26#
27
28#
29# numtree1 - basic compound variable tree demo+benchmark
30#
31
32# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
33export PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
34
35# Make sure all math stuff runs in the "C" locale to avoid problems
36# with alternative # radix point representations (e.g. ',' instead of
37# '.' in de_DE.*-locales). This needs to be set _before_ any
38# floating-point constants are defined in this script).
39if [[ "${LC_ALL}" != "" ]] ; then
40    export \
41        LC_MONETARY="${LC_ALL}" \
42        LC_MESSAGES="${LC_ALL}" \
43        LC_COLLATE="${LC_ALL}" \
44        LC_CTYPE="${LC_ALL}"
45        unset LC_ALL
46fi
47export LC_NUMERIC=C
48
49function fatal_error
50{
51	print -u2 "${progname}: $*"
52	exit 1
53}
54
55function add_number_to_tree
56{
57	typeset treename=$1
58	integer num=$2
59	integer i
60	typeset nodepath # full name of compound variable
61	integer -a pe # path elements
62	integer len
63	typeset revnums="$(rev <<<"${num}")"
64
65	# first built an array containing the names of each path element
66	# (e.g. "135" results in an array containing "( 1 3 5 )")
67	# 10#<number> is used to prevent leading zeros being interpreted
68	# as octals
69	for (( len=${#revnums} , i=$( printf "10#%s\n" "${revnums}" ) ; len > 0 ; len--, i=i/10 )) ; do
70		pe+=( $((i % 10)) )
71	done
72
73	# walk path described via the "pe" array and build nodes if
74	# there aren't any nodes yet
75	nodepath="${treename}"
76	for (( i=0 ; i < ${#pe[@]} ; i++ )) ; do
77		nameref x="${nodepath}"
78
79		# [[ -v ]] does not work for arrays because [[ -v ar ]]
80		# is equal to [[ -v ar[0] ]]. In this case we can
81		# use the output of typeset +p x.nodes
82		[[ "${ typeset +p x.nodes ;}" == "" ]] && compound -a x.nodes
83
84		nodepath+=".nodes[${pe[i]}]"
85	done
86
87	# insert element (leaf)
88	nameref node="${nodepath}"
89	[[ "${ typeset +p node.elements ;}" == "" ]] && integer -a node.elements
90	node.elements+=( ${num} )
91
92	# DEBUG only
93	[[ "${!node.elements[*]}" != ""                ]] || fatal_error "assertion $LINENO FAILED"
94	[[ "${ typeset +p node.elements ;}" == *-a*    ]] || fatal_error "assertion $LINENO FAILED"
95	[[ "${ typeset +p node.elements ;}" == *-i*    ]] || fatal_error "assertion $LINENO FAILED"
96	[[ -v node                                     ]] || fatal_error "assertion $LINENO FAILED"
97	[[ -R node                                     ]] || fatal_error "assertion $LINENO FAILED"
98	[[ "${ typeset +p ${!node} ;}" == *-C*         ]] || fatal_error "assertion $LINENO FAILED"
99	[[ "${!x.nodes[*]}" != ""                      ]] || fatal_error "assertion $LINENO FAILED"
100	[[ "${ typeset +p x.nodes ;}" == *-a*          ]] || fatal_error "assertion $LINENO FAILED"
101	[[ "${ typeset +p x.nodes ;}" == *-C*          ]] || fatal_error "assertion $LINENO FAILED"
102
103	return 0
104}
105
106
107# floating-point version of "seq"
108function floatseq
109{
110	float i
111	float arg1=$1
112	float arg2=$2
113	float arg3=$3
114
115	case $# in
116		1)
117			for (( i=1. ; i <= arg1 ; i=i+1. )) ; do
118				printf "%a\n" i
119			done
120			;;
121		2)
122			for (( i=arg1 ; i <= arg2 ; i=i+1. )) ; do
123				printf "%a\n" i
124			done
125			;;
126		3)
127			for (( i=arg1 ; i <= arg3 ; i+=arg2 )) ; do
128				printf "%a\n" i
129			done
130			;;
131		*)
132			print -u2 -f "%s: Illegal number of arguments %d\n" "$0" $#
133			return 1
134			;;
135	esac
136
137	return 0
138}
139
140
141function usage
142{
143	OPTIND=0
144	getopts -a "${progname}" "${numtree1_usage}" OPT '-?'
145	exit 2
146}
147
148# main
149builtin basename
150builtin rev
151
152set -o noglob
153set -o errexit
154set -o nounset
155
156compound base
157
158compound bench=(
159	float start
160	float stop
161)
162
163integer i
164
165typeset progname="${ basename "${0}" ; }"
166
167typeset -r numtree1_usage=$'+
168[-?\n@(#)\$Id: numtree1 (Roland Mainz) 2010-03-27 \$\n]
169[-author?Roland Mainz <roland.mainz@nrubsig.org>]
170[+NAME?numtree1 - generate sorted variable tree containing numbers]
171[+DESCRIPTION?\bnumtree1\b is a simple variable tree generator
172	sorts a given set of numbers into a ksh compound variable tree).
173	the application supports two different modes: \'seq\' takes
174	1-3 arguments to specify the set of numbers via seq(1) and
175	\'stdin\' reads the numbers from stdin (one per line)]
176
177method [ arguments ]
178
179[+SEE ALSO?\bksh93\b(1), \bseq\b(1)]
180'
181
182while getopts -a "${progname}" "${numtree1_usage}" OPT ; do
183#	printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
184	case ${OPT} in
185		*) usage ;;
186	esac
187done
188shift $((OPTIND-1))
189
190# prechecks
191(( $# > 0 )) || usage
192
193cmd=$1
194shift
195
196# Read numbers from stdin outside benchmark loop
197if [[ ${cmd} == 'stdin' ]] ; then
198	stdin_numbers="$( cat /dev/stdin )" || fatal_error "stdin read error"
199fi
200
201(( bench.start=SECONDS ))
202
203case ${cmd} in
204	"seq")
205		for i in ${ floatseq "$@" ; } ; do
206			add_number_to_tree base "${i}"
207		done
208		;;
209	"stdin")
210		for i in ${stdin_numbers} ; do
211			add_number_to_tree base "${i}"
212		done
213		;;
214	"demo1")
215		for i in 1 32 33 34 34 38 90 ; do
216			add_number_to_tree base "${i}"
217		done
218		;;
219	"demo2")
220		for (( i=1000000000 ; i < 1000000000+10 ; i++ )) ; do
221			add_number_to_tree base "$i"
222		done
223		;;
224	*)
225		fatal_error "Invalid command ${cmd}."
226		;;
227esac
228
229(( bench.stop=SECONDS ))
230
231print -u2 -f "# time used: %f\n" $((bench.stop - bench.start))
232
233# print tree
234print -v base
235
236exit 0
237# EOF.
238