From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11421 invoked from network); 29 Jan 2003 19:45:23 -0000 Received: from sunsite.dk (130.225.247.90) by ns1.primenet.com.au with SMTP; 29 Jan 2003 19:45:23 -0000 Received: (qmail 28783 invoked by alias); 29 Jan 2003 19:44:52 -0000 Mailing-List: contact zsh-users-help@sunsite.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 5843 Received: (qmail 28774 invoked from network); 29 Jan 2003 19:44:52 -0000 Received: from localhost (HELO sunsite.dk) (127.0.0.1) by localhost with SMTP; 29 Jan 2003 19:44:52 -0000 X-MessageWall-Score: 0 (sunsite.dk) Received: from [192.11.223.161] by sunsite.dk (MessageWall 1.0.8) with SMTP; 29 Jan 2003 19:44:52 -0000 Received: from nwsgpa.ih.lucent.com (h135-1-121-22.lucent.com [135.1.121.22]) by auemail1.firewall.lucent.com (Switch-2.2.2/Switch-2.2.0) with ESMTP id h0TJiZY08042; Wed, 29 Jan 2003 14:44:35 -0500 (EST) Received: from nwsgpb.ih.lucent.com by nwsgpa.ih.lucent.com (8.8.8+Sun/EMS-1.5 sol2) id NAA24535; Wed, 29 Jan 2003 13:43:35 -0600 (CST) Received: by nwsgpb.ih.lucent.com (8.11.6+Sun/EMS-1.5 client sol2) id h0TJhZv19253; Wed, 29 Jan 2003 13:43:35 -0600 (CST) From: kwong@nwsgpa.ih.lucent.com Message-Id: <200301291943.h0TJhZv19253@nwsgpb.ih.lucent.com> Subject: Re: a calculator for zsh-4.x To: piyokun@email.com (Clifford Caoile) Date: Wed, 29 Jan 2003 13:43:35 -0600 (CST) Cc: zsh-users@sunsite.dk In-Reply-To: from "Clifford Caoile" at Jan 30, 2003 01:03:02 AM MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Dear Clifford, I think your snippet is very clever and provides a quick and easy way to get a good calculator. My own solution to the need of a calculator is less elegant but seems to be a more general and flexible solution. It is extendable (if you know how to tamper with the perl code) and has many more capabilities. It also can be used anywhere perl is available, not necessarily under zsh. I have been using this calculator for a while and it seems to be quite all right (I won't guarantee there are no bugs). It took me a while to get it into this shape, but if any one wants to try it out, it won't require much effort. To enable the calculator ------------------------ 1. Cut out the perl code attached below, save it in a file, e.g. called "pcal.s" (or any other name you like) somewhere that your $PATH can access. 2. chmod +x pcal.s (to make the file executable). 3. Put "alias pcal='noglob pcal.s' in your .zshrc. This line makes it possible to type commands such as pcal 3*7 without using quotes around 3*7. DISCLAIMER ---------- The program was written strictly for personal use and is definitely not of industrial production grade. My real-work load simply won't allow me to spend too much time on such "frivolous" activities :(. There is not much error checking or error recovery for user input. So use the program at your OWN RISK :) Also the code includes more stuffs than are really needed right now - I put those in there with the intention of future extension - I simply never could find time for that. You can use the calculator in two modes: Non-interactive --------------- pcal 3 * 7 # spaces are optional pcal 3 * (sin(3.14159/4) + 1.2) pcal dh 12345 # convert dec -> hex pcal hd 123ab # convert hex -> dec pcal h 123a + abc # compute in hex pcal b 110111 * 1111 # compute in binary When used in this mode, the answer is not saved in a variable as nicely as Clifford's zcal function. If you really want it that way, you have to do a little more work. Instead of defining pcal an alias to pcal.s as before, you can define (put these lines in .zshrc) pcal.s2() { if [[ -n "$*" ]] then _x=`echo $* | sed "s/ans/$ans/g"` ans=`noglob pcal.s $_x`; print ans = $ans else pcal.s2 fi } alias pcal='noglob pcal.s2' But if you need the answer for further computation, you may as well use the interactive mode. Interactive - just type ----------- pcal You will see a prompt pcal> Then you can type in any math expression or any expression allowable in the non-Interactive mode. In addition, you can assign values or results of expressions to variables * You have to use the perl convention of starting * a variable name with $ - sorry, if you are not a perl * fan, you may not like this. If you are as lazy as * I am, you may type ; instead of $. pcal> $a = 123 + 5 '0 = 128 pcal> ;a + 789 '1 = 917 pcal> ;a + '1 '2 = 1045 pcal> h abc * a If you assign a value to a variable, you can use the variable in subsequent calculations. If you do not assign an expression to a variable, you can still use the answer in subsequent calculations using the symbol '0, '1, etc. Use any one of theses commands to quit: q x quit exit There are other features hidden in the code. Explore as you want to. Let me know if you find any bugs. One thing you may object about using such a perl script instead of directly using zsh functions is that once you get into the interactive mode you lose the capability of command line editing. This is true but if you are a more advanced perl user who can add command line capability in your perl script, e.g. using the CPAN ReadLine module. mk kwong ******************************************************************** Code Snippet: #!/usr/bin/env perl # ---------------------------------------------------------------------- # perl calculator - paste me into a file called e.g. pc.s in your $PATH # chmod +x pc.s # put "alias pc='noglob pc.s' in .zshrc # ---------------------------------------------------------------------- sub isint { $_[0] =~ /^\s*[+-]?\d*\s*$/; } sub isfloat { $_[0] =~ /^\s*[+-]?(\d*\.\d+)([eE]+[+-]*\d+)*\s*$/; } sub isefloat { my ($n) = &abs($_[0]); &isfloat($n) && ($n > 1e8 || $n < 1e-8); } sub isstr { !&isint($_[0]) && !&isfloat($_[0]); } sub round { for (@_) { $_ = sprintf("%.0f",$_); } @_; } sub roundf { my ($p) = &isefloat($_[0])? "e" : "f"; sprintf("%.$_[1]$p",$_[0]); } sub floor { for $n (@_) { if ($n =~ /\./) { if ($n >= 0 || $n =~ /\.0*$/) { $n =~ s/\.\d*//; } else { $n =~ s/\.\d*//; $n--; } } } @_; } sub ceil { for $n (@_) { ($n) = &floor(-$n); $n = -$n;} @_; } sub nsort { return sort {$a <=> $b} @_; } sub pr { ## In my own environment, I have command line editing capability ## REPLACE by subroutine to enable command line editing, e.g. using ## the CPAN modules of Term::ReadLine and Term::ReadLine::Gnu print $prompt; $_ = <>; } #################################################################### ($_p = $0) =~ s/.*\///; $_argvs = join(" ",@ARGV); if (@ARGV) { $non_int = 1; #// non-interactive $_ = join(" ",@ARGV); proc(); exit; } $prompt ||= "pcal> "; $quit = '(q|x|quit|exit)'; #################################################################### sub loop { pr(); # $_nopr = 1 means no initial prompt while (1) { if (/^$quit$/) { exit; } exec "$_p $_argvs" if /^\.{1,}$/; # ... new version of program proc(); pr(); } } #################################################################### $_debug = 1; $_OFMT = "%.6g"; loop(); #################################################################### sub proc { $_a = $_s = 0; $_db && db('=xxx,'); if (/^db$/) { $_db = !$_db; return; } # toggle debug if (/^fmt\s*(\d+)$/) { $_OFMT = "%.$1g"; return; } # float output format if (/^,\s*(.*)/) { system($1); return; } # , shell if (/^\.+$/) { system "pe"; exit; } # . rerun if (/^\. \s*(.*)/) { eval($1); return; } # . perl s/\`\`/\$_ans[0]/; s/\`(\d+)/\$_ans[$1]/g; # `` => $_ans s/;(\w)/\$\1/g; # ;a => $a $_db && db('=yyy,'); if (/^\.(\w+)$/) { $_ = "print join(\", \",\@$1)"; # .a => print @a eval; print ",\n"; return; } if (/^\/(\w+)$/) { eval "\%_a = \%$1"; # /a => print %a for $_i (sort(keys(%_a))) { print "$_i => $_a{$_i}, "; } print "\n"; return; } math(); } sub math { #// math mode s/\'\'/$_ans[$_nans]/g; s/\'(\d+)/$_ans[$1]/g; s/\'([a-zA-Z])/\$$1/g; if (s/^hd\s*//) { print " " x 4; #// hex to dec if (/[^\w\s]/) { s/(\w+)/h2d($1)/ge; print eval, "\n"; } else { for $_x (split(/\s+/)) { $_x and print h2d($_x)," "; } print "\n"; } return; } if (s/^dh\s*//) { print " " x 4; #// dec to hex if (/[^\w\s]/) { print d2h(eval), "\n"; } else { for $_x (split(/\s+/)) { $_x and print d2h($_x)," "; } print "\n"; } return; } if (s/^bd\s*//) { print " " x 4; #// bin to dec if (/[^\w\s]/) { s/(\w+)/b2d($1)/ge; print eval, "\n"; } else { for $_x (split(/\s+/)) { $_x and print b2d($_x)," "; } print "\n"; } return; } if (s/^db\s*//) { print " " x 4; #// dec to bin if (/[^\w\s]/) { print d2b(eval), "\n"; } else { for $_x (split(/\s+/)) { $_x and print d2b($_x)," "; } print "\n"; } return; } if (s/^hb\s*//) { print " " x 4; #// hex to bin if (/[^\w\s]/) { s/(\w+)/h2d($1)/ge; print d2b(eval), "\n"; } else { for $_x (split(/\s+/)) { $_x and print d2b(h2d($_x))," "; } print "\n"; } return; } if (s/^bh\s*//) { print " " x 4; #// bin to hex if (/[^\w\s]/) { s/(\w+)/b2d($1)/ge; print d2h(eval), "\n"; } else { for $_x (split(/\s+/)) { $_x and print d2h(b2d($_x))," "; } print "\n"; } return; } if (s/^h\s+//) { #// hex calculations s/(\w+)/h2d($1)/ge; $_ans = d2h(eval); push(@_ans,$_ans); $_nans = $#_ans; $non_int or print "'$_nans = "; print $_ans, "\n"; $non_int or print "\n"; return; } if (s/^b\s+//) { #// bin calculations s/(\w+)/b2d($1)/ge; $_ans = d2b(eval); push(@_ans,$_ans); $_nans = $#_ans; $non_int or print "'$_nans = "; print $_ans, "\n"; $non_int or print "\n"; return; } if (/;\s*$/) { eval; return; } eval "\$_ans = $_"; push(@_ans,$_ans); $_nans = $#_ans; $non_int or print "'$_nans = "; print $_ans, "\n"; $non_int or print "\n"; } sub d2h($) { local($a,$b,$c) = $_[0]; while ($a > 0) { $c = $a % 16; $a = ($a-$c)/16; if ($c == 10) { $c = "a"; } elsif ($c == 11) { $c = "b"; } elsif ($c == 12) { $c = "c"; } elsif ($c == 13) { $c = "d"; } elsif ($c == 14) { $c = "e"; } elsif ($c == 15) { $c = "f"; } $b = "$c$b" } return "$b"; } sub h2d($) { hex($_[0]); } sub d2b($) { local($a,$b,$c) = $_[0]; while ($a > 0) { $c = $a % 2; $a = ($a-$c)/2; $b = "$c$b" } return "$b"; } sub b2d($) { local($a,$b) = $_[0]; while ($a =~ s/.//) { $b = 2*$b + $&; } return $b; } # -----------------------------------------------------------------end > > Dear zsh-users: > > In my excitement over zsh-4.x, I bring to you some sample calculator > functions to enhance your zsh experience. However, I haven't searched this > mailing list for similar subjects at all, and I am ignorant of this mailing > list past posts. Perhaps I'm duplicating suggestions here, but I hope this > is helpful. > > I don't know about you, but I reach for zsh when I want to calculate > addition in hexadecimal (like whenever I have read a linux ksymoops > message). With the following .zshrc snippet, my shell becomes a > convenient-to-type calculator: > > Code Snippet: > # -----------------------------------------------------------------begin > # calculator - paste me into your .zshrc > # ---------------------------------------------------------------------- > > # Here are some quick calculators that output in integer > # hexadecimal, decimal, and binary. > zcalc () { print $(( ans = ${1:-ans} )) } > zcalch () { print $(( [#16] ans = ${1:-ans} )) } > zcalcd () { print $(( [#10] ans = ${1:-ans} )) } > zcalco () { print $(( [#8] ans = ${1:-ans} )) } > zcalcb () { print $(( [#2] ans = ${1:-ans} )) } > > # A key binding that will allow you to quickly get into zcalc > bindkey -s '\C-xd' "zcalc \'" > > [... omitted]