xref: /titanic_50/usr/src/lib/libshell/common/scripts/shcalc.sh (revision efd4c9b63ad77503c101fc6c2ed8ba96c9d52964)
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# shcalc - small shell-based calculator
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 do_calculate
56{
57	typeset calcline="$1"
58	float x=0.0
59
60	printf "(( x=( %s ) ))\n" "${calcline}" | source /dev/stdin
61	if (( $? != 0 )) ; then
62		print -f $"%s: Syntax error in %s\n" "${progname}" "${calcline}"
63		return 1
64	fi
65
66	printf "%s == %.40g\n" "${calcline}" x
67
68	return 0
69}
70
71function usage
72{
73	OPTIND=0
74	getopts -a "${progname}" "${shcalc_usage}" OPT '-?'
75	exit 2
76}
77
78# program start
79# (be carefull with builtins here - they are unconditionally available
80# in the shell's "restricted" mode)
81builtin basename
82builtin sum
83
84typeset progname="${ basename "${0}" ; }"
85
86typeset -r shcalc_usage=$'+
87[-?\n@(#)\$Id: shcalc (Roland Mainz) 2008-11-03 \$\n]
88[-author?Roland Mainz <roland.mainz@nrubsig.org>]
89[+NAME?shcalc - simple shell calculator]
90[+DESCRIPTION?\bsshcalc\b is a small calculator application which
91	prints the results of ISO C99 math expressions read from either
92	arguments or stdin if no arguments are given.]
93[+SEE ALSO?\bksh93\b(1),\bceil\b(3M), \bcopysign\b(3M), \bcos\b(3M),
94	\bcosh\b(3M), \berf\b(3M), \berfc\b(3M), \bexp\b(3M),
95	\bexp2\b(3M), \bexpm1\b(3M), \bfabs abs\b(3M), \bfdim\b(3M),
96	\bfinite\b(3M), \bfloor int\b(3M), \bfma\b(3M), \bfmax\b(3M), \bfmin\b(3M),
97	\bfmod\b(3M), \bfpclassify\b(3M), \bhypot\b(3M), \bilogb\b(3M),
98	\bisfinite\b(3M), \bisgreater\b(3M), \bisgreaterequal\b(3M), \bisinf\b(3M),
99	\bisless\b(3M), \bislessequal\b(3M), \bislessgreater\b(3M), \bisnan\b(3M),
100	\bisnormal\b(3M), \bissubnormal\b(3M), \bisunordered\b(3M), \biszero\b(3M),
101	\blgamma\b(3M), \blog\b(3M), \blog1p\b(3M), \blog2\b(3M),
102	\blogb\b(3M), \bnearbyint\b(3M), \bnextafter\b(3M), \bnexttoward\b(3M),
103	\bpow\b(3M), \bremainder\b(3M), \brint\b(3M), \bround\b(3M),
104	\bscalb\b(3M), \bscalbn\b(3M), \bsignbit\b(3M), \bsin\b(3M),
105	\bsinh\b(3M), \bsqrt\b(3M), \btan\b(3M), \btanh\b(3M),
106	\btgamma\b(3M), \btrunc\b(3M)]
107'
108while getopts -a "${progname}" "${shcalc_usage}" OPT ; do
109#	printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
110	case ${OPT} in
111		*)	usage ;;
112	esac
113done
114shift $((OPTIND-1))
115
116integer res
117
118if (( $# == 0 )) ; then
119	# No arguments ? Switch to interactive mode...
120
121	# make sure "read" below uses "gmacs"-like editor keys and "multiline" mode
122
123	set -o gmacs
124	set -o multiline
125
126	while read "calcline?calc> " ; do
127		# quit ?
128		[[ "${calcline}" == ~(Elri)(exit|quit|eof) ]] && break
129
130		# empty line ?
131		[[ "${calcline}" == ~(Elri)([[:space:]]*) ]] && continue
132
133		do_calculate "$calcline"
134		(( res=$? ))
135	done
136
137	exit ${res}
138else
139	while (( $# > 0 )) ; do
140		do_calculate "$1"
141		(( res=$? ))
142		shift
143	done
144
145	exit ${res}
146fi
147
148# not reached
149
150# EOF.
151