#!/usr/bin/perl if ( $#ARGV >= 0 ) { $CALC_quiet = 1; } else { $CALC_quiet = 0; } $CALC_nopush = "CALC_DO_NOT_PUSH"; $CALC_max_k = 18; @CALC_stack = (); $CALC_cmdhist = (); $CALC_recenthist = (); $CALC_code_filename = $ENV{"HOME"}; $CALC_code_filename .= '/.calc.code'; $CALC_got_readline = 0; $CALC_use_readline = 0; foreach $CALC_x ( @INC ) { if ( -r "$CALC_x/Term/ReadLine" ) { $CALC_got_readline = 1; } if ( -r "$CALC_x/Term/ReadLine.pm" ) { $CALC_got_readline = 1; } } $CALC_use_readline = $CALC_got_readline; # default to using it, if we have it if ( -r $CALC_code_filename ) { if ( open ( F_CALC_CODE, "<$CALC_code_filename" ) ) { $CALC_code = ''; $CALC_n = 0; while ( defined ( $CALC_buf = ) ) { $CALC_code .= $CALC_buf; $CALC_n++; } close ( F_CALC_CODE ); $CALC_code .= " \n"; $CALC_result = eval ( $CALC_code ); if ( $CALC_quiet == 0 ) { print ("Read $CALC_n lines from $CALC_code_filename [$CALC_result]\n"); } } } if ( ( $ENV{"HOME"} ne $ENV{"PWD"} ) && ( -r ".calc.code" ) ) { if ( open ( F_CALC_CODE, "<.calc.code" ) ) { $CALC_code = ''; $CALC_n = 0; while ( defined ( $CALC_buf = ) ) { $CALC_code .= $CALC_buf; $CALC_n++; } close ( F_CALC_CODE ); $CALC_code .= " \n"; $CALC_result = eval ( $CALC_code ); if ( $CALC_quiet == 0 ) { print ("Read $CALC_n lines from .calc.code [$CALC_result]\n"); } } } # putting this here -- $CALC_use_readline might be overridden in .calc.code if ( $CALC_use_readline != 0 ) { use Term::ReadLine; $CALC_term = new Term::ReadLine ( "calc [$$]" ); $CALC_init_readline = 1; if ( $CALC_quiet == 0 ) { print ("Using Term::ReadLine Library\n"); } } else { $CALC_init_readline = 0; } $CALC_history_file = $ENV{"HOME"}; $CALC_history_file .= '/.calc.history'; if ( -r $CALC_history_file ) { if ( open ( F_CALC_HIST, "<$CALC_history_file" ) ) { while ( defined ( $CALC_buf = ) ) { chomp ( $CALC_buf ); push ( @CALC_cmdhist, $CALC_buf ); } close ( F_CALC_HIST ); } } $CALC_code = $ENV{"HOME"}; $CALC_code .= '/.calc.tickertape'; $CALC_ticker_running = 0; if ( open ( F_CALC_TAPE, ">>$CALC_code" ) ) { $CALC_ticker_running = 1; } sub CALC_display_history { my ( $depth ) = ( $_[0] ); my ( $kp, $i, $k, $n ); $k = $#CALC_cmdhist + 1; $n = 0; if ( $depth == 0 ) { $i = 0; } else { $i = $k - $depth; } while ( $i < $k ) { print ( "$i: ".($CALC_cmdhist[$i])."\n" ); $n++; $i++; } } sub CALC_hash_to_string { my ( $hr ) = @_; my $ret = ''; foreach my $k ( sort ( keys ( %{$hr} ) ) ) { my $v = $hr->{$k}; my $t = 's'; $t = 'i' if ( $v =~ /^[\d\.]+$/ ); if ( ref($v) ne '' ) { $v = substr ( ref($v), 0, 2 ); $t = 'r'; } $v = "'$v'" if ( $t eq 's' ); $ret .= "$k=$v "; } chop ( $ret ); return ( $ret ); } sub CALC_comment { my ( $s ) = ( $_[0] ); chomp ( $s ); return if ( $CALC_ticker_running != 1 ); $s = "# COMMENT ".(localtime())." / ".(time())."\n$s\n"; print ( F_CALC_TAPE $s ); } sub CALC_do { my ( $CALC_param ) = @_; $CALC_EVAL = 1; last if ( lc($CALC_param) =~ /^\s*quit\s*$/ ); if ( $CALC_param =~ /^\s*(#.*)/ ) { CALC_comment ( $1 ); next; } if ( lc($CALC_param) =~ /^d\s*([0-9]+)\-([0-9]+)$/ ) { $CALC_N1 = int($1); $CALC_N2 = int($2); splice ( @CALC_stack, $CALC_N1, $CALC_N2 - $CALC_N1 + 1); splice ( @CALC_recenthist, $CALC_N1, $CALC_N2 - $CALC_N1 + 1); $CALC_EVAL = 0; } elsif ( lc($CALC_param) =~ /^d\s*([0-9]*)$/ ) { $CALC_N = int($1); if ( $CALC_N > 0 ) { splice ( @CALC_stack, $CALC_N, 1 ); splice ( @CALC_recenthist, $CALC_N, 1 ); } else { splice ( @CALC_stack, 0, 1 ); splice ( @CALC_recenthist, 0, 1 ); } $CALC_EVAL = 0; } elsif ( lc($CALC_param) =~ /^m\s*([0-9]+)$/ ) { $CALC_N = int($1); $CALC_V = $CALC_stack[$CALC_N]; splice ( @CALC_stack, $CALC_N, 1 ); unshift ( @CALC_stack, $CALC_V ); $CALC_EVAL = 0; } elsif ( lc($CALC_param) =~ /^s\s*([0-9]+)$/ ) { $CALC_N = int($1); $CALC_state_file = $ENV{"HOME"}; $CALC_state_file .= "/.calc.state.$CALC_N"; if ( open ( F_CALC_STATE, ">$CALC_state_file" ) ) { my($x); foreach $x ( @CALC_stack ) { print ( F_CALC_STATE "$x\n" ); } close ( F_CALC_STATE ); } else { print ("cannot open savefile\n"); } $CALC_EVAL = 0; } elsif ( lc($CALC_param) =~ /^r\s*([0-9]+)$/ ) { $CALC_N = int($1); $CALC_state_file = $ENV{"HOME"}; $CALC_state_file .= "/.calc.state.$CALC_N"; if ( open ( F_CALC_STATE, "<$CALC_state_file" ) ) { my($x); @CALC_stack = (); while ( defined ( $x = ) ) { chomp($x); push ( @CALC_stack, $x ); } close ( F_CALC_STATE ); } else { print ("cannot open savefile\n"); } $CALC_EVAL = 0; } if ( $CALC_EVAL > 0 ) { if ( $CALC_param =~ /^\!([0-9]+)/ ) { $CALC_param = @CALC_cmdhist[$1]; print ("$CALC_param\n"); } if ( $CALC_param eq '!!' ) { $CALC_param = $CALC_last; print ("$CALC_param\n"); } else { $CALC_last = $CALC_param; } if ( $CALC_param =~ /^history\s*([0-9]*)\s*$/ ) { CALC_display_history(int($1)); next; } push ( @CALC_cmdhist, $CALC_param ); push ( @CALC_recenthist, $CALC_param ); $CALC_raw_foo = $CALC_param; if ( $CALC_ticker_running != 0 ) { print ( F_CALC_TAPE "> $CALC_param\n" ); } if ( $CALC_param =~ /^a([0-9]+)(.*)/ ) { $CALC_1 = $1; $CALC_2 = $2; if ( ( length($CALC_2) == 0 ) || ( $CALC_2 !~ /^[a-zA-Z_]/) ) { $CALC_param = '$CALC_stack['.$CALC_1.']'.$CALC_2; } } while ( $CALC_param =~ /(.*?[^a-zA-Z0-9\$])a([0-9]+)(.*)/ ) { # FIXME -- rewrite this so that $3 does not start with a-zA-Z $CALC_param = $1.'$CALC_stack['.$2.']'.$3; } # Some statement should not be prefixed with $a, nor should # results be pushed onto the stack. if ( ( $CALC_param !~ /^\s*sub[\s\{]/ ) && ( $CALC_param !~ /^\s*for[\s\(]/ ) && ( $CALC_param !~ /^\s*foreach\s+/ ) ) { $CALC_param = '$a = '."$CALC_param"; if ( $CALC_param !~ /[\;\}]\s*$/s ) { $CALC_param .= ';'; } } else { $a = $CALC_nopush; } $CALC_res = eval ( $CALC_param ); if ( !defined ( $CALC_res ) ) { chomp ( $CALC_res2 = $@ ); print ("error: '$CALC_res2'\n"); $a = $CALC_nopush; } if ( defined ( $CALC_res ) && $CALC_param =~ /^\s*sub[\s\{]/ ) { if ( open ( F_CALC_CODE, ">>$CALC_code_filename.dynamic" ) ) { print ( F_CALC_CODE "$CALC_param\n" ); close ( F_CALC_CODE ); } } if ( $a ne $CALC_nopush ) { push ( @CALC_stack, $a ); } else { pop ( @CALC_recenthist ); } if ( $CALC_ticker_running != 0 ) { print ( F_CALC_TAPE "$a\n" ); } } $CALC_k0 = 0; $CALC_k1 = $#CALC_stack; if ( $CALC_k1 > $CALC_max_k ) { $CALC_k0 = $CALC_k1 - $CALC_max_k; } for ( $CALC_i = $CALC_k0; $CALC_i <= $CALC_k1; $CALC_i++ ) { $CALC_n = $CALC_i; if ( $CALC_n < 10 ) { $CALC_n = "0$CALC_n"; } if ( $CALC_quiet == 0 ) { my $CALC_pval = $CALC_stack[$CALC_i]; if ( ref($CALC_pval) eq 'HASH' ) { $CALC_pval = CALC_hash_to_string ( $CALC_pval ); } $CALC_print = "a$CALC_n = ".($CALC_pval); if ( length ( $CALC_print ) < 40 ) { $CALC_print .= (' 'x(31-(length($CALC_print)))) . ' = ' . $CALC_recenthist[$CALC_i]; } print ("$CALC_print\n"); } else { print ( $CALC_stack[$CALC_i] . "\n" ); } } } # END of CALC_do() $CALC_last = "no previous operation"; $CALC_foo = "no previous operation"; CALC_comment ("# calc session started"); if ( $#ARGV >= 0 ) { CALC_do ( $ARGV[0] ); } else { while ( lc($CALC_foo) ne 'quit' ) { if ( $CALC_use_readline == 0 ) { print ('> '); $|=1; $|=0; $CALC_foo = ; } else { $CALC_foo = $CALC_term->readline('> '); } chomp ( $CALC_foo ); next if ( $CALC_foo eq '' ); CALC_do ( $CALC_foo ); # If the user switches on readline() manually, handle it here: if ( ( $CALC_use_readline != 0 ) && ( $CALC_init_readline == 0 ) ) { use Term::ReadLine; $CALC_term = new Term::ReadLine ( "calc [$$]" ); $CALC_init_readline = 1; } } } CALC_comment ("# calc session ended"); $CALC_hist_file = $ENV{"HOME"}; $CALC_hist_file .= '/.calc.history'; if ( open ( F_CALC_HIST, ">$CALC_hist_file" ) ) { foreach $x ( @CALC_cmdhist ) { print ( F_CALC_HIST "$x\n" ); } close ( F_CALC_HIST ); } if ( $CALC_ticker_running != 0 ) { close ( F_CALC_TAPE ); } 1;