zsh-users
 help / color / mirror / code / Atom feed
* a calculator for zsh-4.x
@ 2003-01-29 16:03 Clifford Caoile
  2003-01-29 16:18 ` Phil Pennock
  2003-01-29 19:43 ` kwong
  0 siblings, 2 replies; 3+ messages in thread
From: Clifford Caoile @ 2003-01-29 16:03 UTC (permalink / raw)
  To: zsh-users

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 \'"

# this last one lets you calculate the ascii value of a single character
zcalcasc () { print $(( [#16] ans = ##${1:-ans} )) }
# -------------------------------------------------------------------end

Usage example:
%> zcalc '23 / 3'       # integer math
7

%> zcalc '23.0 / 3'     # forced floating point math
7.666666666666667

%> zcalc '23 % 3'      # programmers love to mod
2

%> zcalc 'ans + 2'     # your last answer is still there
4

%> zcalc '0xCD & 0x23'   # uh, why are you bit masking?
1

%> zcalc '0xCD | 0x23'    # or you like "or"?
239

%> zcalcb ; zcalco ; zcalcd ; zcalch  # I want it in a readable format
please.
2#11101111
8#357
239
16#EF

%> zcalch '2#11101111 & 0211' # mix the input bases
16#C3

Recommended convenience feature:
Try the bindkey Control-X d. It's a quick jump into zsh-based calculator.
You only need to worry about adding the last quotation mark. (Ugh)

Call for advice:
Actually, I'm most interested in enhancing the bindkey definition. Placing
just one quotation mark on the command line seems to be sloppy. I wish I was
able to set the position of the cursor at any arbitrary point of the
inserted string, just like in emacs. Anybody have any suggestions? I guess
this is just the whole reason for posting...

Instead of putting this in my .zshrc file, is it better to make it a zsh
module?

HTH, HAND
  ,-~-.
 < ^ ; ~,  Clifford Escobar CAOILE  (aka "Piyo-kun")
  (_  _,
   J~~>  _.___...:.__..__.: __.:_. .:_.__::_..:._::._...  _____ p(^_^)q




^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: a calculator for zsh-4.x
  2003-01-29 16:03 a calculator for zsh-4.x Clifford Caoile
@ 2003-01-29 16:18 ` Phil Pennock
  2003-01-29 19:43 ` kwong
  1 sibling, 0 replies; 3+ messages in thread
From: Phil Pennock @ 2003-01-29 16:18 UTC (permalink / raw)
  To: Clifford Caoile; +Cc: zsh-users

On 2003-01-30 at 01:03 +0900, Clifford Caoile wrote:
> I don't know about you, but I reach for zsh when I want to calculate
> addition in hexadecimal

I also tend to do this; messing around with graphical calculators is a
pain.

> # -----------------------------------------------------------------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 \'"
> 
> # this last one lets you calculate the ascii value of a single character
> zcalcasc () { print $(( [#16] ans = ##${1:-ans} )) }
> # -------------------------------------------------------------------end

I like it.  :^)  But with one modification: for the first five
functions, replace ${1:-ans} with ${@:-ans} so that the quotes are
unnecessary unless you're using characters interpreted by the shell.

> Call for advice:
> Actually, I'm most interested in enhancing the bindkey definition. Placing
> just one quotation mark on the command line seems to be sloppy.

I just bypass the need for the bindkey for most of the things I'd use
these functions for.

Thanks,


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: a calculator for zsh-4.x
  2003-01-29 16:03 a calculator for zsh-4.x Clifford Caoile
  2003-01-29 16:18 ` Phil Pennock
@ 2003-01-29 19:43 ` kwong
  1 sibling, 0 replies; 3+ messages in thread
From: kwong @ 2003-01-29 19:43 UTC (permalink / raw)
  To: Clifford Caoile; +Cc: zsh-users

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]


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2003-01-29 19:45 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-01-29 16:03 a calculator for zsh-4.x Clifford Caoile
2003-01-29 16:18 ` Phil Pennock
2003-01-29 19:43 ` kwong

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).