├── .mvn
└── maven.config
├── graphics
├── Banner.jpg
├── Banner.xcf
├── PostIt.xcf
├── ScreenShot1.jpg
├── ScreenShot1.xcf
├── ScreenShot2.jpg
├── ScreenShot2.xcf
├── ReadmeHeader.jpg
├── ReadmeHeader.xcf
├── PostIt-200x200.jpg
├── PostIt-512x512.jpg
└── PostIt-512x512.png
├── mdbook
├── src
│ ├── Images
│ │ ├── Snap.png
│ │ ├── Trig.png
│ │ ├── UDF.png
│ │ ├── Build.png
│ │ ├── CmdLine.png
│ │ ├── HP15C.jpg
│ │ ├── Install.png
│ │ ├── License.png
│ │ ├── Memory.png
│ │ ├── Plates.png
│ │ ├── WrapUp.png
│ │ ├── Configure.png
│ │ ├── Constants.png
│ │ ├── Operands.png
│ │ ├── WhatIsRPN.jpg
│ │ ├── CalcCommands.png
│ │ ├── Conversion.png
│ │ ├── Acknowledgment.png
│ │ ├── HighLevelUsage.png
│ │ └── OperationalCmds.png
│ ├── Chapters
│ │ ├── Wrapup.md
│ │ ├── Cover.md
│ │ ├── TrigFunctions.md
│ │ ├── CommandLineOptions.md
│ │ ├── BuildingRPNCalc.md
│ │ ├── MemoryCommands.md
│ │ ├── Operands.md
│ │ ├── Installation.md
│ │ ├── Constants.md
│ │ ├── Acknowledgements.md
│ │ ├── Snap.md
│ │ ├── Stacks.md
│ │ ├── Conversions.md
│ │ ├── Introduction.md
│ │ ├── WhatIsRPN.md
│ │ ├── HighLevelUsage.md
│ │ ├── Configuration.md
│ │ └── UserDefinedFunctions.md
│ └── SUMMARY.md
└── book.toml
├── tools
├── FractionTestResults.xlsx
├── UpdateUserGuide.btm
└── GenChecksums.py
├── src
├── main
│ ├── resources
│ │ └── app.properties
│ └── java
│ │ └── org
│ │ └── fross
│ │ ├── library
│ │ ├── GitHub.java
│ │ ├── Debug.java
│ │ ├── URLOperations.java
│ │ ├── Spinner.java
│ │ ├── Date.java
│ │ ├── Format.java
│ │ ├── SpinnerBouncyBall.java
│ │ └── Output.java
│ │ └── rpncalc
│ │ ├── CommandHistory.java
│ │ ├── StackManagement.java
│ │ ├── StackConstants.java
│ │ ├── Display.java
│ │ ├── Browser.java
│ │ ├── CommandLineArgs.java
│ │ ├── StackTrig.java
│ │ └── Configuration.java
└── test
│ └── java
│ └── org
│ └── fross
│ ├── library
│ ├── DebugTest.java
│ ├── DateTest.java
│ └── FormatTest.java
│ └── rpncalc
│ ├── DisplayTest.java
│ ├── StackManagementTest.java
│ ├── CommandHistoryTest.java
│ ├── UserDefinedFunctionsTest.java
│ ├── StackConstantsTest.java
│ ├── CommandLineArgsTest.java
│ ├── ConfigurationTest.java
│ ├── StackMemoryTest.java
│ └── StackTrigTest.java
├── .idea
├── codeStyles
│ └── codeStyleConfig.xml
├── .gitignore
├── encodings.xml
├── statistic.xml
├── vcs.xml
├── misc.xml
├── compiler.xml
└── jarRepositories.xml
├── snap
├── local
│ └── rpncalc-wrapper
└── snapcraft.yaml
├── .gitignore
├── README.md
└── LICENSE
/.mvn/maven.config:
--------------------------------------------------------------------------------
1 | -T 1C
2 |
--------------------------------------------------------------------------------
/graphics/Banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/graphics/Banner.jpg
--------------------------------------------------------------------------------
/graphics/Banner.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/graphics/Banner.xcf
--------------------------------------------------------------------------------
/graphics/PostIt.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/graphics/PostIt.xcf
--------------------------------------------------------------------------------
/graphics/ScreenShot1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/graphics/ScreenShot1.jpg
--------------------------------------------------------------------------------
/graphics/ScreenShot1.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/graphics/ScreenShot1.xcf
--------------------------------------------------------------------------------
/graphics/ScreenShot2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/graphics/ScreenShot2.jpg
--------------------------------------------------------------------------------
/graphics/ScreenShot2.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/graphics/ScreenShot2.xcf
--------------------------------------------------------------------------------
/graphics/ReadmeHeader.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/graphics/ReadmeHeader.jpg
--------------------------------------------------------------------------------
/graphics/ReadmeHeader.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/graphics/ReadmeHeader.xcf
--------------------------------------------------------------------------------
/mdbook/src/Images/Snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/Snap.png
--------------------------------------------------------------------------------
/mdbook/src/Images/Trig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/Trig.png
--------------------------------------------------------------------------------
/mdbook/src/Images/UDF.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/UDF.png
--------------------------------------------------------------------------------
/graphics/PostIt-200x200.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/graphics/PostIt-200x200.jpg
--------------------------------------------------------------------------------
/graphics/PostIt-512x512.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/graphics/PostIt-512x512.jpg
--------------------------------------------------------------------------------
/graphics/PostIt-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/graphics/PostIt-512x512.png
--------------------------------------------------------------------------------
/mdbook/src/Images/Build.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/Build.png
--------------------------------------------------------------------------------
/mdbook/src/Images/CmdLine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/CmdLine.png
--------------------------------------------------------------------------------
/mdbook/src/Images/HP15C.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/HP15C.jpg
--------------------------------------------------------------------------------
/mdbook/src/Images/Install.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/Install.png
--------------------------------------------------------------------------------
/mdbook/src/Images/License.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/License.png
--------------------------------------------------------------------------------
/mdbook/src/Images/Memory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/Memory.png
--------------------------------------------------------------------------------
/mdbook/src/Images/Plates.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/Plates.png
--------------------------------------------------------------------------------
/mdbook/src/Images/WrapUp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/WrapUp.png
--------------------------------------------------------------------------------
/mdbook/src/Images/Configure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/Configure.png
--------------------------------------------------------------------------------
/mdbook/src/Images/Constants.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/Constants.png
--------------------------------------------------------------------------------
/mdbook/src/Images/Operands.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/Operands.png
--------------------------------------------------------------------------------
/mdbook/src/Images/WhatIsRPN.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/WhatIsRPN.jpg
--------------------------------------------------------------------------------
/tools/FractionTestResults.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/tools/FractionTestResults.xlsx
--------------------------------------------------------------------------------
/mdbook/src/Images/CalcCommands.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/CalcCommands.png
--------------------------------------------------------------------------------
/mdbook/src/Images/Conversion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/Conversion.png
--------------------------------------------------------------------------------
/mdbook/src/Images/Acknowledgment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/Acknowledgment.png
--------------------------------------------------------------------------------
/mdbook/src/Images/HighLevelUsage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/HighLevelUsage.png
--------------------------------------------------------------------------------
/mdbook/src/Images/OperationalCmds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frossm/rpncalc/HEAD/mdbook/src/Images/OperationalCmds.png
--------------------------------------------------------------------------------
/src/main/resources/app.properties:
--------------------------------------------------------------------------------
1 | Application.version=${project.version}
2 | Application.inceptionYear=${project.inceptionYear}
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Wrapup
4 |
5 | Well, if you've read this far you probably know more about RPNCalc than I do. I needed a command line based RPN calculator and have been very happy with this one. I've added features as I've needed them and use it daily for many years now. Some time ago I decided to make the program, source, and documentation available so others could use it if they wished. For those that have, I hope you found it useful.
6 |
7 | I'll continue to add new features as I think about them. If you have suggestions, issues, or ideas, the links to reach out to me are on the Introduction page.
8 |
9 | Best wishes and happy reverse Polish notation calculating...
--------------------------------------------------------------------------------
/mdbook/src/Chapters/Cover.md:
--------------------------------------------------------------------------------
1 |
Copyright 2011- 2024 by Michael Fross
7 | This document, along RPNCalc, is licensed under the MIT License
15 |
16 |
16 |
--------------------------------------------------------------------------------
/mdbook/src/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # Summary
2 |
3 | - [Cover](./Chapters/Cover.md)
4 | - [Introduction](./Chapters/Introduction.md)
5 | - [What is an RPN Calculator](./Chapters/WhatIsRPN.md)
6 | - [Installation](./Chapters/Installation.md)
7 | - [Stacks](./Chapters/Stacks.md)
8 | - [High Level Usage](./Chapters/HighLevelUsage.md)
9 | - [Command Line Options](./Chapters/CommandLineOptions.md)
10 | - [Operands](./Chapters/Operands.md)
11 | - [Configuration](./Chapters/Configuration.md)
12 | - [Calculator Commands](./Chapters/CalculatorCommands.md)
13 | - [Conversions](./Chapters/Conversions.md)
14 | - [Trigonometry Functions](./Chapters/TrigFunctions.md)
15 | - [Memory Commands](./Chapters/MemoryCommands.md)
16 | - [Constants](./Chapters/Constants.md)
17 | - [User Defined Functions](./Chapters/UserDefinedFunctions.md)
18 | - [Operational Commands](./Chapters/OperationalCommands.md)
19 | - [Building RPNCalc](./Chapters/BuildingRPNCalc.md)
20 | - [Snap Usage](./Chapters/Snap.md)
21 | - [Wrapup](./Chapters/Wrapup.md)
22 | - [Licenses](./Chapters/License.md)
23 | - [Acknowledgements](./Chapters/Acknowledgements.md)
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2011-2026 Michael Fross
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tools/UpdateUserGuide.btm:
--------------------------------------------------------------------------------
1 | rem #####################################################################
2 | rem # UpdateUserGuide.btm
3 | rem #
4 | rem # Compile the RPNCalc User Guide using mdbook and copy
5 | rem # the files to the user guide directory
6 | rem #
7 | rem #####################################################################
8 |
9 | :: Ensure we're in the project's root directory by looking for the pom.xml file
10 | iff not exist %@Filename[pom.xml] then
11 | echocolor RED, "Error: Must run from the root directory of a maven project"
12 | quit /b
13 | endiff
14 |
15 | :: Build the book
16 | echocolor YELLOW "Generating the html from the markdown with mdbook"
17 | cd mdbook
18 |
19 | echocolor WHITE " - Cleaning any existing generated User Guide files"
20 | mdbook clean
21 |
22 | echocolor WHITE " - Building the User Guide"
23 | mdbook build
24 |
25 |
26 | echo.
27 | echocolor YELLOW "Moving User Guide to frossm.github.io
28 |
29 | :: Move the book
30 | cd ..\..\frossm.github.io
31 |
32 | echocolor WHITE " - Removing old RPNCalc-UserGuide directory"
33 | del /E /S /T /X /Y /Z /K /Q /Nnt RPNCalc-UserGuide
34 |
35 | mkdir RPNCalc-UserGuide
36 | cd RPNCalc-UserGuide
37 |
38 | echocolor WHITE " - Copying the book"
39 | copy ..\..\rpncalc\mdbook\RPNCalc-UserGuide\* . /e/s/v/q
40 | cd ..
41 |
42 | echo.
43 | echocolor YELLOW "Process Completed"
44 |
--------------------------------------------------------------------------------
/mdbook/src/Chapters/TrigFunctions.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Trigonometry Functions
4 |
5 | RPNCalc does not consider itself a fully fledged scientific calculator (at least not currently). However, it's certainly beyond a very basic calculator. The trigonometry commands listed here are basic, but do fill a need if you need to do a few basic calculations.
6 |
7 | Lastly, I'm happy to add more capabilities if there is a desire (and an offer to help test).
8 |
9 | |
2 |
3 | # Command Line Options
4 |
5 | Currently there are several command line options, and all are optional. Normally, one would simply run the program and you would enter in numbers, operands, and commands.
6 |
7 | These options will either start RPNCalc in a certain "mode" such as `Debug` or `No Color` or will provide information and exist such as `Version` or `Help`.
8 |
9 | |
2 |
3 | # Building RPNCalc from the Source
4 |
5 | RPNCalc is written in Java and uses [Maven](https://maven.apache.org/what-is-maven.html) as it's build tool. To build, you'll need to have the Java Development Kit (JDK) installed on your system. Make sure you get the JDK and not the Java Runtime Environment (JRE) which most people would have on their machines. The JRE allows you to run Java applications, but not build them. At the time of this writing, you'll need Java 11 or newer.
6 |
7 | After the JDK is installed, you'll need to install the Apache Maven build tool. Then download/clone of the source code from Github along with my [library package](https://github.com/frossm/library). This library package contains many methods that I use across my applications.
8 |
9 | To install the library, execute the following from the top level library directory (the one with the `pom.xml` file in it):
10 |
11 | `mvn install`
12 |
13 | That should install the library into the Maven cache on your computer. You can remove the library directory.
14 |
15 | Secondly, you'll need to build the executable RPNCalc jar file. Download, or clone, the RPNCalc source code from the link provided above. Unzip it to a directory and from the top level directory of RPNCalc, execute:
16 |
17 | `mvn package`
18 |
19 | Assuming all goes well, you'll have a new shiny `rpncalc.jar` file in the `target` directory.
20 |
21 | Automated testing in RPNCalc (using JUnit5) is fairly complete (although testing can always be more extensive) and should catch most issues with the code. The hope is I find them before it's released, but pay attention to the Maven output and you'll see if there are issues.
22 |
23 | I'll discuss this more in the Snap chapter, but if you are on a Linux system that supports snaps, I would encourage that you leverage it. Not only are Snap applications "sandboxed" so it's more secure, all of the dependencies are bundled in so you don't even need to have java installed on the machine. It is also automatically updated so you'll always have the latest. Although this can also be forced with `sudo snap refresh`.
24 |
25 | My preference is to use the Snap installation which is what I do on my Ubuntu machines.
--------------------------------------------------------------------------------
/tools/GenChecksums.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import re
4 | import hashlib
5 |
6 | BLOCK_SIZE = 65536 # The size of each read from the file
7 |
8 | MD5FILENAME = "CHECKSUM.MD5"
9 | SHA1FILENAME = "CHECKSUM.SHA1"
10 | SHA256FILENAME = "CHECKSUM.SHA256"
11 |
12 | if __name__ == "__main__":
13 | # Determine the jar filename from our path. Must be run in project base dir
14 | fileNamePlain = os.path.basename(os.getcwd()) + ".jar"
15 | fileName = "target/" + fileNamePlain
16 |
17 | # Create the hash objects
18 | hashMD5 = hashlib.md5()
19 | hashSHA1 = hashlib.sha1()
20 | hashSHA256 = hashlib.sha256()
21 |
22 | # Open the file to read it's contents
23 | with open(fileName, 'rb') as f:
24 | # Read the specified amount from the file
25 | fileBuffer = f.read(BLOCK_SIZE)
26 |
27 | # While there is still data being read from the file...
28 | while len(fileBuffer) > 0:
29 | # Update the hashes
30 | hashMD5.update(fileBuffer)
31 | hashSHA1.update(fileBuffer)
32 | hashSHA256.update(fileBuffer)
33 |
34 | # Read the next block from the file
35 | fileBuffer = f.read(BLOCK_SIZE)
36 |
37 | # Print the hexadecimal digest of the hash to the console
38 | print ("Generating Checksums in target directory")
39 | print (MD5FILENAME + ": " + hashMD5.hexdigest() + " " + fileNamePlain)
40 | print (SHA1FILENAME + ": " + hashSHA1.hexdigest() + " " + fileNamePlain)
41 | print (SHA256FILENAME + ": " + hashSHA256.hexdigest() + " " + fileNamePlain)
42 |
43 | # Output the hash information into files
44 | outFile = open("target/" + MD5FILENAME, "w")
45 | try:
46 | print (hashMD5.hexdigest() + " " + fileNamePlain, file=outFile)
47 | finally:
48 | outFile.close()
49 |
50 | outFile = open("target/" + SHA1FILENAME, "w")
51 | try:
52 | print (hashSHA1.hexdigest() + " " + fileNamePlain, file=outFile)
53 |
54 | finally:
55 | outFile.close()
56 |
57 | outFile = open("target/" + SHA256FILENAME, "w")
58 | try:
59 | print (hashSHA256.hexdigest() + " " + fileNamePlain, file=outFile)
60 |
61 | finally:
62 | outFile.close()
63 |
64 |
--------------------------------------------------------------------------------
/src/test/java/org/fross/library/DateTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package org.fross.library;
5 |
6 | import static org.junit.jupiter.api.Assertions.assertEquals;
7 |
8 | import org.junit.jupiter.api.Test;
9 |
10 | /**
11 | * @author Michael Fross (michael@fross.org)
12 | *
13 | */
14 | class DateTest {
15 |
16 | static final String[] monthsLong = { "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November",
17 | "December" };
18 | static final String[] monthsShort = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
19 | static java.util.Calendar jc = java.util.Calendar.getInstance();
20 |
21 | /**
22 | * Test method for {@link org.fross.library.Date#getCurrentMonth()}.
23 | */
24 |
25 | @Test
26 | void testGetCurrentMonth() {
27 | assertEquals(jc.get(java.util.Calendar.MONTH) + 1, Date.getCurrentMonth());
28 | }
29 |
30 | /**
31 | * Test method for {@link org.fross.library.Date#getCurrentDay()}.
32 | */
33 | @Test
34 | void testGetCurrentDay() {
35 | assertEquals(jc.get(java.util.Calendar.DAY_OF_MONTH), Date.getCurrentDay());
36 | }
37 |
38 | /**
39 | * Test method for {@link org.fross.library.Date#getCurrentYear()}.
40 | */
41 | @Test
42 | void testGetCurrentYear() {
43 | assertEquals(jc.get(java.util.Calendar.YEAR), Date.getCurrentYear());
44 | }
45 |
46 | /**
47 | * Test method for {@link org.fross.library.Date#getCurrentMonthNameLong()}.
48 | */
49 | @Test
50 | void testGetCurrentMonthNameLong() {
51 | assertEquals(monthsLong[jc.get(java.util.Calendar.MONTH) + 1], Date.getCurrentMonthNameLong());
52 | }
53 |
54 | /**
55 | * Test method for {@link org.fross.library.Date#getCurrentMonthNameShort()}.
56 | */
57 | @Test
58 | void testGetCurrentMonthNameShort() {
59 | assertEquals(monthsShort[jc.get(java.util.Calendar.MONTH) + 1], Date.getCurrentMonthNameShort());
60 | }
61 |
62 | /**
63 | * Test method for {@link org.fross.library.Date#getMonthNameLong(int)}.
64 | */
65 | @Test
66 | void testGetMonthNameLong() {
67 | assertEquals("January", Date.getMonthNameLong(1));
68 | assertEquals("May", Date.getMonthNameLong(5));
69 | assertEquals("December", Date.getMonthNameLong(12));
70 | }
71 |
72 | /**
73 | * Test method for {@link org.fross.library.Date#getMonthNameShort(int)}.
74 | */
75 | @Test
76 | void testGetMonthNameShort() {
77 | assertEquals("Jan", Date.getMonthNameShort(1));
78 | assertEquals("May", Date.getMonthNameShort(5));
79 | assertEquals("Dec", Date.getMonthNameShort(12));
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/mdbook/src/Chapters/MemoryCommands.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Memory Commands
4 |
5 | The memory capabilities are fairly flexible. By default, there are 10 memory slots you can use (`slot0` - `slot9`). This amount can be increased with the `set memslots` command. If you increase or decrease the number of memory slots, it is persistent across RPNCalc executions. You can change it as will, but if you decrease the number of slots, anything held in the "no longer there" slots will be discarded.
6 |
7 | For example, say you `set memslots 20` and store values in all of them. If you later `set memslots 10`, the values in the upper 10 slots will be discarded.
8 |
9 | The operational command `reset` will reset all of the persistant settings back to their defaults including the number of memory slots.
10 |
11 | The normal usage to is to save a value from the current `line1` into a memory slot and copy it back later. The memory slots are saved between program executions so if you need it in a later session, it will be there. It's saved in the Java preferences system as discussed earlier.
12 |
13 | |
2 |
3 | # Operands
4 |
5 | Operands are the standard symbols used for basic mathematics on numbers. The following is the list of operands supported by RPNCalc. These are also supported by the NumOps shortcut described below.
6 |
7 | With the exception of the addition (`+`) and multiplication (`*`) operands, the order of the items in the stack is important. It's fairly intuitive when you look at it in the calculator, but refer to the following table if needed.
8 |
9 | |Operand|Math|Description|
10 | |:-------:|:----:|-------|
11 | |+ |`Addition`| Add `line1` and `line2`|
12 | |- |`Subtraction`| Subtract `line1` from `line2`|
13 | |\* |`Multiplication`|Multiply`line1` and `line2`|
14 | |/ |`Division`| Divide `line2` by `line1`|
15 | |^ |`Exponent`| Take `line2` to the power of `line1` Note that the exponent must be an integer. If it is not, the fractional component will be dropped prior to the calculation|
16 |
17 | Below are two very simple examples that show the order is important
18 |
19 | |Line Num|Stack|
20 | |:------:|:---:|
21 | |`line2`|3|
22 | |`line1`|2|
23 |
24 | Example: The minus `-` command will execute 3 - 2 and will yield `1`
25 |
26 | |Line Num|Stack|
27 | |:------:|:---:|
28 | |`line2`|2|
29 | |`line1`|3|
30 |
31 | Example: Minus `-` will execute 2 - 3 and will yield `-1`
32 |
33 |
34 |
2 |
3 | # Installation
4 |
5 | There are two ways to install RPNCalc. The first is simply download `rpncalc.jar` file from the latest release on [GitHub](https://github.com/frossm/rpncalc). I have embedded all of the dependencies into this one file and it is directly executable. You do not need to install anything. Of course, you will need a java runtime (JRE) installed in your path.
6 |
7 | The second is to run it as a [Snap](https://en.wikipedia.org/wiki/Snap_(software)). There are many advantages to using it as a snap and I'll get into that in the SNAP secion of this user guide. My personal preference is to install it via Snap for teh following reasons:
8 | - No Java to worry about as it's built into the snap
9 | - Protected as it runs in a sandbox and won't have access to other system objects
10 | - No aliases needed to run it since `rpncalc` can be run directly from the command line. An example alias with Bash is below.
11 | - Its automagically kept up to date
12 | - Additional information is available in the `SNAP` chapter
13 |
14 | Please note that I only have the ability to test it in Windows and Linux (Ubuntu). While I don't think there would be issues on other platforms, it's something to keep in mind. Snapcraft does compile them, however, without issue on the other platforms.
15 |
16 | ## Standard Usage
17 |
18 | To run RPNCalc use the following command:
19 |
20 | `java -jar /path/to/rpncalc.jar`
21 |
22 | This is much too long to type every time you need to run it, so I simply create an alias. Here is example from the Bash shell:
23 |
24 | `alias rpncalc='java -jar /path/to/rpncalc.jar`
25 |
26 | Now, I just need to type `rpncalc` to run it.
27 |
28 | ## Standard Uninstall
29 |
30 | If you wish to uninstall RPNCalc, just delete the file and, if you created an alias, remove that as well. Easy and simple.
31 |
32 | However, RPNCalc does use the Java preferences to store the persistent stack contents, settings, and persistent memory slots. This system is located in different places depending on the OS and these are listed in the `Stacks Chapter`.
33 |
34 | It is very small and removing it is not really necessary, but if you like to keep things exceptionally tidy, delete the `org/fross/rpn/` entry (and everything below it) in the preference system.
35 |
36 | ## Snap Installation
37 |
38 | If you are on a Linux system and have Snap installed (it's comes default on most Ubuntu based distributions, but can be installed by most others if not already there), you can install RPNCalc as a snap. It does not require any special snap permissions. To install via snap use:
39 |
40 | `sudo snap install rpncalc`
41 |
42 | To run it after installation, simply execute:
43 |
44 | `rpncalc`
45 |
46 | ## Snap Uninstall
47 |
48 | To uninstall, execute the following command:
49 |
50 | `sudo snap remove rpncalc`
51 |
52 | [](https://snapcraft.io/rpncalc)
--------------------------------------------------------------------------------
/src/test/java/org/fross/rpncalc/DisplayTest.java:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------------------
2 | * RPNCalc
3 | *
4 | * RPNCalc is is an easy to use console based RPN calculator
5 | *
6 | * Copyright (c) 2011-2026 Michael Fross
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | * ------------------------------------------------------------------------------*/
27 | package org.fross.rpncalc;
28 |
29 | import org.junit.jupiter.api.Test;
30 |
31 | import java.math.BigDecimal;
32 |
33 | import static org.junit.jupiter.api.Assertions.assertEquals;
34 |
35 | public class DisplayTest {
36 | @Test
37 | void testComma() {
38 | assertEquals("1", Display.Comma(new BigDecimal("1")));
39 | assertEquals("1.01", Display.Comma(new BigDecimal("1.01")));
40 | assertEquals("-2.000000001231", Display.Comma(new BigDecimal("-2.000000001231")));
41 | assertEquals("10,001", Display.Comma(new BigDecimal("10001")));
42 | assertEquals("-123,456,789.987654321", Display.Comma(new BigDecimal("-123456789.987654321")));
43 | assertEquals("-0.1234567890123456789", Display.Comma(new BigDecimal("-0.1234567890123456789")));
44 | assertEquals("-1,987,654,321,987,654,321", Display.Comma(new BigDecimal("-1987654321987654321")));
45 | }
46 |
47 | @Test
48 | void testQueryDecimalIndex() {
49 | assertEquals(6, Display.queryDecimalIndex("50,000"));
50 | assertEquals(1, Display.queryDecimalIndex("1"));
51 | assertEquals(1, Display.queryDecimalIndex("1.01"));
52 | assertEquals(5, Display.queryDecimalIndex("-1234.4321"));
53 | assertEquals(0, Display.queryDecimalIndex(".00001"));
54 | assertEquals(18, Display.queryDecimalIndex("-1,123,454,678,999.1234532643"));
55 | assertEquals(5, Display.queryDecimalIndex("-8e21"));
56 | assertEquals(1, Display.queryDecimalIndex("1.02e+22"));
57 | assertEquals(6, Display.queryDecimalIndex("-1e+22"));
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/org/fross/rpncalc/StackManagementTest.java:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------------------
2 | * RPNCalc
3 | *
4 | * RPNCalc is is an easy to use console based RPN calculator
5 | *
6 | * Copyright (c) 2011-2026 Michael Fross
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | * ------------------------------------------------------------------------------*/
27 | package org.fross.rpncalc;
28 |
29 | import org.junit.jupiter.api.Test;
30 |
31 | import static org.junit.jupiter.api.Assertions.assertEquals;
32 |
33 | /**
34 | * @author Michael Fross (michael@fross.org)
35 | */
36 | class StackManagementTest {
37 | /**
38 | * Test method for {@link org.fross.rpncalc.StackManagement#QueryCurrentStackNum()}.
39 | */
40 | @Test
41 | void testQueryCurrentStackNum() {
42 | StackObj stk1 = new StackObj();
43 | StackObj stk2 = new StackObj();
44 |
45 | assertEquals(1, StackManagement.QueryCurrentStackNum());
46 |
47 | StackOperations.cmdSwapStack(stk1, stk2);
48 | assertEquals(2, StackManagement.QueryCurrentStackNum());
49 |
50 | StackOperations.cmdSwapStack(stk1, stk2);
51 | assertEquals(1, StackManagement.QueryCurrentStackNum());
52 | }
53 |
54 | /**
55 | * Test method for {@link org.fross.rpncalc.StackManagement#ToggleCurrentStackNum()}.
56 | */
57 | @Test
58 | void testToggleCurrentStackNum() {
59 | StackManagement.ToggleCurrentStackNum();
60 | assertEquals(2, StackManagement.QueryCurrentStackNum());
61 | StackManagement.ToggleCurrentStackNum();
62 | assertEquals(1, StackManagement.QueryCurrentStackNum());
63 | }
64 |
65 | /**
66 | * Testing querying the name of the loaded stack
67 | */
68 | @Test
69 | void testQueryLoadedStack() {
70 | StackObj stk = new StackObj();
71 |
72 | stk.setStackNameAndRestore("junittest", "1");
73 | assertEquals("junittest", stk.queryStackName());
74 | }
75 |
76 | }
--------------------------------------------------------------------------------
/src/test/java/org/fross/rpncalc/CommandHistoryTest.java:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------------------
2 | * RPNCalc
3 | *
4 | * RPNCalc is is an easy to use console based RPN calculator
5 | *
6 | * Copyright (c) 2011-2026 Michael Fross
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | * ------------------------------------------------------------------------------*/
27 | package org.fross.rpncalc;
28 |
29 | import org.junit.jupiter.api.Test;
30 |
31 | import static org.junit.jupiter.api.Assertions.assertEquals;
32 |
33 | /**
34 | * @author Michael Fross (michael@fross.org)
35 | */
36 | public class CommandHistoryTest {
37 |
38 | /**
39 | * Test History Commands
40 | */
41 | @Test
42 | void testHistoryCommands() {
43 | // Add 3 commands
44 | CommandHistory.addCommand("44", "44", "");
45 | CommandHistory.addCommand("4/", "4/", "");
46 | CommandHistory.addCommand("copy", "copy", "");
47 | assertEquals(3, CommandHistory.size());
48 |
49 | // Get without param
50 | assertEquals("copy##copy##", CommandHistory.get());
51 | assertEquals("44##44##", CommandHistory.get(0));
52 |
53 | // Get with param
54 | CommandHistory.addCommand("LongCommand", "LongCommand", "ParamHere");
55 | assertEquals(4, CommandHistory.size());
56 | assertEquals("LongCommand##LongCommand##ParamHere", CommandHistory.get());
57 |
58 | // Remove that 44 from the beginning
59 | CommandHistory.remove(0);
60 | assertEquals(3, CommandHistory.size());
61 | assertEquals("4/##4/##", CommandHistory.get(0));
62 |
63 | // Remove illegal index value
64 | CommandHistory.remove(-1);
65 | assertEquals(3, CommandHistory.size());
66 |
67 | // Remove the last command
68 | CommandHistory.remove();
69 | assertEquals(2, CommandHistory.size());
70 | assertEquals("4/##4/##", CommandHistory.get(0));
71 |
72 | // Test Clear
73 | CommandHistory.clear();
74 | assertEquals(0, CommandHistory.size());
75 | assertEquals("", CommandHistory.get(0));
76 | assertEquals("", CommandHistory.get(CommandHistory.size() - 1));
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/test/java/org/fross/rpncalc/UserDefinedFunctionsTest.java:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------------------
2 | * RPNCalc
3 | *
4 | * RPNCalc is is an easy to use console based RPN calculator
5 | *
6 | * Copyright (c) 2011-2026 Michael Fross
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | * ------------------------------------------------------------------------------*/
27 | package org.fross.rpncalc;
28 |
29 | import org.junit.jupiter.api.Test;
30 |
31 | import static org.junit.jupiter.api.Assertions.*;
32 |
33 | /**
34 | * @author Michael Fross (michael@fross.org)
35 | */
36 | class UserDefinedFunctionsTest {
37 | /**
38 | * Test recording, testing, and deleting a UDF
39 | */
40 | @Test
41 | void CreateFunction() {
42 | String testFunctionName = "automated-testing";
43 |
44 | // If the test function already exists for some reason delete it
45 | if (UserFunctions.FunctionExists(testFunctionName)) {
46 | UserFunctions.FunctionDelete(testFunctionName);
47 | }
48 |
49 | // Create the test stack
50 | StackObj stk = new StackObj();
51 |
52 | // Add several values to the stack
53 | stk.push("150123123");
54 | stk.push(3.25e4);
55 | assertEquals(2, stk.size());
56 |
57 | // Enable recording
58 | UserFunctions.cmdRecord("on");
59 | assertTrue(UserFunctions.recordingIsEnabled());
60 |
61 | // Add the numbers on the stack together
62 | CommandParser.Parse(stk, stk, "+", "+", "");
63 | UserFunctions.RecordCommand("+");
64 | assertEquals(1, stk.size());
65 | assertEquals("150155623.0", stk.getAsString(0));
66 |
67 | // Stop the recording
68 | UserFunctions.cmdRecord("off " + testFunctionName);
69 | assertFalse(UserFunctions.recordingIsEnabled());
70 |
71 | // Ensure the test is in the preferences system
72 | assertTrue(UserFunctions.FunctionExists(testFunctionName));
73 |
74 | // Use the new function to add two numbers
75 | CommandParser.Parse(stk, stk, "4", "4", "");
76 | assertEquals(2, stk.size());
77 | CommandParser.Parse(stk, stk, testFunctionName, testFunctionName, "");
78 | assertEquals(1, stk.size());
79 | assertEquals("150155627.0", stk.getAsString(0));
80 |
81 | // Remove the test function
82 | UserFunctions.FunctionDelete(testFunctionName);
83 | assertFalse(UserFunctions.FunctionExists(testFunctionName));
84 |
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/mdbook/src/Chapters/Constants.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Constants
4 |
5 | These commands simply take a defined constant and add that number to the top of the stack (`line1`). There are currently not that many constants defined, but if there is a desire to add additional ones please me know. It's quick and easy.
6 |
7 | To use a constant, simply run the command and the value of the requested constant will be added
8 | to the top of the stack (`line1`)
9 |
10 | | Constant | Description |
11 | |-------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
12 | | pi | **PI - ARCHIMEDES' CONSTANT**
2 |
3 | # Acknowledgments
4 |
5 | This is a simple user guide for a tiny piece of software. But I have used other people's art and applications to create RPNCalc and I want to ensure I recognize them
6 | and give them thanks.
7 |
8 | ## Libraries
9 |
10 | Extensive use of several libraries were used in RPNCalc. I'd like to publicly thank the authors and give them credit for their hard work. The licenses for these libraries
11 | is detailed in the `Licenses` chapter.
12 |
13 | - [JCommander](ttps://jcommander.org) is used to parse the command line for options and parameters
14 |
15 | - [jAnsi](https://github.com/fusesource/jansi) allows for colorized output in the consoles
16 |
17 | - [jUnit5](https://github.com/junit-team/junit5) is used for automated unit testing
18 |
19 | - [Maven](https://maven.apache.org/) build tool is used extensively in RPNCalc
20 |
21 | - [OpenJDK](https://adoptium.net) is the engine that runs Java on my systems. You may be running another Java Development Kit (JDK) or Java Runtime Environment (JRE)
22 |
23 | ## Graphics
24 |
25 | I'd like to give recognition and attribution to the authors of the icons used in this guide.
26 |
27 | - Configure: Easy installation icons created by Freepik - Flaticon
28 |
29 | - High Level Usage: Calculator icons created by srip - Flaticon
30 |
31 | - Stacks: Maguro icons created by Kanyanee Watanajitkasem - Flaticon
32 |
33 | - Operands: Calculator icons created by Freepik - Flaticon
34 |
35 | - Install: Save file icons created by Tanah Basah - Flaticon
36 |
37 | - Calculator Commands: Maths icons created by Freepik - Flaticon
38 |
39 | - Conversion: Data transfer icons created by Freepik - Flaticon
40 |
41 | - Trigonometry Functions: Trigonometry icons created by Freepik - Flaticon
42 |
43 | - Memory: Memory icons created by Victoruler - Flaticon
44 |
45 | - Constants: Pi icons created by Freepik - Flaticon
46 |
47 | - User Defined Functions: Path icons created by Freepik - Flaticon
48 |
49 | - Acknowledgment: Agreement icons created by Freepik - Flaticon
50 |
51 | - Other icons were sourced from [IconFinder](https://iconfinder.com) and are licensed via the [Creative Commons License](https://creativecommons.org/licenses/)
52 |
53 | ## mdBook
54 |
55 | This book was generated using [mdBook](https://github.com/rust-lang/mdBook). mdBook is a utility to create modern online books from Markdown
56 | files, and it is fantastic. If you need to do something like this, mdBook is where you should look first in my humble opinion.
57 |
58 | ## HP 15C Calculator
59 |
60 | And, lastly, probably the most important item in my personal RPN journey is my trusty HP 15C calculator. I've had it since the late 1980's. While I
61 | don't use it much anymore, instead relying on RPNCalc, it's still an important item to me and always in my desk drawer. Thanks 15C!
62 |
63 |
67 |
2 |
3 | # SNAP
4 | [](https://snapcraft.io/rpncalc)
5 |
6 | I would encourage anyone with a supported Linux platform to use the Snap package of RPNCalc. You can learn more about Snap from the [Snapcraft Homepage](https://snapcraft.io).
7 |
8 | At a high level, a Snap is a fully contained container with your application and it's dependencies bundled in. It runs in a `sandbox` so it can't interfere with other parts of your system until it's given access. Snaps are automatically kept up to date and are easily removed leaving no trace on the system. There is even a nice [App Store](https://snapcraft.io/store) where you can find software.
9 |
10 | As an example, RPNCalc uses Java, but you don't have to have Java installed on your machine as it's bundled in with the Snap.
11 |
12 | [](https://snapcraft.io/rpncalc)
13 |
14 | As a shameless plug, you can [Search for 'Fross'](https://snapcraft.io/search?q=fross) to see all of my Snap packages, or visit my [GitHub home](https://github.com/frossm) for my other open source software.
15 |
16 | While I'm a fan of Snaps, there are positives and negatives to using them.
17 |
18 | ## Snap: The Good and the Bad
19 |
20 | ***-- Thanks to the good folks at MakeUseOf.com for this! --
*** 21 | 22 | [MakeUseOf.com](https://www.makeuseof.com/everything-you-need-to-know-about-snap-and-snap-store/) has a good breakdown of everything that's good and bad about Snap. 23 | 24 | Ever since Canonical announced Snap, there's been a stir in the Linux community about whether Snap is the right approach to improve package distribution on Linux. This has given rise to two opposing camps: one in favor of Snap and the other critical of its approach in the long run. 25 | 26 | Here's a breakdown of everything that's good and bad about Snap. 27 | 28 | ### Advantages of Using Snap 29 | 30 | - Snaps come bundled with dependencies (libraries) that facilitate instant access to a program, as you no longer have to manually install the missing dependencies to make it work on your system. 31 | - Each snap runs in its own containerized sandbox to avoid interference with other system packages. As a result, when you remove a snap, the system removes all of its data, including dependencies, without affecting other packages. Needless to say, this also offers a more secure environment since one package can't access the information of another. 32 | - Snap updates snaps automatically at set intervals. Hence, you always run the latest version of a program on your system. 33 | - Snap makes it easier for developers to distribute their software directly to users, so they don't have to wait for their Linux distribution to roll them out. 34 | - Adding to the previous point, another advantage of putting developers in charge of packaging and distributing their software is that they don't have to create distro-specific packages, as it comes bundled with the required dependencies. 35 | 36 | ### Disadvantages of Snap 37 | 38 | - Since snaps come bundled with dependencies, they're larger in size and occupy more disk space than their counterparts from other package managers. 39 | - As a result of the bundled dependencies, snaps are distributed as compressed filesystem images and you need to mount them first before installing. Because of this, snaps are slower to run than traditional packages. 40 | - Although Snap enables developers to distribute their snaps directly to users, the distribution pipeline requires them to set up an account with Canonical and host their snaps on it. This goes against the true nature of the open-source methodology because even though the software is still open source, the package management system is controlled by an entity. 41 | - Another downside to allowing developers to distribute packages is that the packages don't go through stringent checks and reviews by the community and therefore carry the risk of containing malware---as seen a few years back. 42 | - Due to the fact that Snap's back-end is still closed-source and controlled by Canonical, many major Linux distros aren't on board with the idea of putting Snap as the default package manager on their system. -------------------------------------------------------------------------------- /mdbook/src/Chapters/Stacks.md: -------------------------------------------------------------------------------- 1 |
2 |
3 | # Stacks
4 |
5 | The entire concept of a RPN calculator is based on a stack, which can be thoughts of as numbers stacked on top of each other. You add numbers to the stack and they are normally processed Last In First Out (LIFO).
6 |
7 | With RPNCalc, when you leave the program, the current (and secondary) stacks are saved. If you didn't specify a named stack, the `default` stack is loaded. When you start the program you can specify which stack to load with the `-l` command. You may also load / create a new stack inside of the program with the `load` command. One use case is to create different aliases to open different stacks using the `-l` command.
8 |
9 | When you perform calculations or commands, they generally work from the top of the stack down. In RPNCalc, the top of the stack is `line1` and it's actually at the bottom of the display. When you perform calculations, you are working on your command line and the lines you are using are above the text entry area. This might be a bit hard to visualize, but makes a lot of sense when you actually use the calculator. Trust me.
10 |
11 | For example, if you want to take the square root of 25, you enter `25 [ENTER]` and it will be added to the top of the stack at `line1`. Anything else on the stack is pushed "up" on the display. Then execute the command `SQRT [ENTER]`. This will remove 25 from the stack on `line1`, perform the square root, then place the result `5` back onto the stack. Some operations require more than one stack item. The addition command `+`, for example, will take the last two numbers off the stack (`line1` and `line2`), add them together, and then place the result on the stack.
12 |
13 | The order of the numbers on the stack is important for some of the operands. This is detailed out in the `Operand chapter`.
14 |
15 |
16 | ## Stack Management
17 |
18 | Saving and loading stacks is fundamental to RPNCalc. You can have as many named stacks as you like. They are stored in the Java Preferences system which is located in various places depending on the OS:
19 |
20 | |OS|Location|
21 | |--|--------|
22 | |Windows| Stored in the current user hive of the registry at`(HKCU\Software\JavaSoft\Prefs\org\fross\rpn)`|
23 | |Linux| Linux uses the .java directory in your home directory|
24 | |Mac| The preferences files are named `com.apple.java.util.prefs` are are stored in their home directory at `~/Library/Preferences`. I don't have access to a Mac and can not confirm this location|
25 |
26 | It is safe to delete these if you wish, but of course you'll lose any saved stacks, memory slots, persistent configurations, and user defined functions which are stored there. The structure, not the data, will be recreated again when RPNCalc is restarted.
27 |
28 | Each stack you load (default or a named stack) actually has 2 internal stacks defined; a primary and secondary. You can quickly swap stacks using the swap stack `ss` command. For example, you are working on something and need to do a few calculations that you wish to keep separate from your main work. You can swap stacks, do the work, then swap back. They do not communicate in any way and are distinctly separate. The primary and secondary stack data is saved and restored upon loading the stack. The primary and secondary stacks have their own unique undo stacks as of version 4.5. This was long standing issue that's now been resolved.
29 |
30 | When you start up RPNCalc, you can load a named stack with the `-l name` command. If the stack `name` exists, it will be loaded. If it does not exist, the stack will be created and when you leave the program it will be saved under that name. You can always view the current stack you are using in the lower right of the dashed bar. The `:1` or `:2` after the stack name will tell you if you are on the primary or secondary stack.
31 |
32 | As a side note, both stacks and memory slots are saved during shutdown. While the data in a stack is specific to that stack, memory slots and user created functions are global. The default stack items are restored at startup (or whatever stack you choose to load with `-l name`.) Memory slots are also restored at startup. `list mem` will show the values in current memory, and `list stacks` will show the existing stacks available to load.
33 |
--------------------------------------------------------------------------------
/src/main/java/org/fross/library/Spinner.java:
--------------------------------------------------------------------------------
1 | /**************************************************************************************************************
2 | * Library Project
3 | *
4 | * Library holds methods and classes frequently used by my programs.
5 | *
6 | * Copyright (c) 2018-2024 Michael Fross
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | ***************************************************************************************************************/
27 | package org.fross.library;
28 |
29 | import static org.fusesource.jansi.Ansi.ansi;
30 |
31 | import java.util.concurrent.TimeUnit;
32 |
33 | import org.fusesource.jansi.Ansi;
34 |
35 | /**
36 | * Spinner is a simple class that displays a text based graphic that can be shown while other work is being done.
37 | *
38 | * The spinner process starts a new thread and when the work in the main program is complete, it's stopped.
39 | *
40 | * Usage:
41 | * Start Spinner:
42 | * SpinnerBouncyBall spinner = new SpinnerBouncyBall();
43 | * spinner.start();
44 | *
45 | * Stop Spinner:
46 | * spinner.interrupt();
47 | *
48 | * @author Michael
49 | *
50 | */
51 | public class Spinner extends Thread {
52 | protected final int SPINNER_DELAY = 120;
53 |
54 | String[] spinnerSymbols = { "|", "/", "-", "\\" };
55 | int currentSpinner = 0;
56 |
57 | /**
58 | * run(): Overrides Thread run() method interface and is the main thread execution loop
59 | */
60 | public void run() {
61 | // Keep calling the update spinner until the thread is interrupted
62 | while (Thread.currentThread().isInterrupted() == false) {
63 | // Spin the spinner
64 | spinSpinner();
65 |
66 | // Delay before next thread symbol is displayed
67 | try {
68 | TimeUnit.MILLISECONDS.sleep(SPINNER_DELAY);
69 | } catch (InterruptedException ex) {
70 | Thread.currentThread().interrupt();
71 | }
72 | }
73 |
74 | // Erase the last spinner symbol character
75 | System.out.println(" ");
76 | }
77 |
78 | /**
79 | * spinSpinner(): Show the spinner symbol and advance to the next index
80 | *
81 | */
82 | public void spinSpinner() {
83 | // Display the Spinner
84 | Output.printColor(Ansi.Color.YELLOW, spinnerSymbols[currentSpinner]);
85 |
86 | // Move cursor back one spot
87 | System.out.print(ansi().cursorLeft(1));
88 |
89 | // Advance the spinner to the next symbol
90 | currentSpinner++;
91 |
92 | // Loop it back around when we hit the end
93 | if (currentSpinner >= spinnerSymbols.length) {
94 | currentSpinner = 0;
95 | }
96 | }
97 |
98 | /**
99 | * main(): Simply here to test the spinner
100 | *
101 | * @param args
102 | */
103 | public static void main(String[] args) {
104 | System.out.println("Running Spinner for 10 seconds:");
105 |
106 | // Define and start the spinner
107 | Spinner spinner = new Spinner();
108 | spinner.start();
109 |
110 | // Sleep for 10 seconds
111 | try {
112 | TimeUnit.MILLISECONDS.sleep(10000);
113 | } catch (InterruptedException ex) {
114 | Thread.currentThread().interrupt();
115 | }
116 |
117 | // Stop the spinner
118 | spinner.interrupt();
119 |
120 | System.out.println("\nSpinner Complete\n\n");
121 | }
122 |
123 | } // END CLASS
--------------------------------------------------------------------------------
/src/main/java/org/fross/rpncalc/StackManagement.java:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------------------
2 | * RPNCalc
3 | *
4 | * RPNCalc is is an easy to use console based RPN calculator
5 | *
6 | * Copyright (c) 2011-2026 Michael Fross
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | * ------------------------------------------------------------------------------*/
27 | package org.fross.rpncalc;
28 |
29 | import org.fross.library.Output;
30 | import org.fusesource.jansi.Ansi;
31 |
32 | import java.util.prefs.BackingStoreException;
33 | import java.util.prefs.Preferences;
34 |
35 | public class StackManagement {
36 | // Class Constants
37 | protected static final String PREFS_PATH = "/org/fross/rpn/stacks";
38 |
39 | // Class Variables
40 | private static int currentStackNum = 1;
41 |
42 | /**
43 | * QueryCurrentStackNum(): Return the current active stack number
44 | *
45 | * @return Current active stack number
46 | */
47 | public static int QueryCurrentStackNum() {
48 | return currentStackNum;
49 | }
50 |
51 | /**
52 | * QueryStacks(): Return a string array of all current stacks
53 | *
54 | * @return String array of all of the current stack
55 | */
56 | public static String[] QueryStacks() {
57 | String[] stacks = {};
58 | Preferences prefsQuery = Preferences.userRoot().node(PREFS_PATH);
59 |
60 | try {
61 | stacks = prefsQuery.childrenNames();
62 | } catch (BackingStoreException ex) {
63 | Output.printColor(Ansi.Color.RED, "Error Reading Stacks from Java Preferences");
64 | }
65 |
66 | return (stacks);
67 | }
68 |
69 | /**
70 | * SaveStack(): Save the provided stack into the preferences system
71 | *
72 | * @param stk - Stack to Save
73 | * @param stackSlot - Stack Save slot number. Should be default, 1, or 2.
74 | */
75 | public static void SaveStack(StackObj stk, String stackSlot) {
76 | Output.debugPrintln("SaveStack: " + PREFS_PATH + "/" + stk.queryStackName() + "/" + stackSlot);
77 |
78 | // Override the default stack location with the provided one
79 | Preferences p = Preferences.userRoot().node(PREFS_PATH + "/" + stk.queryStackName() + "/" + stackSlot);
80 |
81 | // Let's clear out any stack values that may exist
82 | try {
83 | p.clear();
84 | } catch (BackingStoreException e) {
85 | Output.printColorln(Ansi.Color.RED, "ERROR: Could not clear current preferences in Stack #" + stackSlot);
86 | Output.printColorln(Ansi.Color.RED, e.getMessage());
87 | }
88 |
89 | // Save number of elements to key StackElements
90 | p.putInt("StackElements", stk.size());
91 |
92 | // Loop through each member of the stack and save it to the preferences
93 | for (int i = 0; i <= stk.size() - 1; i++) {
94 | Output.debugPrintln(" - Saving #" + (stk.size() - i) + ": " + stk.get(i).toPlainString());
95 | p.put("Stack" + i, stk.get(i).toPlainString());
96 | }
97 |
98 | }
99 |
100 | /**
101 | * Toggle CurrentStackNum(): Toggle to the next stack
102 | */
103 | public static void ToggleCurrentStackNum() {
104 | if (currentStackNum == 1) currentStackNum = 2;
105 | else currentStackNum = 1;
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/src/test/java/org/fross/rpncalc/CommandLineArgsTest.java:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------------------
2 | * RPNCalc
3 | *
4 | * RPNCalc is is an easy to use console based RPN calculator
5 | *
6 | * Copyright (c) 2011-2026 Michael Fross
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | * ------------------------------------------------------------------------------*/
27 | package org.fross.rpncalc;
28 |
29 | import com.beust.jcommander.JCommander;
30 | import org.junit.jupiter.api.Test;
31 |
32 | import static org.junit.jupiter.api.Assertions.*;
33 |
34 | /**
35 | * @author Michael Fross (michael@fross.org)
36 | */
37 | class CommandLineArgsTest {
38 | @Test
39 | void testShortCommandLineArgs() {
40 | // Test Short Options
41 | String[] argv1 = {"-D", "-z", "-h", "-v", "-L", "-l", "LoadFile.txt"};
42 |
43 | CommandLineArgs cli = new CommandLineArgs();
44 | JCommander jc = new JCommander();
45 | jc.setProgramName("RPNCalc");
46 |
47 | jc = JCommander.newBuilder().addObject(cli).build();
48 | jc.parse(argv1);
49 |
50 | assertTrue(cli.clDebug);
51 | assertTrue(cli.clNoColor);
52 | assertTrue(cli.clLicense);
53 | assertTrue(cli.clVersion);
54 | assertTrue(cli.clHelp);
55 | assertEquals("LoadFile.txt", cli.clLoad);
56 | }
57 |
58 | @Test
59 | void testLongCommandLineArgs() {
60 | // Test Long Options
61 | String[] argv2 = {"--debug", "--no-color", "--help", "--license", "--version", "--load", "LongLoadFile.txt"};
62 |
63 | CommandLineArgs cli = new CommandLineArgs();
64 | JCommander jc = new JCommander();
65 | jc.setProgramName("RPNCalc");
66 |
67 | jc = JCommander.newBuilder().addObject(cli).build();
68 | jc.parse(argv2);
69 |
70 | assertTrue(cli.clDebug);
71 | assertTrue(cli.clNoColor);
72 | assertTrue(cli.clLicense);
73 | assertTrue(cli.clVersion);
74 | assertTrue(cli.clHelp);
75 | assertEquals("LongLoadFile.txt", cli.clLoad);
76 | }
77 |
78 | @Test
79 | void testMixedCommandLineArgs1() {
80 | // Test Mix of Options
81 | String[] argv3 = {"--no-color", "-?", "--load", "MixedLoadFile.txt"};
82 |
83 | CommandLineArgs cli = new CommandLineArgs();
84 | JCommander jc = new JCommander();
85 | jc.setProgramName("RPNCalc");
86 |
87 | jc = JCommander.newBuilder().addObject(cli).build();
88 | jc.parse(argv3);
89 |
90 | assertFalse(cli.clDebug);
91 | assertTrue(cli.clNoColor);
92 | assertFalse(cli.clVersion);
93 | assertTrue(cli.clHelp);
94 | assertEquals("MixedLoadFile.txt", cli.clLoad);
95 | }
96 |
97 | @Test
98 | void testMixedCommandLineArgs2() {
99 | // Test Mix of Options
100 | String[] argv4 = {"--debug", "-h", "--license", "-l", "MixedLoadFile2.txt"};
101 |
102 | CommandLineArgs cli = new CommandLineArgs();
103 | JCommander jc = new JCommander();
104 | jc.setProgramName("RPNCalc");
105 |
106 | jc = JCommander.newBuilder().addObject(cli).build();
107 | jc.parse(argv4);
108 |
109 | assertTrue(cli.clDebug);
110 | assertFalse(cli.clNoColor);
111 | assertFalse(cli.clVersion);
112 | assertTrue(cli.clHelp);
113 | assertTrue(cli.clLicense);
114 | assertEquals("MixedLoadFile2.txt", cli.clLoad);
115 | }
116 | }
--------------------------------------------------------------------------------
/src/main/java/org/fross/rpncalc/StackConstants.java:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------------------
2 | * RPNCalc
3 | *
4 | * RPNCalc is is an easy to use console based RPN calculator
5 | *
6 | * Copyright (c) 2011-2026 Michael Fross
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | * ------------------------------------------------------------------------------*/
27 | package org.fross.rpncalc;
28 |
29 | import org.fross.library.Output;
30 | import org.fusesource.jansi.Ansi;
31 |
32 | import java.math.BigDecimal;
33 | import java.math.MathContext;
34 | import java.math.RoundingMode;
35 |
36 | public class StackConstants {
37 | /**
38 | * cmdEulersConstant(): Add the Euler constant to the stack
39 | */
40 | public static void cmdEulersConstant(StackObj calcStack) {
41 | // Save current calcStack to the undoStack
42 | calcStack.saveUndo();
43 |
44 | calcStack.push("0.577215664901532860606512090082402431");
45 |
46 | Output.printColorln(Ansi.Color.CYAN, "Euler's constant (y) has been added to the stack");
47 | }
48 |
49 | /**
50 | * cmdEulersNumber(): Add the Euler number to the stack
51 | */
52 | public static void cmdEulersNumber(StackObj calcStack) {
53 | // Save current calcStack to the undoStack
54 | calcStack.saveUndo();
55 |
56 | calcStack.push("2.71828182845904523536028747135266249775724709369995");
57 |
58 | Output.printColorln(Ansi.Color.CYAN, "Euler's number (e) has been added to the stack");
59 | }
60 |
61 | /**
62 | * cmdPI(): Add the value of PI to the stack
63 | */
64 | public static void cmdPI(StackObj calcStack) {
65 | // Save current calcStack to the undoStack
66 | calcStack.saveUndo();
67 |
68 | calcStack.push("3.14159265358979323846264338327950288419716939937510");
69 |
70 | Output.printColorln(Ansi.Color.CYAN, "The value PI added to the stack");
71 | }
72 |
73 | /**
74 | * cmdPHI(): Add the value PHI (Golden Ratio) to the stack
75 | */
76 | public static void cmdPHI(StackObj calcStack) {
77 | BigDecimal phi = new BigDecimal("1.61803398874989");
78 | // Save current calcStack to the undoStack
79 | calcStack.saveUndo();
80 |
81 |
82 | // If there is something in the stack, display the long and short sections
83 | if (!calcStack.isEmpty()) {
84 | BigDecimal value = calcStack.peek();
85 | Output.printColorln(Ansi.Color.YELLOW, "If Long Section = " + value + " Short Section = " + value.multiply(BigDecimal.ONE.divide(phi, MathContext.DECIMAL128)).setScale(5, RoundingMode.HALF_UP));
86 | Output.printColorln(Ansi.Color.YELLOW, "If Short Section = " + value + " Long Section = " + value.multiply(phi).setScale(5, RoundingMode.HALF_UP));
87 | }
88 |
89 | // Add the value of Phi to the top of the stack
90 | calcStack.push(phi);
91 |
92 | Output.printColorln(Ansi.Color.CYAN, "Phi, the golden ratio, has been added to the stack");
93 | }
94 |
95 | /**
96 | * cmdSpeedOfLight(): Add the speed of light in meters/second to the stack
97 | */
98 | public static void cmdSpeedOfLight(StackObj calcStack) {
99 | // Save current calcStack to the undoStack
100 | calcStack.saveUndo();
101 |
102 | calcStack.push("299792458");
103 |
104 | Output.printColorln(Ansi.Color.CYAN, "Speed of Light (c) added to the stack");
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/org/fross/rpncalc/Display.java:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------------------
2 | * RPNCalc
3 | *
4 | * RPNCalc is is an easy to use console based RPN calculator
5 | *
6 | * Copyright (c) 2011-2026 Michael Fross
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | * ------------------------------------------------------------------------------*/
27 | package org.fross.rpncalc;
28 |
29 | import org.fross.library.Output;
30 | import org.fusesource.jansi.Ansi;
31 |
32 | import java.math.BigDecimal;
33 |
34 | import static org.fross.rpncalc.Main.configProgramWidth;
35 |
36 | public class Display {
37 |
38 | /**
39 | * Comma(BigDecimal): Add comma's to the integer portion and return a string
40 | *
41 | * @param bd Bid Decimal number to comma-ize
42 | */
43 | public static String Comma(BigDecimal bd) {
44 | String formatString = String.format("%%,.%df", bd.scale());
45 | return String.format(formatString, bd);
46 | }
47 |
48 | /**
49 | * queryDecimalIndex(): Return the index of the decimal in a string. If none is given assume it's at the end.
50 | *
51 | * @param str - String with or without a decimal point in it
52 | * @return An integer with the location of the decimal (or the end if it doesn't exist)
53 | */
54 | public static int queryDecimalIndex(String str) {
55 | // Determine where the decimal point is located. If no decimal exists (-1) assume it's at the end
56 | if (!str.contains("."))
57 | return str.length();
58 | else
59 | return str.indexOf(".");
60 | }
61 |
62 | /**
63 | * DisplayStatusLine(): Display the last line of the header and the separator line. This is a separate function given it also
64 | * inserts the loaded stack and spaces everything correctly.
65 | */
66 | public static void ShowStatusLine(StackObj calcStack) {
67 | // Format the number of memory slots used
68 | String sfMem = String.format("Mem:%02d", StackMemory.QueryInUseMemorySlots());
69 |
70 | // Format the undo level to 2 digits. Can't image I'd need over 99 undo levels
71 | String sfUndo = String.format("Undo:%02d", calcStack.undoSize());
72 |
73 | // Determine how many dashes to use after remove space for the undo and stack name
74 | int numDashes = configProgramWidth - 2 - sfMem.length() - sfUndo.length() - calcStack.queryStackName().length() - 11;
75 |
76 | // [Recording] appears if it's turned on. Make room if it's enabled
77 | if (UserFunctions.recordingIsEnabled()) numDashes -= 12;
78 |
79 | // Print the StatusLine dashes
80 | Output.printColor(Ansi.Color.CYAN, "+");
81 | Output.printColor(Ansi.Color.CYAN, "-".repeat(numDashes));
82 |
83 | // Print the StatusLine Data in chunks to be able to better control color output
84 | if (UserFunctions.recordingIsEnabled()) {
85 | Output.printColor(Ansi.Color.CYAN, "[");
86 | Output.printColor(Ansi.Color.RED, "Recording");
87 | Output.printColor(Ansi.Color.CYAN, "]-");
88 | }
89 | Output.printColor(Ansi.Color.CYAN, "[");
90 | Output.printColor(Ansi.Color.WHITE, sfMem);
91 | Output.printColor(Ansi.Color.CYAN, "]-[");
92 | Output.printColor(Ansi.Color.WHITE, sfUndo);
93 | Output.printColor(Ansi.Color.CYAN, "]-[");
94 | Output.printColor(Ansi.Color.WHITE, calcStack.queryStackName() + ":" + StackManagement.QueryCurrentStackNum());
95 | Output.printColor(Ansi.Color.CYAN, "]-");
96 | Output.printColorln(Ansi.Color.CYAN, "+");
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/mdbook/src/Chapters/Conversions.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Conversions
4 |
5 | The conversion commands will simply convert from one unit to another. As an example, I frequently use RPNCalc to convert from inches to millimeters or back.
6 |
7 | I've included the ones I use the most, but I'm happy to include others if you'd find something else useful.
8 |
9 | ## Fractional Display
10 |
11 | The RPNCalc stack only contains decimal numbers. Therefore, we can't directly store fractional values on the stack. If a fraction is entered, it is converted to a decimal.
12 | There could be a loss of precision when this is done. For example, there is no exact fractional equivalent for `PI` much like there is no exact decimal equivalent for `1/3`.
13 | However, the difference is usually so small that it's acceptable.
14 |
15 | The `frac [base]` command takes the item on the top of the stack (`line1`) and displays the approximate fractional equivalent. `[base]` sets the precision of the calculation.
16 | If a `base` is not provided, RPNCalc will use `64` (1/64) as the default.
17 |
18 | **For example**, if you had `1.1234` on the stack, `frac` would show you `1.1234 is approximately 1 1/8` No base was given so it would have used a base of 64 (which means
19 | maximum granularity would be 1/64) and auto reduced the result which is why you get the `1 1/8`.
20 |
21 | if `frac 5` would have been entered (which means 1/5 is maximum granularity), you get `1.1234 is approximately 1 1/5`.
22 |
23 | |
31 |
32 | I studied engineering in [college](https://purdue.edu/) and used the [HP 15C](https://hpcalcs.com/product/hp-15c-collectors-edition) calculator (I think that might date
33 | me...) I grew to love RPN and over the years I've used various GUI RPN
34 | calculators. However, I failed to find a simple command line version that I liked. Therefore, I decided to write one back in 2011.
35 |
36 | One key goal was to make it extensible, so I could easily add new features, constants, and
37 | capabilities. A second goal was to allow it to run everywhere I needed it to run, which is
38 | mostly Windows and Linux. Therefore, it's written in Java, it should run just about anywhere
39 | Java is supported. And, while this calculator doesn't have ***every*** function a complex
40 | scientific calculator would have, it has the basics well covered (along with a few oddball
41 | functions - I'm looking at you `dice`)
42 |
43 | Lastly, I didn't want to have a big uninstall/install task to upgrade to a new version. With RPNCalc, it's just one JAR file. You just run it
44 | (`java -jar rpncalc.jar`). Nothing to install or uninstall. If you want to remove it, just delete the `rpncalc.jar` file. You can now also use the SNAP version
45 | on supported operating systems which means you don't even need to install Java as it's built into the SNAP package.
46 |
47 |
48 | ## Contact Options & Links
49 |
50 | The home page for RPNCalc is located on [GitHub](https://github.com/frossm/rpncalc). It's open source with a **very** open usage license.
51 |
52 | - Report issues or enhancement requests, please post at the RPNCalc [issues page](https://github.com/frossm/rpncalc/issues)
53 | - For RPNCalc discussions, you can post on the [Discussion page](https://github.com/frossm/rpncalc/discussions)
54 | - The RPNCalc [Snap Store Page](https://snapcraft.io/rpncalc)
55 | - You can also reach me directly at `rpncalc@fross.org`
56 | - Checkout my other open source programs on [GitHub](https://github.com/frossm)
57 |
58 |
59 | ## The In-Line Help from RPNCalc
60 |
61 | From within the program, entering `h`, `help` or `?` will show the program help screen. The help can also be viewed by starting RPNCalc with the `-h` or `-?` command line switch (i.e. `rpncalc -h`)
62 |
63 | **Please note I do not update this screenshot with every release so it may be a bit dated.
64 | See the actual program for the up-to-date help screen.**
65 |
66 | The (mostly) current RPNCalc help screen:
69 |
--------------------------------------------------------------------------------
/src/main/java/org/fross/rpncalc/Browser.java:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------------------
2 | * RPNCalc
3 | *
4 | * RPNCalc is is an easy to use console based RPN calculator
5 | *
6 | * Copyright (c) 2011-2026 Michael Fross
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | * ------------------------------------------------------------------------------*/
27 | package org.fross.rpncalc;
28 |
29 | import org.fross.library.Output;
30 | import org.fusesource.jansi.Ansi.Color;
31 |
32 | import java.io.File;
33 | import java.io.IOException;
34 | import java.util.prefs.Preferences;
35 |
36 | public class Browser {
37 | static final Preferences prefConfig = Preferences.userRoot().node("/org/fross/rpn/config");
38 |
39 | /**
40 | * Launch(): Launch the defined browser to the provided URL
41 | *
42 | * @param url URL to the User Guide
43 | */
44 | protected static void Launch(String url) {
45 | String command = "";
46 |
47 | try {
48 | // Get the configured browser from prefs
49 | File browser = new File(prefConfig.get("browser", "none"));
50 |
51 | // Ensure the browser in prefs is valid
52 | if (!browser.canExecute()) {
53 | ConfigureBrowser("");
54 | browser = new File(prefConfig.get("browser", "none"));
55 | }
56 |
57 | // Set the command to execute
58 | command = browser.getAbsolutePath() + " " + url;
59 |
60 | Output.debugPrintln("Browser Command: '" + command + "'");
61 |
62 | // Open the browser
63 | Runtime.getRuntime().exec(command);
64 |
65 | } catch (IOException ex) {
66 | Output.printColorln(Color.RED, "ERROR: Could not launch browser: '" + command + "'");
67 | }
68 | }
69 |
70 | /**
71 | * ConfigureBrowser(): Sets the provided string as the configured browser assuming it's valid
72 | *
73 | * @param bName String of the full path to the local web browser
74 | */
75 | protected static void ConfigureBrowser(String bName) {
76 | // Ensure the provided path is a valid file
77 | if (new File(bName).canExecute()) {
78 | // Save this file as the browser in the config and return
79 | prefConfig.put("browser", bName);
80 | Output.printColorln(Color.CYAN, "Browser set to: '" + prefConfig.get("browser", "
2 |
3 | # What is an RPN Calculator?
4 |
5 | For me, the way I thought about using RPN back in the early 1990s was to approach it with `start on the inside and work your way out`. Just look at the inner most calculation, and start working yourself back out. It also helps if you also understand the order of operations for the operands.
6 |
7 | ### Order of Operations - *PEMA*
8 |
9 | |Order|Abbr|Description|
10 | |:---:|:--:|-----------|
11 | |#1|P|Parentheses First|
12 | |#2|E|Exponents - Powers and Square Roots, etc.|
13 | |#3|M|Multiplication and Division (left-to-right)|
14 | |#4|A|Addition and Subtraction (left-to-right)|
15 |
16 | ### Walkthrough of the Example from the Introduction Page
17 |
18 | `x = SQRT( ((((5+3) * 8)/2) * (2+1)) ^ 2 )`
19 |
20 | This can be tricky with a traditional calculator. However, with a RPN Calculator, to solve for x you would start on the inner calculation and work outwards. Looking at the equation, `5 + 3` is about the lowest so lets start there. The approach will be work back up until you get to a peer of the same "level". Then do the `2+1`. We'll walk through each step and explain what's happening. Go ahead and start RPNCalc and follow along - it's much easier to do it and see the stack rather than just reading it here.
21 |
22 | |Command|Explanation|
23 | |-------|-----------|
24 | |`c [Enter]`| Clear the stack if there is anything on it. Not really needed, but lets start off clean|
25 | |`5 [Enter]`| The top of the stack (`line1`) contains a 5|
26 | |`3 [Enter]`| 3 has been added to the top of the stack (`line1`) pushing 5 to `line2`|
27 | |`+ [Enter]`| 3 and 5 have been removed from the stack, added, and 8 pushed to `line1`|
28 | |`8 [Enter]`| 8 is added to `line1`, pushing the other 8 to `line2`|
29 | |`* [Enter]`| Remove 8 and 8 from the stack, multiply, and push 64 to `line1`|
30 | |`2 [Enter]`| Add 2 to the stack pushing down 64|
31 | |`/ [Enter]`| Divide 64 (`line2`) by 2 (`line1`) and replace those numbers with 32|
32 | |`2 [Enter]`| Add 2 to the stack|
33 | |`1 [Enter]`| Add 1 to the stack|
34 | |`+ [Enter]`| Add 2 and 1. They will be removed and 3 will be pushed to `line`|
35 | |`* [Enter]`| Multiply the 3 to the 32 you had in `line1` resulting in 96|
36 | |`2 [Enter]`| Add 2 to the stack|
37 | |`^ [Enter]`| Take `line2` to the power of `line1` resulting in 9,216|
38 | |`SQRT [Enter]`| Takes the square root of `line1` pushing the result to the stack|
39 |
40 | The result is 96 which ends up on the top (`line1`) of an otherwise empty stack. I'll talk more about stacks and how RPNCalc uses them in future chapters.
41 |
42 | *By the way, this can also be dramatically shortened using the `NumOps` shortcut - see the `Operands` chapter for more information.*
43 |
44 |
45 | ### Traditional RPN Notation Limitations in RPNCalc
46 |
47 | Please note that RPNCalc doesn't implement every RPN convention and there are a few as of yet unimplemented items.
48 |
49 | For example, this won't work in RPNCalc:
50 |
51 | `10 + 10 + 10` can't be solved by entering `10 [Enter] 10 [Enter] 10 [Enter] ++ [Enter]` as RPNCalc only allows one operand per command entry. You'll need an `[Enter]` between the last two `+` signs. Using the `NumOp` shortcut, this is an efficient way to solve that equation:
52 |
53 | `10 [Enter] 10+ [Enter] 10+ [Enter]`
54 |
55 |
2 |
3 | # High Level Usage
4 |
5 | RPNCalc is a command line application that must be run from a console / command prompt. Executing it with a `-h` (or `-?`) switch, or starting the program and entering
6 | the `h` (or `help` or `?`) command will display the in-program help page. This page lists all the commands and operands that can be used, but it is fairly terse This can be also viewed at the bottom of the `Introduction Chapter` of this guide. This document is meant as a more comprehensive guide.
7 |
8 | There are various command line switches that can be used when starting the program as are detailed in the `Command Line Options Chapter`. They generally exist so that aliases can be used to control several key parameters, most likely the `-l StackName` switch.
9 |
10 | Once inside the program, you'll be presented a prompt where numbers, operands, and commands may be entered. Numbers will be added to the stack which you can think of as an upside down stack of plates. The top stack item (represented by `line1` in the program) is on the bottom. You can think of this stack of plates as a Last In First Out (LIFO) approach.
11 |
12 | For example, you could enter `2 [ENTER]` it would be in the `line1` position and would be on the top of the stack. If you then enter `3 [ENTER]` the `2` would move up go `line2` and the `3` would then be on `line1` and be on the top of the stack. You can then enter an operand, such as `+` to perform the action on the items opn the top of the stack. To continue our example, pressing `+ [ENTER]` would take the top two items off of the stack, add them, and put the result back on top of the stack (`line1`).
13 |
14 | I've gone into this in more detail in the `What is an RPN Calculator Chapter` and elsewhere and it's fairly easy and intuitive. Once you get the hang of it, you will regret having to use a standard calculator in the future. ;-)
15 |
16 | #### Why is the stack "upside down?"
17 |
18 | One question I get with RPNCalc is why is the top of the stack on the bottom? The reason is that it's simply more intuitive. The command line is on the bottom. You are usually dealing with the top of the stack so having `line1` directly above makes sense. Also, for some operations, the order is important (think subtraction or division). Having `line1` "underneath" `line2` is easy to understand as that's how we learned to do subtraction. `line1` is subtracted from `line2`.
19 |
20 | ### Decimals & Fractions
21 |
22 | In RPNCalc, the stacks always store numbers as decimals. You can, however, enter in fractions, and they will be instantly converted to a decimal equivalent and added to
23 | the stack.
24 |
25 | **Example:**
26 |
27 | `1 5/16 [ENTER]`
28 |
29 | will add `1.3125` to the top of the stack (`line1`)
30 |
31 | `14/8 [ENTER]`
32 |
33 | will add `1.75` to the stack
34 |
35 | While you can never directly convert a decimal number on the stack back to a fraction, you can display an approximation of what the top of the stack (`line1`) value would be as a fraction. You do have to decide on the smallest denominator that will be used (called the base.) The default base is `64` which is the equivalent of `1/64` and will be used if no base is specified. Use the `frac [base]` command to display the approximate fractional equivalent. RPNCalc will simplify the fraction as much as it can so if `line1` is `0.5`, the command `frac 4` won't convert and display `2/4`. The result would be `1/2`. Also note that `frac [based]` is a display command and will not actually change the stack in any way.
36 |
37 | **Example:**
38 | `12.3456 [Enter]`
39 | `frac [Enter]`
40 |
41 | No base was entered, so use `64`. It will display `12 11/32` RPNCalc converted it to `12 22/64` and then reduced it.
42 |
43 | `1 3/64 [Enter]`
44 | `frac 16 [Enter]`
45 |
46 | will display `1 1/16` as that's as close as it could get with a granularity of 1/16.
47 |
48 | `1 3/64 [ENTER]`
49 | `frac 100000`
50 |
51 | will display `1 293/6250`. This is a closer approximation than using base 16. This also shows why this is an approximate.
52 |
53 | ### Scientific Notation
54 |
55 | As of version 5, scientific notation is supported. You can enter in values with the format `1.2345E18` and it will be saved as a value in the stack. There are a few areas where it's not 100% supported (i.e. NumOps at the time of this writing) but just about everything will work with it.
56 |
57 | ### Percent Entry
58 |
59 | As of version 5.4.0, a number, followed by a `%` can be entered. This will be divided by 100 prior to being added onto the stack. This will work with both negative
60 | numbers and scientific notation.
61 |
62 | ## Operands, Numbers, and Commands
63 |
64 | Numbers, whether decimal or fractions, can be entered on the command line, and they get added to the stack. That's fairly self-explanatory.
65 |
66 | Operands perform basic match functions on those numbers.
67 |
68 | Commands do the more exciting things. You can add the speed of light constant to the stack (`sol`) or PI (`pi`), take the sine of the number, add it to a memory slot, and then save that sequence of commands as a user defined function. Most of the rest of this guide will be talking about the various RPNCalc commands.
69 |
70 | Lastly, as of `v4.6.0`, the arrow keys can be used within RPNCalc. Up/Down will move you through your historical entries, and Left/Right will move you within the current command line. This is probably what you would have expected it to do as it behaves similar to common consoles.
71 |
72 | ## Precision
73 | The intent of RPNCalc is to have unlimited precision in the numbers and calculations. RPNCalc leverages a Java technology called `BigDecimal` which limits precision only by the amount of memory in your machine. This is most likely more than you will ever need. However, the program does make use of several Java math methods which must be done via a Java `Double`.
74 |
75 | A `Double` has the following characteristics:
76 | - The upper range of a double in Java is `1.7976931348623157 x 10^308`
77 | - The lower range of a double in Java is `4.9 x 10^-324`
78 |
79 | I will attempt to point out in this guide when a command is using `Double` and therefore has a limit on precision. Double is, however, huge and shouldn't pose an issue for most use cases.
--------------------------------------------------------------------------------
/src/main/java/org/fross/rpncalc/StackTrig.java:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------------------
2 | * RPNCalc
3 | *
4 | * RPNCalc is is an easy to use console based RPN calculator
5 | *
6 | * Copyright (c) 2011-2026 Michael Fross
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | * ------------------------------------------------------------------------------*/
27 | package org.fross.rpncalc;
28 |
29 | import org.fross.library.Output;
30 | import org.fusesource.jansi.Ansi;
31 |
32 | public class StackTrig {
33 | /**
34 | * cmdArcTrig(): Calculate the arc Trig functions. There was so much overlap in the functions I consolidated
35 | *
36 | * @param calcStack Primary Stack
37 | * @param cmd Command entered
38 | * @param arg Parameters after the command
39 | */
40 | public static void cmdArcTrig(StackObj calcStack, String cmd, String arg) {
41 | // Ensure we have at least one item on the stack
42 | if (calcStack.isEmpty()) {
43 | Output.printColorln(Ansi.Color.RED, "ERROR: Must be at least one item on the stack");
44 | return;
45 | }
46 |
47 | double result;
48 | double originalValue;
49 |
50 | originalValue = calcStack.peek().doubleValue();
51 |
52 | // Save current calcStack to the undoStack
53 | calcStack.saveUndo();
54 |
55 | // Calculate the arc trig function
56 | switch (cmd) {
57 | case "asin":
58 | result = java.lang.Math.asin(calcStack.pop().doubleValue());
59 | break;
60 |
61 | case "acos":
62 | result = java.lang.Math.acos(calcStack.pop().doubleValue());
63 | break;
64 |
65 | case "atan":
66 | result = java.lang.Math.atan(calcStack.pop().doubleValue());
67 | break;
68 |
69 | default:
70 | Output.printColorln(Ansi.Color.RED, "ERROR: Unknown command: '" + cmd + "'");
71 | calcStack.push(originalValue);
72 | return;
73 | }
74 |
75 | try {
76 | // Display value in degrees or if 'rad' is a parameter, as radians
77 | if (arg.toLowerCase().charAt(0) == 'r') {
78 | calcStack.push(result);
79 | } else {
80 | calcStack.push(originalValue);
81 | Output.printColorln(Ansi.Color.RED, "ERROR: unknown " + cmd + " parameter: '" + arg + "'");
82 | }
83 |
84 | } catch (StringIndexOutOfBoundsException ex) {
85 | calcStack.push(java.lang.Math.toDegrees(result));
86 | }
87 | }
88 |
89 | /**
90 | * cmdHypotenuse(): Calculates the hypotenuse by pulling the top two stack items and using them as the triangle legs
91 | *
92 | * @param calcStack Primary Stack
93 | */
94 | public static void cmdHypotenuse(StackObj calcStack) {
95 | // Ensure we have two items on the stack
96 | if (calcStack.size() < 2) {
97 | Output.printColorln(Ansi.Color.RED, "ERROR: There must be two items on the stack to calculate the hypotenuse");
98 | return;
99 | }
100 |
101 | // Save current calcStack to the undoStack
102 | calcStack.saveUndo(); // Save current calcStack to the undoStack
103 |
104 | // Pop the two values and push the hypotenuse back onto the stack
105 | calcStack.push(java.lang.Math.hypot(calcStack.pop().doubleValue(), calcStack.pop().doubleValue()));
106 | }
107 |
108 | /**
109 | * cmdTrig(): Calculate the trig functions. There was so much overlap in the functions I consolidated the operations together
110 | *
111 | * @param calcStack Primary Stack
112 | * @param cmd Command entered
113 | * @param arg Parameters after the command
114 | */
115 | public static void cmdTrig(StackObj calcStack, String cmd, String arg) {
116 | // Ensure we have at least one item on the stack
117 | if (calcStack.isEmpty()) {
118 | Output.printColorln(Ansi.Color.RED, "ERROR: Must be at least one item on the stack");
119 | return;
120 | }
121 |
122 | double angle = 0.0;
123 |
124 | try {
125 | angle = calcStack.pop().doubleValue();
126 |
127 | // Calculations are done in radians. Convert if 'rad' is NOT provided as a parameter
128 | if (arg.toLowerCase().charAt(0) != 'r') {
129 | Output.printColorln(Ansi.Color.RED, "ERROR: unknown " + cmd + " parameter: '" + arg + "'");
130 | calcStack.push(angle);
131 | return;
132 | }
133 | } catch (StringIndexOutOfBoundsException ex) {
134 | angle = java.lang.Math.toRadians(angle);
135 | }
136 |
137 | // Save current calcStack to the undoStack
138 | calcStack.saveUndo();
139 |
140 | // Push the result back onto the stack
141 | switch (cmd) {
142 | case "tan":
143 | calcStack.push(java.lang.Math.tan(angle));
144 | break;
145 |
146 | case "sin":
147 | calcStack.push(java.lang.Math.sin(angle));
148 | break;
149 |
150 | case "cos":
151 | calcStack.push(java.lang.Math.cos(angle));
152 | break;
153 |
154 | default:
155 | Output.printColorln(Ansi.Color.RED, "ERROR: Could not understand trig command: '" + cmd + "'");
156 | }
157 | }
158 |
159 | }
160 |
--------------------------------------------------------------------------------
/src/main/java/org/fross/rpncalc/Configuration.java:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------------------
2 | * RPNCalc
3 | *
4 | * RPNCalc is is an easy to use console based RPN calculator
5 | *
6 | * Copyright (c) 2011-2026 Michael Fross
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | * ------------------------------------------------------------------------------*/
27 | package org.fross.rpncalc;
28 |
29 | import org.fross.library.Output;
30 | import org.fusesource.jansi.Ansi;
31 |
32 | import java.util.prefs.Preferences;
33 |
34 | public class Configuration {
35 | /**
36 | * set(): Set configuration Options
37 | */
38 | public static void cmdSet(String arg) {
39 | Preferences prefConfig = Preferences.userRoot().node("/org/fross/rpn/config");
40 | String command;
41 | String value;
42 |
43 | // If there is not a parameter provided, display the current values and return
44 | if (arg.isBlank()) {
45 | Output.printColorln(Ansi.Color.YELLOW, "\n-Configuration Values" + "-".repeat(Main.configProgramWidth - 21));
46 | Output.printColorln(Ansi.Color.CYAN, String.format("Width: %02d\t| Sets the program width in characters", Main.configProgramWidth));
47 | Output.printColorln(Ansi.Color.CYAN, "Align: " + Main.configAlignment + "\t| Set display alignment. Values: (l)eft, (d)ecimal, (r)ight");
48 | Output.printColorln(Ansi.Color.CYAN, String.format("MemSlots: %02d\t| Sets number of available memory slots", Main.configMemorySlots));
49 | Output.printColorln(Ansi.Color.CYAN, "Browser Path: " + prefConfig.get("browser", "
2 |
3 | # Configuration
4 | There are a few, although not many, configuration options available in RPNCalc. These are settings which control various aspects of the program and are persistent between executions. When these are changed, they are saved in the Java Preferences system.
5 |
6 | There are currently three configuration options that can be changed the commands to do so are listed below. They are:
7 |
8 | #### Program Width
9 | Program Width controls the amount of characters the base program uses. This can be changed and is especially useful if using a terminal with a small number of characters per line.
10 |
11 | #### Memory Slots
12 | By default there are 10 memory slots numbers 0 through 9. This is probably more than most people would need, but if you save a lot of values, or have a User Defined Function that needs to store a lot of numbers, it can be changed. Each memory slot is simply an additional array element, so I don't think there is much of a memory impact, but I suppose if you have thousands it would increase memory usage.
13 |
14 | #### Display Alignment
15 | By default, the numbers displayed on the stack are left aligned. There are times when it is prefered to be right aligned (for example if you are working with money and always want two decimal places), or decimal aligned which is nice to easily see the integer from the decimal. Play around with it and see which one you like for difference circumstances.
16 |
17 |
18 | #### Reset
19 | Ok, this isn't really a configuration option, but the command can be used to reset everything back to the defaults. At the time of this writing, the defaults are:
20 | - Program Width: `80` Current minimum width is `46` characters
21 | - Memory Slots: `10` Numbered `0` through `9`
22 | - Display Alignment: `l(eft)`
23 |
24 | |
2 |
3 | # User Defined Functions
4 |
5 | RPNCalc can record your commands and save them as a user defined function. In essence, you are creating a new command that can be run.
6 |
7 | When recording a new function, start by adding data to your stack that would emulate when you would run your function. The only data that will be part of your recording will be data & commands entered ***after*** recording has been turned on. When you are ready, enter the `record on` command. A red `[Recording]` alert will appear in the status line. Anything you add during this period will be recorded with the exception of the commands listed below. Enter your commands, numbers, etc. until you are done.
8 |
9 | When recording is complete, enter `record off` to complete your recording. You'll be prompted for a function name. Your new command will be this name so choose a name without spaces and that is easy to type when you wish to execute the function in the future. You should also not choose a name of an existing command as your function will not be able to be called. If you do not provide a name, i.e, just hit enter, the recording will be discarded.
10 |
11 | Then you can run your function whenever you like on the stack currently available. To run the function, simply type the name of your function as a standard command. To
12 | see a list of the saved functions, execute `list func` and it will display the name and the steps you recorded.
13 |
14 | User defined functions can be deleted with the `func del NAME` command or you can delete all of the functions with `func delall`
15 |
16 | Functions are global and can work across any stack. They are saved in the preferences system and will be reloaded when RPNCalc starts. They are saved immediately after you give a new recording a name and press enter.
17 |
18 | When you execute a function, the steps of that function are executed one after the other. Therefore when you execute `undo` you will undo back through your function step
19 | by step. You do not `undo` the entire function in one command. Of course, you can always run `undo NUM` where `NUM` is the steps to undo.
20 |
21 | The following commands can be entered during a recording, but are not recorded.
22 | - list
23 | - debug
24 | - ver, version
25 | - help, h, ?
26 | - rec, record
27 | - func, function
28 | - set, reset
29 | - cx, x, quit, exit
30 |
31 | |