From a4635fb95235ba4bf077bd59957da0626fc5ba72 Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Tue, 14 Dec 2021 12:34:06 -0500 Subject: EC, a terminal-based RPN calculator --- src/main.cc | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/main.cc (limited to 'src/main.cc') diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..959cda0 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,117 @@ +// Copyright 2021 Benjamin Barenblat +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include +#include +#include + +#include +#include +#include + +#include "src/ui/stream.h" +#include "src/ui/terminal.h" +#include "src/util.h" +#include "third_party/abseil/absl/strings/string_view.h" + +namespace { + +constexpr absl::string_view kShortUsage = "Usage: ec [OPTION...] [FILENAME]\n"; + +constexpr absl::string_view kHelp = + R"( +A Reverse Polish scientific calculator. Invoked directly, ec launches an +interactive interpreter that displays the stack and accepts input. Invoked on a +file, ec processes the entire file; if the result stack is nonempty, ec prints +the stack in space-separated form. + +Options: + --help display this help and exit + --version display version information and exit +)"; + +constexpr absl::string_view kAskForHelp = + "Try 'ec --help' for more information.\n"; + +constexpr absl::string_view kVersionInfo = "ec development build\n"; + +enum { + kHelpLongOption = 128, + kVersionLongOption = 129, +}; + +int TerminalUi() { + if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { + return ec::TerminalUi().Main(); + } else { + return ec::LineUi().Main(); + } +} + +int ProcessFile(const char* path) { + std::ifstream file(path); + if (!file.is_open()) { + std::cerr << "ec: failed to open file " << path << '\n'; + return 1; + } + return ec::StreamUi(file).Main(); +} + +} // namespace + +int main(int argc, char* argv[]) { + setlocale(LC_ALL, ""); + + static option long_options[] = { + {"help", no_argument, nullptr, kHelpLongOption}, + {"version", no_argument, nullptr, kVersionLongOption}, + {nullptr, 0, nullptr, 0}, + }; + while (true) { + int c = getopt_long(argc, argv, "", long_options, /*longindex=*/nullptr); + if (c == -1) { + break; + } + switch (c) { + case kHelpLongOption: + std::cout << kShortUsage << kHelp; + return 0; + case kVersionLongOption: + std::cout << kVersionInfo; + return 0; + case '?': + std::cerr << kAskForHelp; + return 1; + default: + std::cerr << "ec: internal error: unhandled getopt switch\nThis is a " + "bug! Please report it.\n"; + return 1; + } + } + + try { + if (optind == argc) { + TerminalUi(); + } else if (optind == argc - 1) { + return ProcessFile(argv[optind]); + } else { + std::cerr << kShortUsage << kAskForHelp; + return 1; + } + } catch (const std::exception& e) { + std::cerr << "ec: internal error: " << DemangleIfPossible(typeid(e).name()) + << ": " << e.what() << "\nThis is a bug! Please report it.\n"; + return 1; + } +} -- cgit v1.2.3