// 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; } }