├── .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 | 5 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /snap/local/rpncalc-wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Runs RPNCalc as a bash script with the needed options 4 | # 5 | exec "$SNAP"/bin/java -Djava.util.prefs.userRoot="$SNAP_USER_DATA" -Dorg.jline.terminal.dumb=true -jar "$SNAP"/jar/rpncalc.jar "$@" 6 | -------------------------------------------------------------------------------- /.idea/statistic.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | mdbook/RPNCalc-UserGuide 2 | target/ 3 | build/ 4 | pom.xml.tag 5 | pom.xml.releaseBackup 6 | pom.xml.versionsBackup 7 | pom.xml.next 8 | *.md.backup 9 | release.properties 10 | dependency-reduced-pom.xml 11 | buildNumber.properties 12 | .mvn/timing.properties 13 | .mvn/wrapper/maven-wrapper.jar 14 | .README.md.html 15 | .pydevproject 16 | -------------------------------------------------------------------------------- /mdbook/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | title = "RPNCalc User Guide" 3 | authors = ["Michael Fross"] 4 | description = "The RPNCalc User Guide" 5 | language = "en" 6 | src = "src" 7 | 8 | [build] 9 | build-dir = "RPNCalc-UserGuide" 10 | create-missing = true 11 | use-default-preprocessors = true 12 | 13 | [output.html] 14 | default-theme = "ayu" 15 | preferred-dark-theme = "ayu" 16 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /mdbook/src/Chapters/Wrapup.md: -------------------------------------------------------------------------------- 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 |

Readme Header

2 |

Post It

3 | 4 |

A User Guide for the RPNCalc Calculator

5 | 6 |

Copyright 2011- 2024 by Michael Fross
7 | This document, along RPNCalc, is licensed under the MIT License

8 | 9 |

10 | The RPNCalc GitHub Homepage 11 |

12 | 13 |
14 |

15 | UsersLoveUsUsersLoveUs 16 |

-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Banner

