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