diff --git a/.gitignore b/.gitignore
index 68c5392..ed13d1c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
releases
rpn
+rpn.1
diff --git a/Makefile b/Makefile
index 91375f0..69027a4 100644
--- a/Makefile
+++ b/Makefile
@@ -23,8 +23,27 @@ archs = darwin freebsd linux windows
PREFIX = /usr/local
UID = root
GID = 0
+HAVE_POD := $(shell pod2text -h 2>/dev/null)
-all: buildlocal
+all: $(tool).1 $(tool).go buildlocal
+
+%.1: %.pod
+ifdef HAVE_POD
+ pod2man -c "User Commands" -r 1 -s 1 $*.pod > $*.1
+endif
+
+%.go: %.pod
+ifdef HAVE_POD
+ echo "package main" > $*.go
+ echo >> $*.go
+ echo "var manpage = \`" >> $*.go
+ pod2text $*.pod >> $*.go
+ echo "\`" >> $*.go
+
+ echo "var usage = \`" >> $*.go
+ awk '/SYNOPS/{f=1;next} /DESCR/{f=0} f' $*.pod | sed 's/^ //' >> $*.go
+ echo "\`" >> $*.go
+endif
buildlocal:
CGO_LDFLAGS='-static' go build -tags osusergo,netgo -ldflags "-extldflags=-static" -o $(tool)
diff --git a/README.md b/README.md
index 9d24bc7..d3a2d05 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,55 @@ Features:
- can calculate data in batch mode (also from STDIN)
- extensible with custom LUA functions
+## Working principle
+
+Reverse Polish Notation (short: RPN) requires to have a stack where
+numbers and results are being put. So, you put numbers onto the stack
+and each math operation uses these for calculation, removes them and
+puts the result back.
+
+To visualize it, let's look at a calculation:
+
+ ((80 + 20) / 2) * 4
+
+This is how you enter the formula int an RPN calculator and how the
+stack evolves during the operation:
+
+| rpn commands | stack contents | calculation |
+|--------------|----------------|---------------|
+| 80 | 80 | |
+| 20 | 80 20 | |
+| + | 100 | 80 + 20 = 100 |
+| 2 | 100 2 | |
+| / | 50 | 100 / 2 = 50 |
+| 4 | 50 4 | |
+| x | 200 | 50 * 4 = 200 |
+
+The last stack element 200 is the calculation result. This is how it looks with debugging enabled in `rpn`:
+
+```
+rpn->debug [0/rev0]ยป 80 20 + 2 / 4 x
+DEBUG(000): push to stack: 80.00
+DEBUG(001): push to stack: 20.00
+DEBUG(002): remove from stack: 20.00
+DEBUG(003): remove from stack: 80.00
+DEBUG(calc): evaluating: 80.00 + 20.00
+DEBUG(004): push to stack: 100.00
+= 100
+DEBUG(005): push to stack: 2.00
+DEBUG(006): remove from stack: 2.00
+DEBUG(007): remove from stack: 100.00
+DEBUG(calc): evaluating: 100.00 / 2.00
+DEBUG(008): push to stack: 50.00
+= 50
+DEBUG(009): push to stack: 4.00
+DEBUG(010): remove from stack: 4.00
+DEBUG(011): remove from stack: 50.00
+DEBUG(calc): evaluating: 50.00 x 4.00
+DEBUG(012): push to stack: 200.00
+= 200
+```
+
## Usage
Basically you enter numbers followed by an operator or a
diff --git a/calc.go b/calc.go
index 6517d08..6e7a445 100644
--- a/calc.go
+++ b/calc.go
@@ -76,9 +76,9 @@ Math operators:
// commands, constants and operators, defined here to feed completion
// and our mode switch in Eval() dynamically
const (
- Commands string = `dump reverse debug undebug clear batch shift undo help history exit quit`
+ Commands string = `dump reverse debug undebug clear batch shift undo help history manual exit quit`
Operators string = `+ - * x / ^ % %- %+`
- MathFunctions string = `sqrt remainder avg mean min max median`
+ MathFunctions string = `sqrt remainder`
Constants string = `Pi Phi Sqrt2 SqrtE SqrtPi SqrtPhi Ln2 Log2E Ln10 Log10E`
BatchFunctions string = `median avg mean max min`
)
@@ -255,6 +255,8 @@ func (c *Calc) Eval(line string) {
fallthrough
case "quit":
os.Exit(0)
+ case "manual":
+ man()
default:
fmt.Println("unknown command or operator!")
}
diff --git a/main.go b/main.go
index 144c8df..c4da892 100644
--- a/main.go
+++ b/main.go
@@ -18,8 +18,11 @@ along with this program. If not, see .
package main
import (
+ "bytes"
"fmt"
+ "log"
"os"
+ "os/exec"
"strings"
"github.com/chzyer/readline"
@@ -36,6 +39,7 @@ Usage: rpn [-bdvh] []
Options:
-b, --batchmode enable batch mode
-d, --debug enable debug mode
+ -m, --manual show manual
-v, --version show version
-h, --help show help
@@ -49,6 +53,7 @@ func main() {
showversion := false
showhelp := false
+ showmanual := false
enabledebug := false
configfile := ""
@@ -56,6 +61,7 @@ func main() {
flag.BoolVarP(&enabledebug, "debug", "d", false, "debug mode")
flag.BoolVarP(&showversion, "version", "v", false, "show version")
flag.BoolVarP(&showhelp, "help", "h", false, "show usage")
+ flag.BoolVarP(&showmanual, "manual", "m", false, "show manual")
flag.StringVarP(&configfile, "config", "c",
os.Getenv("HOME")+"/.rpn.lua", "config file (lua format)")
@@ -75,6 +81,11 @@ func main() {
calc.ToggleDebug()
}
+ if showmanual {
+ man()
+ os.Exit(0)
+ }
+
// the lua state object is global, instanciate it early
L = lua.NewState(lua.Options{SkipOpenLibs: true})
defer L.Close()
@@ -141,3 +152,20 @@ func inputIsStdin() bool {
stat, _ := os.Stdin.Stat()
return (stat.Mode() & os.ModeCharDevice) == 0
}
+
+func man() {
+ man := exec.Command("less", "-")
+
+ var b bytes.Buffer
+ b.Write([]byte(manpage))
+
+ man.Stdout = os.Stdout
+ man.Stdin = &b
+ man.Stderr = os.Stderr
+
+ err := man.Run()
+
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/rpn.go b/rpn.go
new file mode 100644
index 0000000..164db2a
--- /dev/null
+++ b/rpn.go
@@ -0,0 +1,206 @@
+package main
+
+var manpage = `
+NAME
+ rpn - Reverse Polish Notation Calculator for the commandline
+
+SYNOPSIS
+ Usage: rpn [-bdvh] []
+
+ Options:
+ -b, --batchmode enable batch mode
+ -d, --debug enable debug mode
+ -v, --version show version
+ -h, --help show help
+
+ When is given, batch mode ist automatically enabled. Use
+ this only when working with stdin. E.g.: echo "2 3 4 5" | rpn +
+
+DESCRIPTION
+ rpn is a command line calculator using reverse polish notation.
+
+ Working principle
+ Reverse Polish Notation (short: RPN) requires to have a stack where
+ numbers and results are being put. So, you put numbers onto the stack
+ and each math operation uses these for calculation, removes them and
+ puts the result back.
+
+ To visualize it, let's look at a calculation:
+
+ ((80 + 20) / 2) * 4
+
+ This is how you enter the formula int an RPN calculator and how the
+ stack evolves during the operation:
+
+ | rpn commands | stack contents | calculation |
+ |--------------|----------------|---------------|
+ | 80 | 80 | |
+ | 20 | 80 20 | |
+ | + | 100 | 80 + 20 = 100 |
+ | 2 | 100 2 | |
+ | / | 50 | 100 / 2 = 50 |
+ | 4 | 50 4 | |
+ | x | 200 | 50 * 4 = 200 |
+
+ The last stack element 200 is the calculation result.
+
+ USAGE
+ The default mode of operation is the interactive mode. You'll get a
+ prompt which shows you the current size of the stack. At the prompt you
+ enter numbers followed by operators or mathematical functions. You can
+ use completion for the functions. You can either enter each number or
+ operator on its own line or separated by whitespace, that doesn't
+ matter. After a calculation the result will be immediately displayed
+ (and added to the stack). You can quit interactive mode using the
+ commands quit or exit or hit one of the "ctrl-d" or "ctrl-c" key
+ combinations.
+
+ If you feed data to standard input (STDIN), rpn just does the
+ calculation denoted in the contet fed in via stdin, prints the result
+ and exits. You can also specify a calculation on the commandline.
+
+ Here are the three variants ($ is the shell prompt):
+
+ $ rpn
+ rpn> 2
+ rpn> 2
+ rpn> +
+ = 4
+
+ $ rpn
+ rpn> 2 2 +
+ = 4
+
+ $ echo 2 2 + | rpn
+ 4
+
+ $ rpn 2 2 +
+ 4
+
+ The rpn calculator provides a batch mode which you can use to do math
+ operations on many numbers. Batch mode can be enabled using the
+ commandline option "-b" or toggled using the interactive command batch.
+ Not all math operations and functions work in batch mode though.
+
+ Example of batch mode usage:
+
+ $ rpn -b
+ rpn->batch > 2 2 2 2 +
+ = 8
+
+ $ rpn
+ rpn> batch
+ rpn->batch> 2 2 2 2 +
+ 8
+
+ $ echo 2 2 2 2 + | rpn -b
+ 8
+
+ $ echo 2 2 2 2 | rpn +
+ 8
+
+ If the first parameter to rpn is a math operator or function, batch mode
+ is enabled automatically, see last example.
+
+ STACK MANIPULATION
+ There are lots of stack manipulation commands provided. The most
+ important one is undo which goes back to the stack before the last math
+ operation.
+
+ You can use dump to display the stack. If debugging is enabled ("-d"
+ switch or debug toggle command), then the backup stack is also being
+ displayed.
+
+ The stack can be reversed using the reverse command.
+
+ You can use the shift command to remove the last number from the stack.
+
+EXTENDING RPN USING LUA
+ You can use a lua script with lua functions to extend the calculator. By
+ default the tool looks for "~/.rpn.lua". You can also specify a script
+ using the -c flag.
+
+ Here's an example of such a script:
+
+ function add(a,b)
+ return a + b
+ end
+
+ function init()
+ register("add", 2, "addition")
+ end
+
+ Here we created a function "add()" which adds two parameters. All
+ parameters are "FLOAT64" numbers. You don't have to worry about stack
+ management, this is taken care of automatically.
+
+ The function "init()" MUST be defined, it will be called on startup. You
+ can do anything you like in there, but you need to call the "register()"
+ function to register your functions to the calculator. This function
+ takes these parameters:
+
+ * function name
+
+ * number of arguments expected (1,2 or -1 allowed), -1 means batch
+ mode.
+
+ * help text
+
+ Please refer to the lua language reference:
+ for more details about LUA.
+
+ Please note, that io, networking and system stuff is not allowed though.
+ So you can't open files, execute other programs or open a connection to
+ the outside!
+
+GETTING HELP
+ In interactive mode you can enter the help command (or ?) to get a short
+ help along with a list of all supported operators and functions.
+
+ To read the manual you can use the manual command in interactive mode.
+ The commandline option "-m" does the same thing.
+
+ If you have installed rpn as a package or using the distributed tarball,
+ there will also be a manual page you can read using "man rpn".
+
+BUGS
+ In order to report a bug, unexpected behavior, feature requests or to
+ submit a patch, please open an issue on github:
+ .
+
+LICENSE
+ This software is licensed under the GNU GENERAL PUBLIC LICENSE version
+ 3.
+
+ Copyright (c) 2023 by Thomas von Dein
+
+ This software uses the following GO modules:
+
+ readline (github.com/chzyer/readline)
+ Released under the MIT License, Copyright (c) 2016-2023 ChenYe
+
+ pflag (https://github.com/spf13/pflag)
+ Released under the BSD 3 license, Copyright 2013-2023 Steve Francia
+
+ gopher-lua (github.com/yuin/gopher-lua)
+ Released under the MIT License, Copyright (c) 2015-2023 Yusuke
+ Inuzuka
+
+AUTHORS
+ Thomas von Dein tom AT vondein DOT org
+
+`
+var usage = `
+
+Usage: rpn [-bdvh] []
+
+Options:
+ -b, --batchmode enable batch mode
+ -d, --debug enable debug mode
+ -v, --version show version
+ -h, --help show help
+
+When is given, batch mode ist automatically enabled. Use
+this only when working with stdin. E.g.: echo "2 3 4 5" | rpn +
+
+`
diff --git a/rpn.pod b/rpn.pod
new file mode 100644
index 0000000..1dea393
--- /dev/null
+++ b/rpn.pod
@@ -0,0 +1,220 @@
+=head1 NAME
+
+rpn - Reverse Polish Notation Calculator for the commandline
+
+=head1 SYNOPSIS
+
+ Usage: rpn [-bdvh] []
+
+ Options:
+ -b, --batchmode enable batch mode
+ -d, --debug enable debug mode
+ -v, --version show version
+ -h, --help show help
+
+ When is given, batch mode ist automatically enabled. Use
+ this only when working with stdin. E.g.: echo "2 3 4 5" | rpn +
+
+=head1 DESCRIPTION
+
+rpn is a command line calculator using reverse polish notation.
+
+=head2 Working principle
+
+Reverse Polish Notation (short: RPN) requires to have a stack where
+numbers and results are being put. So, you put numbers onto the stack
+and each math operation uses these for calculation, removes them and
+puts the result back.
+
+To visualize it, let's look at a calculation:
+
+ ((80 + 20) / 2) * 4
+
+This is how you enter the formula int an RPN calculator and how the
+stack evolves during the operation:
+
+ | rpn commands | stack contents | calculation |
+ |--------------|----------------|---------------|
+ | 80 | 80 | |
+ | 20 | 80 20 | |
+ | + | 100 | 80 + 20 = 100 |
+ | 2 | 100 2 | |
+ | / | 50 | 100 / 2 = 50 |
+ | 4 | 50 4 | |
+ | x | 200 | 50 * 4 = 200 |
+
+The last stack element 200 is the calculation result.
+
+=head2 USAGE
+
+The default mode of operation is the interactive mode. You'll get a
+prompt which shows you the current size of the stack. At the prompt
+you enter numbers followed by operators or mathematical functions. You
+can use completion for the functions. You can either enter each number
+or operator on its own line or separated by whitespace, that doesn't
+matter. After a calculation the result will be immediately displayed
+(and added to the stack). You can quit interactive mode using the
+commands B or B or hit one of the C or C
+key combinations.
+
+If you feed data to standard input (STDIN), rpn just does the
+calculation denoted in the contet fed in via stdin, prints the result
+and exits. You can also specify a calculation on the commandline.
+
+Here are the three variants ($ is the shell prompt):
+
+ $ rpn
+ rpn> 2
+ rpn> 2
+ rpn> +
+ = 4
+
+ $ rpn
+ rpn> 2 2 +
+ = 4
+
+ $ echo 2 2 + | rpn
+ 4
+
+ $ rpn 2 2 +
+ 4
+
+The rpn calculator provides a batch mode which you can use to do math
+operations on many numbers. Batch mode can be enabled using the
+commandline option C<-b> or toggled using the interactive command
+B. Not all math operations and functions work in batch mode
+though.
+
+Example of batch mode usage:
+
+ $ rpn -b
+ rpn->batch > 2 2 2 2 +
+ = 8
+
+ $ rpn
+ rpn> batch
+ rpn->batch> 2 2 2 2 +
+ 8
+
+ $ echo 2 2 2 2 + | rpn -b
+ 8
+
+ $ echo 2 2 2 2 | rpn +
+ 8
+
+
+If the first parameter to rpn is a math operator or function, batch
+mode is enabled automatically, see last example.
+
+=head2 STACK MANIPULATION
+
+There are lots of stack manipulation commands provided. The most
+important one is B which goes back to the stack before the last
+math operation.
+
+You can use B to display the stack. If debugging
+is enabled (C<-d> switch or B toggle command), then the backup
+stack is also being displayed.
+
+The stack can be reversed using the B command.
+
+You can use the B command to remove the last number from the
+stack.
+
+
+=head1 EXTENDING RPN USING LUA
+
+You can use a lua script with lua functions to extend the
+calculator. By default the tool looks for C<~/.rpn.lua>. You can also
+specify a script using the -c flag.
+
+Here's an example of such a script:
+
+ function add(a,b)
+ return a + b
+ end
+
+ function init()
+ register("add", 2, "addition")
+ end
+
+Here we created a function C which adds two parameters. All
+parameters are C numbers. You don't have to worry about stack
+management, this is taken care of automatically.
+
+The function C B be defined, it will be called on
+startup. You can do anything you like in there, but you need to call
+the C function to register your functions to the
+calculator. This function takes these parameters:
+
+=over
+
+=item *
+
+function name
+
+=item *
+
+number of arguments expected (1,2 or -1 allowed), -1 means batch
+mode.
+
+=item *
+
+help text
+
+=back
+
+Please refer to the lua language reference:
+L for more details about LUA.
+
+B
+
+=head1 GETTING HELP
+
+In interactive mode you can enter the B command (or B>) to get
+a short help along with a list of all supported operators and
+functions.
+
+To read the manual you can use the B command in interactive
+mode. The commandline option C<-m> does the same thing.
+
+If you have installed rpn as a package or using the distributed
+tarball, there will also be a manual page you can read using C.
+
+=head1 BUGS
+
+In order to report a bug, unexpected behavior, feature requests
+or to submit a patch, please open an issue on github:
+L.
+
+=head1 LICENSE
+
+This software is licensed under the GNU GENERAL PUBLIC LICENSE version 3.
+
+Copyright (c) 2023 by Thomas von Dein
+
+This software uses the following GO modules:
+
+=over 4
+
+=item readline (github.com/chzyer/readline)
+
+Released under the MIT License, Copyright (c) 2016-2023 ChenYe
+
+=item pflag (https://github.com/spf13/pflag)
+
+Released under the BSD 3 license, Copyright 2013-2023 Steve Francia
+
+=item gopher-lua (github.com/yuin/gopher-lua)
+
+Released under the MIT License, Copyright (c) 2015-2023 Yusuke Inuzuka
+
+=back
+
+=head1 AUTHORS
+
+Thomas von Dein B
+
+=cut