2 | 3 | # INTRODUCTION 4 | 5 | RPNCalc is the command-line based Reverse Polish Notation (RPN) calculator. RPN calculators make it very simple to do complex calculations, especially if there are parentheses involved. 6 | 7 | I've created a detailed [User Guide](https://frossm.github.io/RPNCalc-UserGuide) to do a better job of explaining how to use RPNCalc. If you have questions, issues, feedback, or ideas, please let me know. You can contact me via the links in the **Introduction** page of the User Guide. 8 | 9 | # [RPNCalc User Guide](https://frossm.github.io/RPNCalc-UserGuide/) 10 | 11 |
12 | 13 | The (somewhat) current RPNCalc help screen: 14 | 15 | Screen Shot1 16 | Screen Shot2 -------------------------------------------------------------------------------- /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 | |
Command
|Description| 10 | |-------|-----------| 11 | |sin [rad]
cos [rad]
tan [rad]|Calculate the [trigonometry](https://en.wikipedia.org/wiki/Trigonometry) function requested. Angles are input as degrees by default unless the optional `rad` parameter is given in which case the angles will be in [radians](https://en.wikipedia.org/wiki/Radian).

**Example:** `tan` will calculate the tangent using `line1` as the angle in degrees. Use `tan rad` if `line1` contains the angle in radians| 12 | |asin [rad]
acos [rad]
atan [rad]|Calculate the arc [trigonometry](https://en.wikipedia.org/wiki/Trigonometry) function. Like the above, the result is returned in degrees unless `rad` parameter is provided| 13 | |hypot
hypotenuse| Assumes the top two stack items are the right triangle' legs and this function returns the hypotenuse using the [Pythagorean theorem](https://en.wikipedia.org/wiki/Pythagorean_theorem). Specifically, it returns SQRT( (`line1`^2 + `line2`^2 )). The hypotenuse will replace the values of the two legs on the stack| -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /src/test/java/org/fross/library/DebugTest.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.junit.jupiter.api.Assertions.*; 30 | 31 | import org.junit.jupiter.api.Test; 32 | 33 | /** 34 | * @author Michael Fross (michael@fross.org) 35 | * 36 | */ 37 | class DebugTest { 38 | 39 | @Test 40 | void test() { 41 | // Should be false as Debug has not been enabled 42 | assertFalse(Debug.query()); 43 | 44 | // Turn on Debugging 45 | Debug.enable(); 46 | assertTrue(Debug.query()); 47 | 48 | // Turn it back off 49 | Debug.disable(); 50 | assertFalse(Debug.query()); 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /mdbook/src/Chapters/CommandLineOptions.md: -------------------------------------------------------------------------------- 1 | 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 | |
Option
|Name|Description| 10 | |------|----|-----------| 11 | |-D
--debug| `DEBUG MODE`| Runs the program in debug mode. This will display quite a bit of information in RED as you use the program. This is mostly used by the developer and clutters everything up, but you may find it useful if you are trying to debug something. I could certainly add a lot more if needed, but it's useful today. You can also toggle debug mode on/off by entering in the command `debug` while within the program - you don't have to restart RPNCalc| 12 | |-l `name`
--load `name`|`LOAD STACK`| Load a saved stack. This essentially will "name" your session and store the stack upon exit in the Java preferences system. You can load the stack with the `-l name` command line option, or from within the program by using the `load name` command. Please note the name field is whatever you want to call the instance but avoid spaces in the name. I'm not aware of a limit to the number of saved stacks You can have. If the name to load does not exist, the stack will be created and saved when you exit.| 13 | |-z
--no-color| `DISABLE COLOR`| Disable colorized output. Useful if your current terminal doesn't support ANSI color sequences| 14 | |-L
--license| `DISPLAY LICENSE`| Display the RPNCalc usage license. Currently, RPNCalc uses the [The MIT License](https://opensource.org/licenses/MIT)| 15 | |-v
--version| `VERSION`| This will display the current program version, but will also check GitHub for the leatest release. It is possible, especially if you are using RPNCalc as a Snap, to have a later version than the latest GitHub release.| 16 | |-h
-?
--help| `HELP`| Display the program help page and exit. This is the same as the `h` or `help` command within RPNCalc| -------------------------------------------------------------------------------- /mdbook/src/Chapters/BuildingRPNCalc.md: -------------------------------------------------------------------------------- 1 | 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 | |
Command
|Description| 14 | |-------|-----------| 15 | |mem [slot] add|`mem X add`
Will add the top stack item (`line1`) into the memory slot X. By default, there are 10 slots; 0 through 9. If you do not provide a slot number it will default to `slot0`
Example: `mem add` will add the contents of `line1` into memory `slot0`| 16 | |mem [slot] copy
mem [slot] recall|`mem X copy`
Copies the contents of memory slot provided back onto the stack. Defaults to `slot0` if no slot number is provided| 17 | |mem [slot] clr|`mem X clr`
Clear the contents of the memory slot provided. Defaults to Slot0 if no slot is provided. Example: `mem 2 clr` The command `clear` can also be used instead of `clr`| 18 | |mem clearall|`mem clearall`
Clears the contents of all memory slots. There is no need to include a SlotNumber as they will all be erased. Note `mem clrall` will also work| 19 | |mem copyall|`mem copyall`
Copy all items from the memory slots onto the stack. These will be ordered via memory slot number. i.e. Memory slot 0 will be at the top of the stack / `line1`. `recallall` will also work| 20 | |mem addall|`mem addall`
Add all items in the stack to a memory slot. The order will be the same as the stack with memory slot0 being the top of the stack. The command will fail if there are more stack items than there are memory slots - which default to 10. It may simply be easier to save the stack with a name using the load `-l` command. Also, any values currently in a needed memory slot will be silently overwritten| -------------------------------------------------------------------------------- /src/main/java/org/fross/library/GitHub.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 java.util.regex.Matcher; 30 | import java.util.regex.Pattern; 31 | 32 | public class GitHub { 33 | /** 34 | * latestRelease: Query GitHub's tag API and determine the latest release of the application 35 | * 36 | * Examples of application names would be "quoter" or "rpncalc" 37 | * 38 | * @param applicationName 39 | * @return 40 | */ 41 | public static String updateCheck(String app) { 42 | String finalURL = "https://api.github.com/repos/frossm/" + app + "/tags"; 43 | String returnString = null; 44 | 45 | Output.debugPrintln("URL for UpdateCheck: " + finalURL); 46 | 47 | try { 48 | // Read the tags from the GitHub Tags API 49 | String githubPage = URLOperations.ReadURL(finalURL); 50 | 51 | // Pull out the latest version 52 | Pattern pattern = Pattern.compile("name.: *\"(.*?)\"", Pattern.CASE_INSENSITIVE); 53 | Matcher matcher = pattern.matcher(githubPage); 54 | 55 | if (matcher.find()) { 56 | returnString = matcher.group(1); 57 | } else { 58 | throw new Exception(); 59 | } 60 | } catch (Exception ex) { 61 | returnString = "Unable to determine latest release"; 62 | } 63 | 64 | return returnString; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /mdbook/src/Chapters/Operands.md: -------------------------------------------------------------------------------- 1 | 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 |
35 |
36 |
37 | 38 | `Hint:` We'll discuss commands in later chapters, but the `swap` command `s` will swap the top two items in the stack (`line1` and `line2`). Swap will also swap any two line numbers provided. See the `Calculator Commands Chapter` for more information. 39 | 40 | ## The NumOps Shortcut 41 | 42 | RPNCalc has an important shortcut that can speed up your calculations. You can append one of the above operands at the end of an entered number and the program will, behind the scenes, place the number on top of the stack (`line1`) and then execute the operand. The operand must directly follow the number without a space between. For example: 43 | 44 | `2 [ENTER]` 45 | 46 | `3+ [ENTER]` 47 | 48 | When the second enter is pressed, the two stack items will be removed, added together, and the result, `5`, will be added back. It's the same as entering this the following three commands: 49 | 50 | `2 [ENTER]` 51 | 52 | `3 [ENTER]` 53 | 54 | `+ [ENTER]` 55 | 56 | As an example of this NumOps shortcut, see the following example: 57 | 58 | `x = SQRT((((5+3) * 8)/2) ^ 6)` 59 | 60 | Leveraging the shortcut, this would become: 61 | 62 | - `5` 63 | - `3+` 64 | - `8*` 65 | - `2/` 66 | - `6^` 67 | - `SQRT` 68 | 69 | By the way, if you were wondering the answer is 32,768. 70 | 71 | ***Please note that you can not use this NumOps shortcut with a fractional number entry or a scientific notation entry*** -------------------------------------------------------------------------------- /snap/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: rpncalc 2 | title: RPNCalc 3 | version: '5.11.03' 4 | summary: The command-line Reverse Polish Notation (RPN) calculator 5 | description: | 6 | RPNCalc is the command-line based Reverse Polish Notation (RPN) calculator. 7 | RPN calculators make it very simple to do complex calculations, especially 8 | if there are parentheses involved. In essence, you enter your numbers first, 9 | and then the operator. 10 | 11 | So, to add 2 and 3 to get 5, you would first add the number 2 to the stack. 12 | Then you would add 5 to the stack (pushing the 2 to the second position.) 13 | Now, to add them you would enter + and RPNCalc would remove the 2 and 3 14 | from the stack, add them, and push 5 back onto the stack. 15 | 16 | There is a very large collection of functions that can be used. Trig functions, 17 | statistical functions, user defined functions, multiple stacks, constants, etc. 18 | 19 | For a quick summary of RPNCalc usage, run the program with the -h switch or enter `h` 20 | within the program. 21 | 22 | Please take a look at the User guide for detailed information on what 23 | RPNCalc is and how to use it. Once you use an RPN calculator, 24 | it's hard to go back to a traditional one. 25 | 26 | Homepage: https://github.com/frossm/rpncalc 27 | RPNCalc user guide: https://frossm.github.io/RPNCalc-UserGuide 28 | 29 | grade: stable 30 | confinement: strict 31 | base: core24 32 | type: app 33 | 34 | website: https://github.com/frossm/rpncalc 35 | contact: rpncalc@fross.org 36 | issues: https://github.com/frossm/rpncalc/issues 37 | icon: graphics/PostIt.svg 38 | license: MIT 39 | 40 | platforms: 41 | amd64: 42 | arm64: 43 | armhf: 44 | # s390x: 45 | # ppc64el: 46 | 47 | # Enable faster LZO decompression 48 | compression: lzo 49 | 50 | apps: 51 | rpncalc: 52 | command: rpncalc-wrapper 53 | plugs: 54 | - network 55 | - home 56 | 57 | parts: 58 | wrapper: 59 | plugin: dump 60 | source: snap/local 61 | source-type: local 62 | 63 | rpncalc: 64 | plugin: maven 65 | source: https://github.com/frossm/rpncalc.git 66 | source-branch: master 67 | source-type: git 68 | maven-parameters: 69 | # Having issues with the tests at SnapCraft. Skip this as they have all passed locally. 70 | - package -DskipTests 71 | 72 | build-packages: 73 | - maven 74 | - openjdk-17-jdk-headless 75 | 76 | stage-packages: 77 | - openjdk-17-jre-headless 78 | 79 | # Bypass a build issue where an absolute reference is made to a file outside the snap filesystem 80 | # Ref: https://forum.snapcraft.io/t/resolve-package-contains-external-symlinks-error-when-trying-to-snap/2963/23 81 | override-prime: | 82 | craftctl default 83 | rm -vf usr/lib/jvm/java-17-openjdk-*/lib/security/blacklisted.certs 84 | -------------------------------------------------------------------------------- /mdbook/src/Chapters/Installation.md: -------------------------------------------------------------------------------- 1 | 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 | [![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](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 | Page Icon 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**
[Archimedes' constant, or PI](https://en.wikipedia.org/wiki/Pi), is the name given to the ratio of the circumference of a circle to the diameter. `PI` inserts the value of PI onto the stack. In RPNCalc, Pi is calculated to 50 decimal places `3.14159265358979323846264338327950288419716939937510` | 13 | | phi | **PHI - THE GOLDEN RATIO**
If the stack is empty, `phi` will simply insert the [PHI](https://en.wikipedia.org/wiki/Golden_ratio), also known as the Golden Ratio, onto the top of the stack (`line1`). In RPNCalc, Phi is defined as `1.618033989`
However, if there is an item on the stack, it will also display the possible long and short section values | 14 | | eulersnum
eulersnumber | **EULER'S NUMBER**
Euler's number is also known as the exponential growth constant. It is the base for natural logarithms and is found in many areas of mathematics. The command `euler` inserts [Euler's number (e)](https://en.wikipedia.org/wiki/E_(mathematical_constant)) onto the stack. e is calculated to 50 deciaml places `2.71828182845904523536028747135266249775724709369995` | 15 | | eulersconst
eulersconstant | **EULER'S CONSTANT**
[Euler's constant](https://en.wikipedia.org/wiki/Euler%27s_constant#:~:text=The%20numerical%20value%20of%20Euler's,Is%20Euler's%20constant%20irrational%3F) (sometimes called the Euler–Mascheroni constant) is a mathematical constant, usually denoted by the lowercase Greek letter gamma (γ), defined as the limiting difference between the harmonic series and the natural logarithm. Euler's Constant is represented in RPNCalc to 36 decimal places `0.57721566490153286060651209008240243` 16 | | sol | **SPEED OF LIGHT**
Inserts the [speed of light](https://en.wikipedia.org/wiki/Speed_of_light), in meters per second, onto the stack. RPNCalc uses `299,792,458 m/s` as the speed of light | 17 | -------------------------------------------------------------------------------- /src/main/java/org/fross/library/Debug.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 | /** 30 | * Debug contains static methods to maintain the debug state and display messages when enabled. 31 | * 32 | * @author michael.d.fross 33 | * 34 | */ 35 | public class Debug { 36 | // Class Variables 37 | private static boolean clDebug = false; 38 | 39 | /** 40 | * Query(): Query current state of this object's debug setting 41 | * 42 | * @return 43 | */ 44 | public static boolean query() { 45 | return clDebug; 46 | } 47 | 48 | /** 49 | * Enable(): Turn debugging on for this object 50 | */ 51 | public static void enable() { 52 | clDebug = true; 53 | } 54 | 55 | /** 56 | * Disable(): Disable debugging for this object 57 | */ 58 | public static void disable() { 59 | clDebug = false; 60 | } 61 | 62 | /** 63 | * displaySysInfo(): Display some system level information used in Debug Mode 64 | */ 65 | public static void displaySysInfo() { 66 | Output.debugPrintln("------------------------------------------------------------"); 67 | Output.debugPrintln("System Information:"); 68 | Output.debugPrintln(" - class.path: " + System.getProperty("java.class.path")); 69 | Output.debugPrintln(" - java.home: " + System.getProperty("java.home")); 70 | Output.debugPrintln(" - java.vendor: " + System.getProperty("java.vendor")); 71 | Output.debugPrintln(" - java.version: " + System.getProperty("java.version")); 72 | Output.debugPrintln(" - os.name: " + System.getProperty("os.name")); 73 | Output.debugPrintln(" - os.version: " + System.getProperty("os.version")); 74 | Output.debugPrintln(" - os.arch: " + System.getProperty("os.arch")); 75 | Output.debugPrintln(" - user.name: " + System.getProperty("user.name")); 76 | Output.debugPrintln(" - user.home: " + System.getProperty("user.home")); 77 | Output.debugPrintln(" - user.dir: " + System.getProperty("user.dir")); 78 | Output.debugPrintln(" - file.separator: " + System.getProperty("file.separator")); 79 | Output.debugPrintln(" - library.path: " + System.getProperty("java.library.path")); 80 | Output.debugPrintln("------------------------------------------------------------"); 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /mdbook/src/Chapters/Acknowledgements.md: -------------------------------------------------------------------------------- 1 | 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 |
64 | 65 |
66 | 67 |
-------------------------------------------------------------------------------- /src/main/java/org/fross/library/URLOperations.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 java.io.BufferedInputStream; 30 | import java.io.BufferedReader; 31 | import java.io.FileOutputStream; 32 | import java.io.IOException; 33 | import java.io.InputStreamReader; 34 | import java.net.URL; 35 | 36 | public class URLOperations { 37 | 38 | /** 39 | * ReadURL: Retrieve data from a website 40 | * 41 | * @param urlString 42 | * @return 43 | * @throws Exception 44 | */ 45 | public static String ReadURL(String urlString) throws Exception { 46 | BufferedReader reader = null; 47 | 48 | try { 49 | URL url = new URL(urlString); 50 | reader = new BufferedReader(new InputStreamReader(url.openStream())); 51 | StringBuilder buffer = new StringBuilder(); 52 | int read; 53 | char[] chars = new char[1024]; 54 | while ((read = reader.read(chars)) != -1) { 55 | buffer.append(chars, 0, read); 56 | } 57 | 58 | return buffer.toString(); 59 | 60 | } finally { 61 | if (reader != null) { 62 | reader.close(); 63 | } 64 | } 65 | } 66 | 67 | /** 68 | * DownloadFileFromURL(): Download a file from a URL to the provided directory 69 | * 70 | * @param urlStr 71 | * @param file 72 | * @throws IOException 73 | */ 74 | public static void DownloadURLToFile(String urlStr, String file) throws IOException { 75 | final int blockSize = 1024; 76 | URL url = new URL(urlStr); 77 | BufferedInputStream bis = new BufferedInputStream(url.openStream()); 78 | FileOutputStream fos = new FileOutputStream(file); 79 | byte[] buffer = new byte[blockSize]; 80 | int count = 0; 81 | 82 | // Download chunks of the file and write them out 83 | while ((count = bis.read(buffer, 0, blockSize)) != -1) { 84 | fos.write(buffer, 0, count); 85 | } 86 | 87 | // Cleanup by closing the streams 88 | fos.close(); 89 | bis.close(); 90 | } 91 | 92 | /** 93 | * main(): Used for testing DownloadFileFromURL() 94 | * 95 | * @param args 96 | */ 97 | public static void main(String[] args) { 98 | String url = args[0]; 99 | String fullFilePathAndName = args[1].replace('\\', '/'); 100 | 101 | // Download Test 102 | try { 103 | System.out.println("Testing URL Download to File:"); 104 | System.out.println(" Downloading: " + url); 105 | System.out.println(" Destination: " + fullFilePathAndName); 106 | DownloadURLToFile(url, fullFilePathAndName); 107 | } catch (IOException ex) { 108 | System.out.println("An IO Error Occured: Arguments are URL, DownloadedFilePath\n" + ex.getMessage()); 109 | } 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/org/fross/rpncalc/CommandHistory.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 java.util.Stack; 30 | 31 | public class CommandHistory { 32 | // Class Variables 33 | static final Stack cmdHistory = new Stack<>(); 34 | 35 | /** 36 | * addCommand(): Add a command to the command history 37 | * 38 | * @param cmdInput Full entered command 39 | * @param cmdInputCmd First part of the input - the command 40 | * @param cmdInputParam Parameters to that input 41 | */ 42 | public static void addCommand(String cmdInput, String cmdInputCmd, String cmdInputParam) { 43 | String[] commandsToIgnore = {"list", "debug", "ver", "h", "help", "?", "rec", "rep", "func", "reset"}; 44 | boolean saveHistory = true; 45 | for (String s : commandsToIgnore) { 46 | if (cmdInput.startsWith(s)) { 47 | saveHistory = false; 48 | break; 49 | } 50 | } 51 | if (saveHistory) { 52 | cmdHistory.push(cmdInput + "##" + cmdInputCmd + "##" + cmdInputParam); 53 | } 54 | 55 | } 56 | 57 | /** 58 | * remove(): Remove the last command history item 59 | */ 60 | public static void remove() { 61 | cmdHistory.remove(cmdHistory.size() - 1); 62 | } 63 | 64 | /** 65 | * clear(): Clear the command history 66 | */ 67 | public static void clear() { 68 | cmdHistory.clear(); 69 | } 70 | 71 | /** 72 | * get(i): Return the history item at the provided point 73 | * 74 | * @param i Index 75 | * @return String at index i 76 | */ 77 | public static String get(int i) { 78 | try { 79 | return cmdHistory.get(i); 80 | } catch (ArrayIndexOutOfBoundsException e) { 81 | return ""; 82 | } 83 | } 84 | 85 | /** 86 | * get(): Return the last command entered 87 | * 88 | * @return last command entered 89 | */ 90 | public static String get() { 91 | return cmdHistory.get(cmdHistory.size() - 1); 92 | } 93 | 94 | /** 95 | * remove(i): Remove the specified command history item 96 | * 97 | * @param i index of item to remove 98 | */ 99 | public static void remove(int i) { 100 | try { 101 | cmdHistory.remove(i); 102 | } catch (ArrayIndexOutOfBoundsException e) { 103 | // Skip the removal 104 | } 105 | } 106 | 107 | 108 | /** 109 | * size(): Return the size of the command history 110 | * 111 | * @return the size of the command history stack 112 | */ 113 | public static int size() { 114 | return cmdHistory.size(); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/test/java/org/fross/rpncalc/StackConstantsTest.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 | import static org.junit.jupiter.api.Assertions.assertNotNull; 33 | 34 | class StackConstantsTest { 35 | @Test 36 | void testCmdPI() { 37 | StackObj calcStack = new StackObj(); 38 | StackConstants.cmdPI(calcStack); 39 | 40 | // Ensure the stack is not null 41 | assertNotNull(calcStack); 42 | 43 | // Ensure there is only one item in the stack 44 | assertEquals(1, calcStack.size()); 45 | 46 | // Ensure that the value is correct 47 | assertEquals("3.14159265358979323846264338327950288419716939937510", calcStack.getAsString(0)); 48 | } 49 | 50 | @Test 51 | void testCmdPHI() { 52 | StackObj calcStack = new StackObj(); 53 | StackConstants.cmdPHI(calcStack); 54 | 55 | // Ensure the stack is not null 56 | assertNotNull(calcStack); 57 | 58 | // Ensure there is only one item in the stack 59 | assertEquals(1, calcStack.size()); 60 | 61 | // Ensure that the value is correct 62 | assertEquals("1.61803398874989", calcStack.getAsString(0)); 63 | } 64 | 65 | @Test 66 | void testCmdEulersNumber() { 67 | StackObj calcStack = new StackObj(); 68 | StackConstants.cmdEulersNumber(calcStack); 69 | 70 | // Ensure the stack is not null 71 | assertNotNull(calcStack); 72 | 73 | // Ensure there is only one item in the stack 74 | assertEquals(1, calcStack.size()); 75 | 76 | // Ensure that the value is correct 77 | assertEquals("2.71828182845904523536028747135266249775724709369995", calcStack.getAsString(0)); 78 | } 79 | 80 | @Test 81 | void testCmdEulersConstant() { 82 | StackObj calcStack = new StackObj(); 83 | StackConstants.cmdEulersConstant(calcStack); 84 | 85 | // Ensure the stack is not null 86 | assertNotNull(calcStack); 87 | 88 | // Ensure there is only one item in the stack 89 | assertEquals(1, calcStack.size()); 90 | 91 | // Ensure that the value is correct 92 | assertEquals("0.577215664901532860606512090082402431", calcStack.getAsString(0)); 93 | } 94 | 95 | @Test 96 | void testCmdSpeedOfLight() { 97 | StackObj calcStack = new StackObj(); 98 | StackConstants.cmdSpeedOfLight(calcStack); 99 | 100 | // Ensure the stack is not null 101 | assertNotNull(calcStack); 102 | 103 | // Ensure there is only one item in the stack 104 | assertEquals(1, calcStack.size()); 105 | 106 | // Ensure that the value is correct 107 | assertEquals("299792458", calcStack.getAsString(0)); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /mdbook/src/Chapters/Snap.md: -------------------------------------------------------------------------------- 1 | Page Icon 2 | 3 | # SNAP 4 | [![rpncalc](https://snapcraft.io//rpncalc/badge.svg)](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 | [![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](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 | |
Command
| Description | 24 | |---------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| 25 | | to% | Converts `line1` from a "number" to a percent. For example, `0.4455` becomes `44.55%`. This is simply done by multiplying the number by 100 | 26 | | from% | Converts `line1` from a percent to a "number". For example, `93.124%` becomes `.93124`. This is simply done by multiplying the number by 0.01 | 27 | | frac [base] | Display a fractional estimate of the last stack item (`line1`) with the maximum granularity of 1/[base]. See the above description for more detail | 28 | | in2mm | Converts the value in `line1` from inches to millimeters | 29 | | mm2in | Converts the value in `line1` from millimeters to inches | 30 | | in2ft | Converts the value in `line1` from inches to feet | 31 | | ft2in | Converts the value in `line1` from feet to inches | 32 | | deg2rad | Convert `line1` from degrees into [radians](https://en.wikipedia.org/wiki/Radian) | 33 | | rad2deg | Convert `line1` from radians into degrees | 34 | | gram2oz | Convert `line1` from grams into ounces using the constant of 0.035274 ounces / gram | 35 | | oz2gram | Convert `line1` from ounces into grams using the constant of 28.349523125 grams / ounce | 36 | | kg2lb | Convert `line1` from kilograms to US pounds using the constant of 2.2046226218 lbs/kg | 37 | | lb2kg | Convert `line1` from US pounds using the constant of 0.45359237 kg/lbs | 38 | | f2c | Convert `line1` from Fahrenheit to Celsius | 39 | | c2f | Convert `line1` from Celsius to Fahrenheit | 40 | -------------------------------------------------------------------------------- /src/test/java/org/fross/library/FormatTest.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.junit.jupiter.api.Assertions.assertEquals; 30 | 31 | import org.junit.jupiter.api.Test; 32 | 33 | /** 34 | * @author Michael Fross (michael@fross.org) 35 | * 36 | */ 37 | class FormatTest { 38 | 39 | /** 40 | * Test method for {@link org.fross.library.Format#Comma(java.lang.Double)}. 41 | */ 42 | @Test 43 | void testCommaDouble() { 44 | assertEquals("1,234,567.01", Format.Comma(1234567.01)); 45 | assertEquals("999.9999", Format.Comma(999.9999)); 46 | assertEquals(".003", Format.Comma(.003)); 47 | assertEquals("1,000.00", Format.Comma(Double.valueOf(1000))); 48 | assertEquals("-.123456", Format.Comma(-0.123456)); 49 | } 50 | 51 | /** 52 | * Test method for {@link org.fross.library.Format#Comma(java.lang.Long)}. 53 | */ 54 | @Test 55 | void testCommaLong() { 56 | assertEquals("1,234,567", Format.Comma(1234567L)); 57 | assertEquals("999", Format.Comma(999L)); 58 | assertEquals("123,456,789", Format.Comma(123456789L)); 59 | assertEquals("1,000", Format.Comma(1000L)); 60 | } 61 | 62 | /** 63 | * Test Comma when sending a string 64 | */ 65 | @Test 66 | void testCommaString() { 67 | assertEquals("1,234,567.00", Format.Comma("1234567")); 68 | assertEquals("999.00", Format.Comma("999")); 69 | assertEquals("963.11", Format.Comma("963.11")); 70 | assertEquals("5,123.11", Format.Comma("5123.11")); 71 | assertEquals(".123456", Format.Comma(".123456")); 72 | assertEquals("-.123456", Format.Comma("-.123456")); 73 | assertEquals("-12,345,678.123456", Format.Comma("-12345678.123456")); 74 | } 75 | 76 | /** 77 | * Test method for {@link org.fross.library.Format#humanReadableBytes(long)}. 78 | */ 79 | @Test 80 | void testHumanReadableBytes() { 81 | assertEquals("1.235 GB", Format.humanReadableBytes(1234567890)); 82 | assertEquals("1.000 KB", Format.humanReadableBytes(1000)); 83 | assertEquals("4.096 MB", Format.humanReadableBytes(4096000)); 84 | } 85 | 86 | /** 87 | * Test method for {@link org.fross.library.Format#CenterText(int, java.lang.String, java.lang.String, java.lang.String)}. 88 | */ 89 | @Test 90 | void testCenterTextIntStringStringString() { 91 | String in = "Even Length String"; 92 | String out = "-Even Length String+"; 93 | 94 | assertEquals(out, Format.CenterText(20, in, "-", "+")); 95 | 96 | in = "Odd Length String"; 97 | out = "- Odd Length String +"; 98 | assertEquals(out, Format.CenterText(25, in, "-", "+")); 99 | } 100 | 101 | /** 102 | * Test method for {@link org.fross.library.Format#CenterText(int, java.lang.String)}. 103 | */ 104 | @Test 105 | void testCenterTextIntString() { 106 | String in = "Even Length String"; 107 | String out = " Even Length String "; 108 | 109 | assertEquals(out, Format.CenterText(20, in)); 110 | 111 | in = "Odd Length String"; 112 | out = " Odd Length String "; 113 | assertEquals(out, Format.CenterText(25, in)); 114 | } 115 | 116 | /** 117 | * Test method for {@link org.fross.library.Format#Capitalize(java.lang.String)}. 118 | */ 119 | @Test 120 | void testCapitalize() { 121 | assertEquals("CapitalizeD first CHAracter", Format.Capitalize("capitalizeD first CHAracter")); 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/org/fross/library/Date.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 | public class Date { 30 | static final String[] monthsLong = { "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "Novemember", 31 | "December" }; 32 | static final String[] monthsShort = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 33 | 34 | /** 35 | * getCurrentMonth(): Return an integer value of the current month 36 | * 37 | * @return 38 | */ 39 | public static int getCurrentMonth() { 40 | java.util.Calendar jc = java.util.Calendar.getInstance(); 41 | int month = jc.get(java.util.Calendar.MONTH) + 1; 42 | return month; 43 | } 44 | 45 | /** 46 | * getCurrentDay(): Return an integer value of the current day 47 | * 48 | * @return 49 | */ 50 | public static int getCurrentDay() { 51 | java.util.Calendar jc = java.util.Calendar.getInstance(); 52 | int day = jc.get(java.util.Calendar.DAY_OF_MONTH); 53 | return day; 54 | } 55 | 56 | /** 57 | * getCurrentYear(): Return an integer value of the current year 58 | * 59 | * @return 60 | */ 61 | public static int getCurrentYear() { 62 | java.util.Calendar jc = java.util.Calendar.getInstance(); 63 | int year = jc.get(java.util.Calendar.YEAR); 64 | return year; 65 | } 66 | 67 | /** 68 | * getCurrentHour(): Return an integer value for the current hour 69 | * 70 | * @return 71 | */ 72 | public static int getCurrentHour() { 73 | java.util.Calendar jc = java.util.Calendar.getInstance(); 74 | int hour = jc.get(java.util.Calendar.HOUR); 75 | return hour; 76 | } 77 | 78 | /** 79 | * getCurrentMinute(): Return an integer value for the current minute 80 | * 81 | * @return 82 | */ 83 | public static int getCurrentMinute() { 84 | java.util.Calendar jc = java.util.Calendar.getInstance(); 85 | int min = jc.get(java.util.Calendar.MINUTE); 86 | return min; 87 | } 88 | 89 | /** 90 | * getCurrentSecond(): Return an integer value for the current second 91 | * 92 | * @return 93 | */ 94 | public static int getCurrentSecond() { 95 | java.util.Calendar jc = java.util.Calendar.getInstance(); 96 | int sec = jc.get(java.util.Calendar.SECOND); 97 | return sec; 98 | } 99 | 100 | /** 101 | * getCurrentMonthNameLong(): Return full name of the current month 102 | * 103 | * @return 104 | */ 105 | public static String getCurrentMonthNameLong() { 106 | return monthsLong[getCurrentMonth()]; 107 | } 108 | 109 | /** 110 | * getCurrentMonthNameShort(): Return three letter short name for current month 111 | * 112 | * @return 113 | */ 114 | public static String getCurrentMonthNameShort() { 115 | return monthsShort[getCurrentMonth()]; 116 | } 117 | 118 | /** 119 | * getMonthNameLong(): Return long name of month for provided month number 120 | * 121 | * @param mon 122 | * @return 123 | */ 124 | public static String getMonthNameLong(int mon) { 125 | return monthsLong[mon]; 126 | } 127 | 128 | /** 129 | * getMonthNameShort(): Return short month name for provided month number 130 | * 131 | * @param mon 132 | * @return 133 | */ 134 | public static String getMonthNameShort(int mon) { 135 | return monthsShort[mon]; 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /mdbook/src/Chapters/Introduction.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | # INTRODUCTION 4 | RPNCalc is the command-line based [Reverse Polish Notation (RPN) calculator](https://en.wikipedia.org/wiki/Reverse_Polish_notation). 5 | RPN calculators make it very simple to do complex calculations, especially if there are 6 | parentheses involved. In essence, you enter your numbers first, then the operator. 7 | 8 | So, to add 2 and 3 to get 5, you would first add the number 2 to the stack: `2 [Enter]`. Then 9 | you would add 3 to the stack (pushing the 2 to the second position): `3 [Enter]`. Now, to add 10 | them you would enter: `+ [Enter]` and RPNCalc would remove the 2 and 3 from the stack, add them, and push 5 back onto the stack. 11 | 12 | The following example can be tricky to get your head around in a traditional calculator but is quite easy with RPN. The chapter `What is an RPN Calculator` 13 | will go through solving this step by step. ***(Spoiler warning: just start in the middle and work your way out.)*** 14 | 15 | `x = SQRT(((((5+3) * 8)/2) * (2+1)) ^ 2)` 16 | 17 | RPN is based on a Last In First Out (LIFO) stack framework which sounds complicated, but makes intuitive sense when you use it. 18 | You can think of it as a stack of plates. When you put one on the top of the stack, everyone other one shifts down by one. On an RPN calculator, 19 | there is no equal sign, but there is an enter key to put a value onto the stack. The chapter on `Stacks` talks more about how this works with RPNCalc. 20 | 21 | This guide also has chapters on the various functions provided by the calculator and how to use them. If you find something that is unclear, or 22 | could benefit from an example or two, please let me know. Contact information is below. 23 | 24 | If you have not heard of reverse Polish notation, or just have a passion for various calculator notations (and seriously, who doesn't?), you can read more about RPN on 25 | [Wikipedia](https://en.wikipedia.org/wiki/Reverse_Polish_notation) or a (very) quick summary in the `What is an RPN Calculator` chapter. 26 | 27 | 28 | ## My Brief History of RPNCalc 29 | 30 | 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:
67 | 68 | 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", "") + "'"); 81 | 82 | } else { 83 | Output.printColorln(Color.RED, "ERROR: Provided browser is not valid: '" + bName + "'"); 84 | // Since the provided bName is not valid, ask for one explicitly 85 | Output.printColorln(Color.YELLOW, "Enter the full path to your preferred browser"); 86 | Output.printColorln(Color.YELLOW, "NOTE: Always use slashes '/' instead of backslashes '\\')"); 87 | 88 | try { 89 | String browserInput = Main.scanner.readLine(":: "); 90 | Output.println(""); 91 | 92 | // If the user entered nothing, remove preference 93 | if (browserInput.isEmpty()) { 94 | prefConfig.remove("browser"); 95 | 96 | } else { 97 | // Confirm entered browser can be executed 98 | if (!new File(browserInput).canExecute()) { 99 | Output.printColorln(Color.RED, "ERROR: Provided file is not executable: '" + browserInput + "'"); 100 | } else { 101 | prefConfig.put("browser", browserInput); 102 | Output.printColorln(Color.CYAN, "Browser set to: '" + prefConfig.get("browser", "") + "'"); 103 | } 104 | 105 | } 106 | 107 | } catch (Exception e) { 108 | Output.printColorln(Color.RED, "ERROR: Could not read user input"); 109 | } 110 | 111 | } 112 | 113 | } 114 | 115 | } -------------------------------------------------------------------------------- /src/main/java/org/fross/rpncalc/CommandLineArgs.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 com.beust.jcommander.Parameter; 31 | import com.beust.jcommander.ParameterException; 32 | import org.fross.library.Debug; 33 | import org.fross.library.Output; 34 | 35 | public class CommandLineArgs { 36 | // --------------------------------------------------------------------------------------------- 37 | // Define command line options that can be used 38 | // --------------------------------------------------------------------------------------------- 39 | 40 | @Parameter(names = {"-h", "-?", "--help"}, help = true, description = "Display RPNCalc help and exit") 41 | protected boolean clHelp = false; 42 | 43 | @Parameter(names = {"-z", "--no-color"}, description = "Disable colorized output") 44 | protected boolean clNoColor = false; 45 | 46 | @Parameter(names = {"-v", "--version"}, description = "Show current program version and latest release on GitHub") 47 | protected boolean clVersion = false; 48 | 49 | @Parameter(names = {"-D", "--debug"}, description = "Turn on Debug mode to display extra program information") 50 | protected boolean clDebug = false; 51 | 52 | @Parameter(names = {"-l", "--load"}, description = "Load saved stack file") 53 | protected String clLoad = ""; 54 | 55 | @Parameter(names = {"-L", "--license"}, description = "Display program usage license") 56 | protected boolean clLicense = false; 57 | 58 | // --------------------------------------------------------------------------------------------- 59 | // Process command line parameters with the following methods 60 | // --------------------------------------------------------------------------------------------- 61 | public static void ProcessCommandLine(String[] argv) { 62 | CommandLineArgs cli = new CommandLineArgs(); 63 | JCommander jc = new JCommander(); 64 | 65 | // JCommander parses the command line 66 | try { 67 | jc.setProgramName("RPNCalc"); 68 | jc = JCommander.newBuilder().addObject(cli).build(); 69 | jc.parse(argv); 70 | } catch (ParameterException ex) { 71 | System.out.println(ex.getMessage()); 72 | jc.usage(); 73 | System.exit(0); 74 | } 75 | 76 | // --------------------------------------------------------------------------------------------- 77 | // Process the parsed command line options 78 | // --------------------------------------------------------------------------------------------- 79 | // Debug Switch 80 | if (cli.clDebug) Debug.enable(); 81 | 82 | // Set the stack name and restore stack from Preferences 83 | if (!cli.clLoad.isBlank()) { 84 | Main.calcStack.setStackNameAndRestore(cli.clLoad, "1"); 85 | Main.calcStack2.setStackNameAndRestore(cli.clLoad, "2"); 86 | } else { 87 | Main.calcStack.setStackNameAndRestore("default", "1"); 88 | Main.calcStack2.setStackNameAndRestore("default", "2"); 89 | } 90 | 91 | // Version Display 92 | if (cli.clVersion) { 93 | Help.DisplayVersion(); 94 | System.exit(0); 95 | } 96 | 97 | // License Display 98 | if (cli.clLicense) { 99 | Help.DisplayLicense(); 100 | System.exit(0); 101 | } 102 | 103 | // Disable Colorized Output Switch 104 | if (cli.clNoColor) { 105 | Output.enableColor(false); 106 | } 107 | 108 | // Show Help and Exit 109 | if (cli.clHelp) { 110 | Help.Display(); 111 | System.exit(0); 112 | } 113 | 114 | } 115 | 116 | } -------------------------------------------------------------------------------- /src/test/java/org/fross/rpncalc/ConfigurationTest.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.util.prefs.Preferences; 32 | 33 | import static org.junit.jupiter.api.Assertions.assertEquals; 34 | 35 | class ConfigurationTest { 36 | 37 | // Class variables 38 | Preferences prefConfig = Preferences.userRoot().node("/org/fross/rpn/config"); 39 | 40 | // Save current settings, so they can be reinstated after the test 41 | String align = prefConfig.get("alignment", Main.CONFIG_DEFAULT_ALIGNMENT); 42 | int width = prefConfig.getInt("programwidth", Main.CONFIG_DEFAULT_PROGRAM_WIDTH); 43 | int memSlots = prefConfig.getInt("memoryslots", Main.CONFIG_DEFAULT_MEMORY_SLOTS); 44 | 45 | @Test 46 | void testSetMemSlots() { 47 | // Test MemSlots 48 | Configuration.cmdSet("memslots 1123"); 49 | assertEquals(1123, StackMemory.memorySlots.length); 50 | 51 | Configuration.cmdSet("memslots 100"); 52 | assertEquals(100, StackMemory.memorySlots.length); 53 | 54 | Configuration.cmdSet("memslots 71"); 55 | assertEquals(71, StackMemory.memorySlots.length); 56 | 57 | // Rest configuration to original user value 58 | prefConfig.putInt("memoryslots", memSlots); 59 | } 60 | 61 | @Test 62 | void testSetWidth() { 63 | // Test Width 64 | Configuration.cmdSet("width 100"); 65 | assertEquals(100, Main.configProgramWidth); 66 | assertEquals("100", prefConfig.get("programwidth", "")); 67 | 68 | // Rest configuration to original user value 69 | prefConfig.putInt("programwidth", width); 70 | } 71 | 72 | @Test 73 | void testSetAlignment() { 74 | // Test Align 75 | Configuration.cmdSet("alignment d"); 76 | assertEquals("d", Main.configAlignment); 77 | assertEquals("d", prefConfig.get("alignment", "")); 78 | 79 | Configuration.cmdSet("alignment R"); 80 | assertEquals("r", Main.configAlignment); 81 | assertEquals("r", prefConfig.get("alignment", "")); 82 | 83 | Configuration.cmdSet("alignment l"); 84 | assertEquals("l", Main.configAlignment); 85 | assertEquals("l", prefConfig.get("alignment", "")); 86 | 87 | Configuration.cmdSet("align d"); 88 | assertEquals("d", Main.configAlignment); 89 | assertEquals("d", prefConfig.get("alignment", "")); 90 | 91 | Configuration.cmdSet("align r"); 92 | assertEquals("r", Main.configAlignment); 93 | assertEquals("r", prefConfig.get("alignment", "")); 94 | 95 | Configuration.cmdSet("align L"); 96 | assertEquals("l", Main.configAlignment); 97 | assertEquals("l", prefConfig.get("alignment", "")); 98 | 99 | // Rest configuration to original user value 100 | prefConfig.put("alignment", align); 101 | 102 | } 103 | 104 | @Test 105 | void testResetCommand() { 106 | // Test Reset 107 | Configuration.cmdReset(); 108 | assertEquals(Main.CONFIG_DEFAULT_PROGRAM_WIDTH, Main.configProgramWidth); 109 | assertEquals(Main.CONFIG_DEFAULT_PROGRAM_WIDTH, Integer.parseInt(prefConfig.get("programwidth", ""))); 110 | 111 | assertEquals(Main.CONFIG_DEFAULT_ALIGNMENT, Main.configAlignment); 112 | assertEquals(Main.CONFIG_DEFAULT_ALIGNMENT, prefConfig.get("alignment", "")); 113 | 114 | assertEquals(Main.CONFIG_DEFAULT_MEMORY_SLOTS, Main.configMemorySlots); 115 | assertEquals(Main.CONFIG_DEFAULT_MEMORY_SLOTS, Integer.parseInt(prefConfig.get("memoryslots", ""))); 116 | 117 | // Rest configuration to original user value 118 | prefConfig.putInt("programwidth", width); 119 | prefConfig.put("alignment", align); 120 | prefConfig.putInt("memoryslots", memSlots); 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/test/java/org/fross/rpncalc/StackMemoryTest.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.util.prefs.Preferences; 32 | 33 | import static org.junit.jupiter.api.Assertions.assertEquals; 34 | import static org.junit.jupiter.api.Assertions.assertTrue; 35 | 36 | /** 37 | * @author Michael Fross (michael@fross.org) 38 | */ 39 | class StackMemoryTest { 40 | /** 41 | * Test method for {@link org.fross.rpncalc.StackMemory#SetMaxMemorySlots(java.lang.String)}. 42 | */ 43 | @Test 44 | void testSetMaxMemorySlots() { 45 | // Save current number of memory slots given changes are persistent 46 | Preferences prefConfig = Preferences.userRoot().node("/org/fross/rpn/config"); 47 | int currentSlots = prefConfig.getInt("memoryslots", Integer.MAX_VALUE); 48 | 49 | // If the value doesn't exist, it will error out - so add one if it's not there 50 | if (currentSlots == Integer.MAX_VALUE) { 51 | prefConfig.putInt("memoryslots", Main.CONFIG_DEFAULT_MEMORY_SLOTS); 52 | currentSlots = Main.CONFIG_DEFAULT_MEMORY_SLOTS; 53 | } 54 | 55 | boolean result = StackMemory.SetMaxMemorySlots("2099"); 56 | assertTrue(result); 57 | assertEquals(2099, StackMemory.memorySlots.length); 58 | 59 | // Set slots back to what they were originally 60 | StackMemory.SetMaxMemorySlots(currentSlots + ""); 61 | assertEquals(currentSlots, StackMemory.memorySlots.length); 62 | } 63 | 64 | /** 65 | * Test method for {@link org.fross.rpncalc.StackMemory#QueryInUseMemorySlots()}. 66 | */ 67 | @Test 68 | void testQueryInUseMemorySlots() { 69 | StackObj stk = new StackObj(); 70 | 71 | stk.push(1.0); 72 | 73 | // Clear the memory slots 74 | StackMemory.cmdMem(stk, "clearall"); 75 | 76 | // 2 items to slots 77 | StackMemory.cmdMem(stk, "1 add"); 78 | StackMemory.cmdMem(stk, "2 add"); 79 | 80 | // Test there are 2 slots in use 81 | assertEquals(2, StackMemory.QueryInUseMemorySlots()); 82 | 83 | // Remove one and test again 84 | StackMemory.cmdMem(stk, "1 clear"); 85 | assertEquals(1, StackMemory.QueryInUseMemorySlots()); 86 | 87 | // Clear the memory slots 88 | StackMemory.cmdMem(stk, "clearall"); 89 | } 90 | 91 | /** 92 | * Test method for {@link org.fross.rpncalc.StackMemory#cmdMem(org.fross.rpncalc.StackObj, java.lang.String)}. 93 | * add, clear, and clearall tested above 94 | */ 95 | @Test 96 | void testCmdMem() { 97 | StackObj stk = new StackObj(); 98 | 99 | // Copy 100 | stk.push(71.0); 101 | StackMemory.cmdMem(stk, "clearall"); 102 | StackMemory.cmdMem(stk, "2 add"); 103 | assertEquals(1, StackMemory.QueryInUseMemorySlots()); 104 | 105 | StackMemory.cmdMem(stk, "2 copy"); 106 | assertEquals(2, stk.size()); 107 | assertEquals(142, stk.pop().add(stk.pop()).doubleValue()); 108 | 109 | stk.push(1.234e12); 110 | StackMemory.cmdMem(stk, "4 add"); 111 | assertEquals(2, StackMemory.QueryInUseMemorySlots()); 112 | StackMemory.cmdMem(stk, "4 copy"); 113 | Math.Divide(stk); 114 | assertEquals(1, stk.peek().doubleValue()); 115 | 116 | // addall 117 | stk.clear(); 118 | stk.push(11.0); 119 | stk.push(12.0); 120 | stk.push(13.0); 121 | StackMemory.cmdMem(stk, "addall"); 122 | assertEquals(4, StackMemory.QueryInUseMemorySlots()); 123 | 124 | // copyall 125 | stk.clear(); 126 | StackMemory.cmdMem(stk, "copyall"); 127 | assertEquals(4, stk.size()); 128 | StackCommands.cmdAddAll(stk, ""); 129 | StackCommands.cmdRound(stk, "2"); 130 | assertEquals("1234000000036.00", stk.pop().toEngineeringString()); 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /mdbook/src/Chapters/WhatIsRPN.md: -------------------------------------------------------------------------------- 1 | 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 |
56 | 57 | ## Wikipedia: 58 | 59 | The following is directly from [Wikipedia](https://en.wikipedia.org/wiki/Reverse_Polish_notation). There is a lot more information there, but here are a few highlights. 60 | 61 | ### Explanation 62 | 63 | In reverse Polish notation, the operators follow their operands; for instance, to add 3 and 4 together, one would write `3 4 +` rather than `3 + 4`. If there are multiple operations, operators are given immediately after their final operands (often an operator takes two operands, in which case the operator is written after the second operand); so the expression written `3 − 4 + 5` in conventional notation would be written `3 4 − 5 +` in reverse Polish notation: 4 is first subtracted from 3, then 5 is added to it. An advantage of reverse Polish notation is that it removes the need for parentheses that are required by infix notation. While `3 − 4 × 5` can also be written `3 − (4 × 5)`, that means something quite different from `(3 − 4) × 5`. In reverse Polish notation, the former could be written `3 4 5 × −`, which unambiguously means `3 (4 5 ×) −` which reduces to `3 20 −` (which can further be reduced to -17); the latter could be written `3 4 − 5 ×` (or `5 3 4 − ×`, if keeping similar formatting), which unambiguously means `(3 4 −) 5 ×`. 64 | 65 | ### Practical implications 66 | 67 | In comparison, testing of reverse Polish notation with algebraic notation, reverse Polish has been found to lead to faster calculations, for two reasons. The first reason is that reverse Polish calculators do not need expressions to be parenthesized, so fewer operations need to be entered to perform typical calculations. Additionally, users of reverse Polish calculators made fewer mistakes than for other types of calculators. Later research clarified that the increased speed from reverse Polish notation may be attributed to the smaller number of keystrokes needed to enter this notation, rather than to a smaller cognitive load on its users. However, anecdotal evidence suggests that reverse Polish notation is more difficult for users to learn than algebraic notation. -------------------------------------------------------------------------------- /src/main/java/org/fross/library/Format.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 java.math.BigDecimal; 30 | import java.text.DecimalFormat; 31 | import java.text.NumberFormat; 32 | 33 | import org.fusesource.jansi.Ansi; 34 | 35 | public class Format { 36 | 37 | /** 38 | * Comma Return a string with comma separators at the correct intervals. Supports decimal places and a negative sign. 39 | * 40 | * @param num - Number to comma-ize 41 | * @return 42 | */ 43 | public static String Comma(Double num) { 44 | DecimalFormat df = null; 45 | 46 | try { 47 | df = new DecimalFormat("#,###.00#######"); 48 | } catch (Exception Ex) { 49 | Output.printColorln(Ansi.Color.RED, "ERROR Adding Commas to numbers:\n" + Ex.getMessage()); 50 | } 51 | 52 | return (String.valueOf(df.format(num))); 53 | } 54 | 55 | /** 56 | * Comma Return a string with comma separators at the correct intervals. Supports decimal places and a negative sign. 57 | * 58 | * @param num - Number to comma-ize 59 | * @return 60 | */ 61 | public static String Comma(Long num) { 62 | return NumberFormat.getInstance().format(num); 63 | } 64 | 65 | /** 66 | * Comma Return a string with comma separators at the correct intervals. Supports decimal places and a negative sign. 67 | * 68 | * @param num - Number to comma-ize 69 | * @return 70 | */ 71 | public static String Comma(String num) { 72 | DecimalFormat df = null; 73 | 74 | try { 75 | df = new DecimalFormat("#,###.00#######"); 76 | } catch (Exception Ex) { 77 | Output.printColorln(Ansi.Color.RED, "ERROR Adding Commas to numbers:\n" + Ex.getMessage()); 78 | } 79 | 80 | return (String.valueOf(df.format(new BigDecimal(num)))); 81 | } 82 | 83 | 84 | /** 85 | * HumanReadableBytes(): Take a long number in bytes and return a more human readable format Reference: 86 | * https://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java 87 | * https://www.geeksforgeeks.org/how-to-calculate-log-base-2-of-an-integer-in-java/?ref=leftbar-rightbar 88 | * 89 | * @param numInBytes 90 | * @return String 91 | */ 92 | public static String humanReadableBytes(long numInBytes) { 93 | String[] descriptor = { "K", "M", "G", "T", "P", "E" }; 94 | int unit = 1000; // As opposed to 1024 95 | 96 | // If the size is < than 1k, just return as bytes 97 | if (numInBytes < unit) { 98 | return numInBytes + " B"; 99 | } 100 | 101 | // Math.log uses base 10. You have to divide to get the base we want..in this case unit 102 | // exp is the number of times you have to multiply a base to get the inputed number 103 | int exp = (int) (Math.log(numInBytes) / Math.log(unit)); 104 | 105 | // Determine the descriptor to use based on the log 106 | String prefix = descriptor[exp - 1]; 107 | 108 | // Create the string and return it 109 | return String.format("%.3f %sB", numInBytes / Math.pow(unit, exp), prefix); 110 | } 111 | 112 | /** 113 | * CenterText(): Center the text within the width provided adding the pre and post string. Returns a string that can be 114 | * printed. 115 | * 116 | * Approach: ((Width - length of text - length of pre - length of post) / 2 ) = spaces to add at the front & back 117 | * 118 | * @param width 119 | * @param lineToCenter 120 | * @param pre 121 | * @param post 122 | * @return 123 | */ 124 | public static String CenterText(int width, String lineToCenter, String pre, String post) { 125 | String result = null; 126 | 127 | int spacesToAdd = ((width - lineToCenter.length() - pre.length() - post.length()) / 2); 128 | result = pre + " ".repeat(spacesToAdd) + lineToCenter + " ".repeat(spacesToAdd) + post; 129 | 130 | return (result); 131 | } 132 | 133 | /** 134 | * CenterText(): Center the text within the width provided. If no pre and post are provided, assume spaces 135 | * 136 | * @param width 137 | * @param lineToCenter 138 | * @return 139 | */ 140 | public static String CenterText(int width, String lineToCenter) { 141 | return CenterText(width, lineToCenter, " ", " "); 142 | } 143 | 144 | /** 145 | * Capitalize(): Return the provided string with the first character capitalized 146 | * 147 | * @param str 148 | * @return 149 | */ 150 | public static String Capitalize(String str) { 151 | return str.substring(0, 1).toUpperCase() + str.substring(1); 152 | } 153 | 154 | } // END OF CLASS 155 | -------------------------------------------------------------------------------- /src/main/java/org/fross/library/SpinnerBouncyBall.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. The spinner 37 | * process starts a new thread and when the work in the main program is complete, it's stopped. 38 | * 39 | * Usage: Start Spinner: SpinnerBouncyBall spinner = new SpinnerBouncyBall(); spinner.start(); 40 | * 41 | * Stop Spinner: spinner.interrupt(); 42 | * 43 | * @author Michael 44 | * 45 | */ 46 | public class SpinnerBouncyBall extends Thread { 47 | private int spinnerDelay = 70; 48 | private int numBallSlots = 6; 49 | private String leftWall = "["; 50 | private String rightWall = "]"; 51 | private String ball = "o"; 52 | 53 | // Position of the ball in it's journey 54 | int ballPosition = 0; 55 | 56 | // Direction the ball is heading. Positive is to the right 57 | int ballDirection = 1; 58 | 59 | /** 60 | * configureDelay(): Set spinner's movement speed in milliseconds 61 | * 62 | * @param delay 63 | */ 64 | public void configureDelay(int delay) { 65 | spinnerDelay = delay; 66 | } 67 | 68 | /** 69 | * configureSlots(): Set number of spinner slots the ball will traverse 70 | * 71 | * @param slots 72 | */ 73 | public void configureSlots(int slots) { 74 | this.numBallSlots = slots; 75 | } 76 | 77 | /** 78 | * configureLeftWall(): Set spinner's left wall character 79 | * 80 | * @param lWall 81 | */ 82 | public void configureLeftWall(String lWall) { 83 | this.leftWall = lWall; 84 | } 85 | 86 | /** 87 | * configureRightWall(): Set spinner's right wall character 88 | * 89 | * @param rWall 90 | */ 91 | public void configureRightWall(String rWall) { 92 | this.rightWall = rWall; 93 | } 94 | 95 | /** 96 | * configureBall(): Set spinner's ball character 97 | * 98 | * @param ballChar 99 | */ 100 | public void configureBall(String ballChar) { 101 | this.ball = ballChar; 102 | } 103 | 104 | /** 105 | * run(): Overrides Thread run() method interface and is the main thread execution loop 106 | */ 107 | @Override 108 | public void run() { 109 | // Keep calling the update spinner until the thread is interrupted 110 | while (Thread.currentThread().isInterrupted() == false) { 111 | // Bounce the ball 112 | bounceBall(); 113 | 114 | // Delay before next thread symbol is displayed 115 | try { 116 | TimeUnit.MILLISECONDS.sleep(spinnerDelay); 117 | } catch (InterruptedException ex) { 118 | Thread.currentThread().interrupt(); 119 | } 120 | } 121 | } 122 | 123 | /** 124 | * bounceBall(): Show the spinner symbol and advance to the next index 125 | * 126 | */ 127 | public void bounceBall() { 128 | // Display the bouncy ball and walls 129 | Output.printColor(Ansi.Color.WHITE, leftWall); 130 | System.out.print(" ".repeat(ballPosition)); 131 | Output.printColor(Ansi.Color.YELLOW, ball); 132 | System.out.print(" ".repeat(numBallSlots - ballPosition)); 133 | Output.printColor(Ansi.Color.WHITE, rightWall); 134 | 135 | // Move cursor back 136 | System.out.print(ansi().cursorLeft(numBallSlots + 3)); 137 | 138 | // Determine next ball location 139 | if (ballDirection > 0) { 140 | // Ball moving to the right (positive direction) 141 | ballPosition++; 142 | if (ballPosition >= numBallSlots) 143 | ballDirection *= -1; 144 | } else { 145 | // Ball moving to the left 146 | ballPosition--; 147 | if (ballPosition <= 0) 148 | ballDirection *= -1; 149 | } 150 | } 151 | 152 | /** 153 | * main(): Simply here to test the spinner 154 | * 155 | * @param args 156 | */ 157 | public static void main(String[] args) { 158 | System.out.println("Running Spinner for 10 seconds:"); 159 | 160 | // Define and start the spinner 161 | SpinnerBouncyBall spinner = new SpinnerBouncyBall(); 162 | 163 | // Configure the spinner look and feel 164 | // spinner.configureDelay(40); 165 | // spinner.configureSlots(50); 166 | // spinner.configureLeftWall("<"); 167 | // spinner.configureRightWall(">"); 168 | // spinner.configureBall("*"); 169 | 170 | spinner.start(); 171 | 172 | // Sleep for 10 seconds 173 | try { 174 | TimeUnit.MILLISECONDS.sleep(10000); 175 | } catch (InterruptedException ex) { 176 | Thread.currentThread().interrupt(); 177 | } 178 | 179 | // Stop the spinner 180 | spinner.interrupt(); 181 | 182 | System.out.println("\nSpinner Complete\n\n"); 183 | } 184 | 185 | } // END CLASS 186 | -------------------------------------------------------------------------------- /mdbook/src/Chapters/HighLevelUsage.md: -------------------------------------------------------------------------------- 1 | 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", "")); 50 | Output.printColorln(Ansi.Color.YELLOW, "-".repeat(Main.configProgramWidth) + "\n"); 51 | return; 52 | } 53 | 54 | // Parse the provided argument into a command and value 55 | try { 56 | command = arg.substring(0, arg.indexOf(" ")).toLowerCase(); 57 | value = arg.substring(arg.indexOf(" ") + 1); 58 | 59 | Output.debugPrintln("Set Command: '" + command + "'"); 60 | Output.debugPrintln("Set Value: '" + value + "'"); 61 | 62 | switch (command.toLowerCase()) { 63 | case "align": 64 | case "alignment": 65 | value = value.toLowerCase(); 66 | if (value.compareTo("l") != 0 && value.compareTo("d") != 0 && value.compareTo("r") != 0) { 67 | Output.printColorln(Ansi.Color.RED, "Alignment can only be 'l'eft, 'd'ecimal, or 'r'ight. See help for usage"); 68 | return; 69 | } 70 | Main.configAlignment = value; 71 | Output.debugPrintln("Saving Alignment value to preferences"); 72 | prefConfig.put("alignment", value); 73 | Output.printColorln(Ansi.Color.CYAN, "Alignment set to '" + value + "'"); 74 | break; 75 | 76 | case "width": 77 | value = value.toLowerCase(); 78 | if (Integer.parseInt(value) < Main.PROGRAM_MINIMUM_WIDTH) { 79 | Output.printColorln(Ansi.Color.RED, "Error. Minimum width is " + Main.PROGRAM_MINIMUM_WIDTH + ". Setting width to that value."); 80 | value = "" + Main.PROGRAM_MINIMUM_WIDTH; 81 | } 82 | Main.configProgramWidth = Integer.parseInt(value); 83 | Output.debugPrintln("Saving Program Width value to preferences"); 84 | prefConfig.putInt("programwidth", Integer.parseInt(value)); 85 | Output.printColorln(Ansi.Color.CYAN, "Program Width set to '" + value + "'"); 86 | break; 87 | 88 | case "mem": 89 | case "memslots": 90 | case "memoryslots": 91 | if (StackMemory.SetMaxMemorySlots(value)) { 92 | Output.printColorln(Ansi.Color.CYAN, "Memory Slots set to '" + value + "'"); 93 | } 94 | break; 95 | 96 | case "browser": 97 | Browser.ConfigureBrowser(value); 98 | break; 99 | 100 | default: 101 | Output.printColorln(Ansi.Color.RED, "ERROR: Unknown set command: '" + command + "'"); 102 | } 103 | 104 | } catch (Exception ex) { 105 | Output.printColorln(Ansi.Color.RED, "Error parsing set command: 'set " + arg + "' See help for set command usage"); 106 | } 107 | } 108 | 109 | /** 110 | * cmdReset(): Resets the configuration variables back to default 111 | */ 112 | public static void cmdReset() { 113 | Output.printColorln(Ansi.Color.CYAN, "Alignment, Width, and Memory slots reset to default values"); 114 | Preferences prefConfig = Preferences.userRoot().node("/org/fross/rpn/config"); 115 | 116 | // Reset Alignment 117 | prefConfig.put("alignment", Main.CONFIG_DEFAULT_ALIGNMENT); 118 | Main.configAlignment = Main.CONFIG_DEFAULT_ALIGNMENT; 119 | 120 | // Reset Width 121 | prefConfig.putInt("programwidth", Main.CONFIG_DEFAULT_PROGRAM_WIDTH); 122 | Main.configProgramWidth = Main.CONFIG_DEFAULT_PROGRAM_WIDTH; 123 | 124 | // Reset the number of Memory Slots 125 | StackMemory.SetMaxMemorySlots(Main.CONFIG_DEFAULT_MEMORY_SLOTS + ""); 126 | prefConfig.putInt("memoryslots", Main.CONFIG_DEFAULT_MEMORY_SLOTS); 127 | Main.configMemorySlots = Main.CONFIG_DEFAULT_MEMORY_SLOTS; 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /mdbook/src/Chapters/Configuration.md: -------------------------------------------------------------------------------- 1 | 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 | |
Command
| Description | 25 | |---------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 26 | | reset| This command resets the configuration setting that are set with the `set` command back to their default values | 27 | | set| Display the current values of the configurable persistent settings | 28 | | set width `NUM`| Sets the width of the program. If you are using a small display, and the calculator wraps, this can be used to make the width smaller (or larger). Please note that there is a minimum width that must be used. This setting is persistent across RPNCalc executions | 29 | | set mem `NUM`| Set the number of memory slots available to RPNCalc to `NUM`. If you need more, or less, it can be changed with this command. The setting is persistent across RPNCalc executions. `set memslots` or `set memoryslots` may also be used. See the memory commands chapter for more information | 30 | | set align `l`

set align `d`

set align `r` | Set the alignment of the stack when it's displayed

`l` or left alignment aligns on the left of the number
`r` or right alignment has the numbers aligned to the right
`d` or decimal aligns all of the decimal points together in a column

This setting is persistent across RPNCalc executions. `set alignment` may also be used | 31 | | set browser FILE| Sets the full path to the web browser on your computer.
A browser is opened by several RPNCalc commands. In order for RPNCalc to know which browser to launch, the full path to the browser needs to be provided and is stored in the configuration preferences. This command will set the browser file location. If you wish to clear it, simply `set browser clear` and enter nothing at the prompt. If you give it an executable file, it will be set to that. If the provided file is not executable, it will re-prompt for a valid one. Also, if you run a commande (i.e. `hp` or `ug`) that use an external browser, and none is set, you will be prompted for the full path (which is the same as setting it here).

Please note that use should always use slashes `/` as a path separater instead of backslashes `\` on windows. The `C:` syntax is fine on windows | -------------------------------------------------------------------------------- /mdbook/src/Chapters/UserDefinedFunctions.md: -------------------------------------------------------------------------------- 1 | 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 | |
Command
| Description | 32 | |-------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 33 | |record on
rec on| Turn on recording. Most commands and numbers entered after record is enabled will be saved. There are some that are excluded from being recorded as detailed above | 34 | |record off
rec off| Turn off recording. The user will be prompted to enter in a name for this function and that name will be used to run it in the future. If you do not enter in a name the recording is canceled and nothing will be saved | 35 | |func del `NAME`| Delete a saved function. The name must match the one given when saved. A list of functions can be viewed with `list func`. Undo will not recover a deleted function | 36 | |func delall| Delete all saved user defined functions. Please note that undo will not recover deleted functions | 37 | |func export| Export all User Defined Functions to a file for backup or future import | 38 | |func import| Import a previously exported set of functions. Please note that importing will append the imported functions to the currently defined list. If an imported function has the same name as an existing one, the existing function will be overwritten | 39 | 40 | 41 | ### Example 1 42 | Here is a full real world example. Lets say you'd like to make a user defined function to take the cube of number. Here are the steps you'd take to do that. 43 | 44 | |Number|Command|Description| 45 | |:------:|:-------:|:-----------| 46 | |1|`c`|Clear the stack. Not really needed, but let's start off tidy| 47 | |2|`3 [Enter]`|Add the number 3 to the stack. This can be any number really as it's not part of the recording| 48 | |3|`record on`|Start recording. From now on anything you do (mostly) will be recorded| 49 | |4|`3`|Add 3 to the stack| 50 | |5|`^`|Take `line1` value to the power of 3| 51 | |6|`record off`|Stop recording and give the function the name "cube"| 52 | |7|`list func`|Show the user defined functions including the `cube` command you just made| 53 | 54 | From now on, just type `cube` and `line1` will be cubed! Go You! You can always list your defined functions with `list func` 55 | 56 | ### Example 2 57 | Another real world but slightly more complex example. Say you wish to know the percentage different between two numbers. Let's create a function called `diffpercent` The 58 | logic is to find the smallest number on the stack and then the largest. Divide them. Flip the sign and add one to it. Then convert it to a percent. 59 | 60 | | Number | Command | Description | 61 | |:------:|:---------------:|:------------------------------------------------------------------------------------| 62 | | 1 | `c` | Clear the stack. Not really needed, but let's start off tidy | 63 | | 2 | `10` | Setting up two numbers before we record the function | 64 | | 3 | `1` | Setting up two numbers before we record the function | 65 | | 4 | `record on` | Start recording. From now on anything you do (mostly) will be recorded | 66 | | 5 | `min` | Copy the smallest number in the stack to the top | 67 | | 6 | `max` | Copy the largest number in the stack to the top | 68 | | 7 | `/` | Divide them | 69 | | 8 | `f` | Flip the sign | 70 | | 9 | `1` | Add the number one to the stack | 71 | | 10 | `+` | Add the numbers together (effectively subtracting the division results from 1 | 72 | | 11 | `to%` | Convert to a percent (multiply by 100) | 73 | | 12 | `record off` | Save the function with the name `diffpercent` | 74 | 75 | In the example above, the result it 90%. There is a 90% different between 10 and 1. Going forward, you can use the command `diffpercent` anytime you need to find the 76 | percentage different between the lowest and highest number on the stack. 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/test/java/org/fross/rpncalc/StackTrigTest.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 StackTrigTest { 37 | 38 | /** 39 | * Test method for 40 | * {@link org.fross.rpncalc.StackTrig#cmdTrig(org.fross.rpncalc.StackObj, java.lang.String, java.lang.String)}. 41 | */ 42 | @Test 43 | void testCmdTrig() { 44 | StackObj stk = new StackObj(); 45 | 46 | // Testing Sine - Degrees 47 | stk.push(12.0); 48 | StackTrig.cmdTrig(stk, "sin", ""); 49 | StackCommands.cmdRound(stk, "5"); 50 | assertEquals(0.20791, stk.peek().doubleValue()); 51 | assertEquals(1, stk.size()); 52 | 53 | stk.clear(); 54 | stk.push(1.2e11); 55 | StackTrig.cmdTrig(stk, "sin", ""); 56 | StackCommands.cmdRound(stk, "7"); 57 | assertEquals("0.8660255", stk.peek().toEngineeringString()); 58 | assertEquals(1, stk.size()); 59 | 60 | // Testing Sine - Radians 61 | stk.clear(); 62 | stk.push(1.2); 63 | StackTrig.cmdTrig(stk, "sin", "rad"); 64 | StackCommands.cmdRound(stk, "5"); 65 | assertEquals(0.93204, stk.peek().doubleValue()); 66 | assertEquals(1, stk.size()); 67 | 68 | stk.clear(); 69 | stk.push(1.2e11); 70 | StackTrig.cmdTrig(stk, "sin", "rad"); 71 | StackCommands.cmdRound(stk, "7"); 72 | assertEquals("0.1715595", stk.peek().toEngineeringString()); 73 | assertEquals(1, stk.size()); 74 | 75 | // Testing Cosine - Degrees 76 | stk.clear(); 77 | stk.push(12.0); 78 | StackTrig.cmdTrig(stk, "cos", ""); 79 | StackCommands.cmdRound(stk, "5"); 80 | assertEquals(0.97815, stk.peek().doubleValue()); 81 | assertEquals(1, stk.size()); 82 | 83 | stk.clear(); 84 | stk.push(1.2e11); 85 | StackTrig.cmdTrig(stk, "cos", ""); 86 | StackCommands.cmdRound(stk, "7"); 87 | assertEquals("-0.4999999", stk.peek().toEngineeringString()); 88 | assertEquals(1, stk.size()); 89 | 90 | // Testing Cosine - Radians 91 | stk.clear(); 92 | stk.push(1.2); 93 | StackTrig.cmdTrig(stk, "cos", "rad"); 94 | StackCommands.cmdRound(stk, "5"); 95 | assertEquals(0.36236, stk.peek().doubleValue()); 96 | assertEquals(1, stk.size()); 97 | 98 | stk.clear(); 99 | stk.push(1.2e11); 100 | StackTrig.cmdTrig(stk, "cos", "rad"); 101 | StackCommands.cmdRound(stk, "7"); 102 | assertEquals("0.9851738", stk.peek().toEngineeringString()); 103 | assertEquals(1, stk.size()); 104 | 105 | // Testing Tangent - Degrees 106 | stk.clear(); 107 | stk.push(23.0); 108 | StackTrig.cmdTrig(stk, "tan", ""); 109 | StackCommands.cmdRound(stk, "5"); 110 | assertEquals(0.42447, stk.peek().doubleValue()); 111 | assertEquals(1, stk.size()); 112 | 113 | stk.clear(); 114 | stk.push(1.2e11); 115 | StackTrig.cmdTrig(stk, "tan", ""); 116 | StackCommands.cmdRound(stk, "7"); 117 | assertEquals("-1.7320512", stk.peek().toEngineeringString()); 118 | assertEquals(1, stk.size()); 119 | 120 | // Testing Tangent - Radians 121 | stk.clear(); 122 | stk.push(16.0); 123 | StackTrig.cmdTrig(stk, "tan", "rad"); 124 | StackCommands.cmdRound(stk, "5"); 125 | assertEquals(0.30063, stk.peek().doubleValue()); 126 | assertEquals(1, stk.size()); 127 | 128 | stk.clear(); 129 | stk.push(1.2e11); 130 | StackTrig.cmdTrig(stk, "tan", "rad"); 131 | StackCommands.cmdRound(stk, "7"); 132 | assertEquals("0.1741414", stk.peek().toEngineeringString()); 133 | assertEquals(1, stk.size()); 134 | 135 | } 136 | 137 | /** 138 | * Test method for 139 | * {@link org.fross.rpncalc.StackTrig#cmdArcTrig(org.fross.rpncalc.StackObj, java.lang.String, java.lang.String)}. 140 | */ 141 | @Test 142 | void testCmdArcTrig() { 143 | StackObj stk = new StackObj(); 144 | 145 | // Testing ArcSine - Degrees 146 | stk.push(0.123); 147 | StackTrig.cmdArcTrig(stk, "asin", ""); 148 | StackCommands.cmdRound(stk, "5"); 149 | assertEquals(7.06527, stk.peek().doubleValue()); 150 | assertEquals(1, stk.size()); 151 | 152 | // Testing ArcSine - Radians 153 | stk.clear(); 154 | stk.push(.123); 155 | StackTrig.cmdArcTrig(stk, "asin", "rad"); 156 | StackCommands.cmdRound(stk, "5"); 157 | assertEquals(0.12331, stk.peek().doubleValue()); 158 | assertEquals(1, stk.size()); 159 | 160 | // Testing ArcCosine - Degrees 161 | stk.clear(); 162 | stk.push(.345); 163 | StackTrig.cmdArcTrig(stk, "acos", ""); 164 | StackCommands.cmdRound(stk, "5"); 165 | assertEquals(69.8182, stk.peek().doubleValue()); 166 | assertEquals(1, stk.size()); 167 | 168 | // Testing ArcCosine - Radians 169 | stk.clear(); 170 | stk.push(.345); 171 | StackTrig.cmdArcTrig(stk, "acos", "rad"); 172 | StackCommands.cmdRound(stk, "5"); 173 | assertEquals(1.21856, stk.peek().doubleValue()); 174 | assertEquals(1, stk.size()); 175 | 176 | // Testing ArcTangent - Degrees 177 | stk.clear(); 178 | stk.push(2.123); 179 | StackTrig.cmdArcTrig(stk, "atan", ""); 180 | StackCommands.cmdRound(stk, "5"); 181 | assertEquals(64.77808, stk.peek().doubleValue()); 182 | assertEquals(1, stk.size()); 183 | 184 | // Testing ArcTangent - Radians 185 | stk.clear(); 186 | stk.push(2.123); 187 | StackTrig.cmdArcTrig(stk, "atan", "rad"); 188 | StackCommands.cmdRound(stk, "5"); 189 | assertEquals(1.13059, stk.peek().doubleValue()); 190 | assertEquals(1, stk.size()); 191 | 192 | } 193 | 194 | /** 195 | * Test method for {@link org.fross.rpncalc.StackTrig#cmdHypotenuse(org.fross.rpncalc.StackObj)}. 196 | */ 197 | @Test 198 | void testCmdHypotenuse() { 199 | StackObj stk = new StackObj(); 200 | 201 | stk.push(3.0); 202 | stk.push(4.0); 203 | StackTrig.cmdHypotenuse(stk); 204 | assertEquals(5.0, stk.peek().doubleValue()); 205 | assertEquals(1, stk.size()); 206 | 207 | stk.push(8.123); 208 | stk.push(4.789); 209 | StackTrig.cmdHypotenuse(stk); 210 | StackCommands.cmdRound(stk, "5"); 211 | assertEquals(9.42962, stk.peek().doubleValue()); 212 | assertEquals(2, stk.size()); 213 | 214 | stk.push(12.65421); 215 | stk.push(15.69857741); 216 | StackTrig.cmdHypotenuse(stk); 217 | StackCommands.cmdRound(stk, "9"); 218 | assertEquals(20.163689231, stk.peek().doubleValue()); 219 | assertEquals(3, stk.size()); 220 | 221 | } 222 | 223 | } 224 | -------------------------------------------------------------------------------- /src/main/java/org/fross/library/Output.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 org.fusesource.jansi.Ansi; 32 | import org.fusesource.jansi.Ansi.Attribute; 33 | import org.fusesource.jansi.Ansi.Erase; 34 | import org.fusesource.jansi.AnsiConsole; 35 | 36 | public class Output { 37 | static boolean colorizedOutput = true; // By default, color is enabled 38 | 39 | /** 40 | * enableColor(): Enable or disable colorized output 41 | * 42 | * @param value 43 | */ 44 | public static void enableColor(boolean value) { 45 | colorizedOutput = value; 46 | } 47 | 48 | /** 49 | * queryColorEnabled(): Return true if colorized output is configured. False if not. 50 | * 51 | * @return 52 | */ 53 | public static boolean queryColorEnabled() { 54 | return colorizedOutput; 55 | } 56 | 57 | /** 58 | * printColorln(): Print to the console with the provided foreground color 59 | * 60 | * Allowable colors are: - Ansi.Color.BLACK - Ansi.Color.RED - Ansi.Color.GREEN - Ansi.Color.YELLOW - Ansi.Color.BLUE - 61 | * Ansi.Color.MAGENTA - Ansi.Color.CYAN - Ansi.Color.WHITE - Ansi.Color.DEFAULT 62 | * 63 | * @param Color 64 | * @param msg 65 | */ 66 | public static void printColorln(Ansi.Color clr, String msg) { 67 | if (colorizedOutput) { 68 | System.out.println(ansi().a(Attribute.INTENSITY_BOLD).fg(clr).a(msg).reset()); 69 | } else { 70 | println(msg); 71 | } 72 | } 73 | 74 | /** 75 | * printColorln(): Overloaded. Added background parameter 76 | * 77 | * @param fclr 78 | * @param bclr 79 | * @param msg 80 | */ 81 | public static void printColorln(Ansi.Color fclr, Ansi.Color bclr, String msg) { 82 | if (colorizedOutput) { 83 | System.out.println(ansi().a(Attribute.INTENSITY_BOLD).fg(fclr).bg(bclr).a(msg).reset()); 84 | Ansi.ansi().reset(); 85 | } else { 86 | print(msg); 87 | } 88 | } 89 | 90 | /** 91 | * printColorln(): Overloaded. FG Color can be selected by an index number 0-256 92 | * 93 | * @param colorIndexFG 94 | * @param msg 95 | */ 96 | public static void printColorln(int colorIndexFG, String msg) { 97 | if (colorizedOutput) { 98 | System.out.println(ansi().fg(colorIndexFG).a(msg).reset()); 99 | } else { 100 | println(msg); 101 | } 102 | } 103 | 104 | /** 105 | * printColor(): Print to the console with the provided foreground color 106 | * 107 | * Allowable colors are: - Ansi.Color.BLACK - Ansi.Color.RED - Ansi.Color.GREEN - Ansi.Color.YELLOW - Ansi.Color.BLUE - 108 | * Ansi.Color.MAGENTA - Ansi.Color.CYAN - Ansi.Color.WHITE - Ansi.Color.DEFAULT 109 | * 110 | * @param fclr 111 | * @param msg 112 | */ 113 | public static void printColor(Ansi.Color fclr, String msg) { 114 | if (colorizedOutput) { 115 | System.out.print(ansi().a(Attribute.INTENSITY_BOLD).fg(fclr).a(msg).reset()); 116 | } else { 117 | print(msg); 118 | } 119 | } 120 | 121 | /** 122 | * printColor(): Overloaded. Added background parameter 123 | * 124 | * @param fclr 125 | * @param bclr 126 | * @param msg 127 | */ 128 | public static void printColor(Ansi.Color fclr, Ansi.Color bclr, String msg) { 129 | if (colorizedOutput) { 130 | System.out.print(ansi().a(Attribute.INTENSITY_BOLD).fg(fclr).bg(bclr).a(msg).reset()); 131 | Ansi.ansi().reset(); 132 | } else { 133 | print(msg); 134 | } 135 | } 136 | 137 | /** 138 | * printColor(): Overloaded. FG Color can be selected by an index number 0-256 139 | * 140 | * @param colorIndexFG 141 | * @param msg 142 | */ 143 | public static void printColor(int colorIndexFG, String msg) { 144 | if (colorizedOutput) { 145 | System.out.println(ansi().fg(colorIndexFG).a(msg).reset()); 146 | } else { 147 | println(msg); 148 | } 149 | } 150 | 151 | /** 152 | * printColor(): Overloaded. FG & BG Color can be selected by an index number 0-256 153 | * 154 | * @param colorIndexFG 155 | * @param msg 156 | */ 157 | public static void printColor(int colorIndexFG, int colorIndexBG, String msg) { 158 | if (colorizedOutput) { 159 | System.out.println(ansi().fg(colorIndexFG).bg(colorIndexBG).a(msg).reset()); 160 | } else { 161 | println(msg); 162 | } 163 | } 164 | 165 | /** 166 | * println(): Basic System.out.println call. It's here so all text output can go through this function. 167 | * 168 | * @param msg 169 | */ 170 | public static void println(String msg) { 171 | System.out.println(msg); 172 | } 173 | 174 | /** 175 | * print(): Basic System.out.print call. It's here so out text output can go through this function. 176 | * 177 | * @param msg 178 | */ 179 | public static void print(String msg) { 180 | System.out.print(msg); 181 | } 182 | 183 | /** 184 | * fatalError(): Print the provided string in RED and exit the program with the error code given 185 | * 186 | * @param msg 187 | * @param errorCode 188 | */ 189 | public static void fatalError(String msg, int errorCode) { 190 | Output.printColorln(Ansi.Color.RED, "\nFATAL ERROR: " + msg); 191 | System.exit(errorCode); 192 | } 193 | 194 | /** 195 | * debugPrintln(): Print the provided text in RED with the preface of DEBUG: with a newline 196 | * 197 | * @param msg 198 | */ 199 | public static void debugPrintln(String msg) { 200 | if (Debug.query()) { 201 | Output.printColorln(Ansi.Color.RED, "DEBUG: " + msg); 202 | } 203 | } 204 | 205 | /** 206 | * debugPrint(): Print the provided text in RED with the preface of DEBUG: and no new line at the end 207 | * 208 | * @param msg 209 | */ 210 | public static void debugPrint(String msg) { 211 | if (Debug.query()) { 212 | Output.printColor(Ansi.Color.RED, "DEBUG: " + msg); 213 | } 214 | } 215 | 216 | /** 217 | * clearScreen(): Uses the JAnsi library to clear the screen 218 | */ 219 | public static void clearScreen() { 220 | // Can only clear the screen if ANSI sequences are being used 221 | if (queryColorEnabled()) { 222 | // Clear the screen 223 | System.out.println(ansi().eraseScreen(Erase.ALL).reset()); 224 | 225 | // Position cursor at the top 226 | System.out.println(ansi().cursor(0, 0)); 227 | } 228 | } 229 | 230 | /** 231 | * JAnsi256Test(): Simple printout of colors to test jAnsi 256 on terminals 232 | * 233 | */ 234 | public static void JAnsi256Test() { 235 | // Test Foregrounds 236 | Ansi ansi = Ansi.ansi(); 237 | for (int index = 0; index < 256; index++) { 238 | // ansi.fg(index).a("FG %d ".formatted(index)); 239 | System.out.print(ansi().fg(index).a(String.format("FG%d ", index)).reset()); 240 | } 241 | AnsiConsole.out().println(ansi); 242 | System.out.println("\n"); 243 | 244 | // Test Backgrounds 245 | ansi = Ansi.ansi(); 246 | for (int index = 0; index < 256; index++) { 247 | // ansi.bg(index).a("BG %d ".formatted(index)); 248 | System.out.print(ansi().bg(index).a(String.format("BG%d ", index)).reset()); 249 | } 250 | AnsiConsole.out().println(ansi); 251 | } 252 | 253 | } --------------------------------------------------------------------------------