/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include #include #include #include #include #include #include #include #include "cmsys/Encoding.hxx" #include "cmCursesColor.h" #include "cmCursesForm.h" #include "cmCursesMainForm.h" #include "cmCursesStandardIncludes.h" #include "cmDocumentation.h" #include "cmDocumentationEntry.h" // IWYU pragma: keep #include "cmMessageMetadata.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmake.h" static const char* cmDocumentationName[][2] = { { nullptr, " ccmake - Curses Interface for CMake." }, { nullptr, nullptr } }; static const char* cmDocumentationUsage[][2] = { { nullptr, " ccmake \n" " ccmake " }, { nullptr, "Specify a source directory to (re-)generate a build system for " "it in the current working directory. Specify an existing build " "directory to re-generate its build system." }, { nullptr, nullptr } }; static const char* cmDocumentationUsageNote[][2] = { { nullptr, "Run 'ccmake --help' for more information." }, { nullptr, nullptr } }; static const char* cmDocumentationOptions[][2] = { CMAKE_STANDARD_OPTIONS_TABLE, { nullptr, nullptr } }; cmCursesForm* cmCursesForm::CurrentForm = nullptr; extern "C" { void onsig(int /*unused*/) { if (cmCursesForm::CurrentForm) { endwin(); if (initscr() == nullptr) { static const char errmsg[] = "Error: ncurses initialization failed\n"; auto r = write(STDERR_FILENO, errmsg, sizeof(errmsg) - 1); static_cast(r); exit(1); } noecho(); /* Echo off */ cbreak(); /* nl- or cr not needed */ keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ refresh(); int x; int y; getmaxyx(stdscr, y, x); cmCursesForm::CurrentForm->Render(1, 1, x, y); cmCursesForm::CurrentForm->UpdateStatusBar(); } signal(SIGWINCH, onsig); } } int main(int argc, char const* const* argv) { cmSystemTools::EnsureStdPipes(); cmsys::Encoding::CommandLineArguments encoding_args = cmsys::Encoding::CommandLineArguments::Main(argc, argv); argc = encoding_args.argc(); argv = encoding_args.argv(); cmSystemTools::InitializeLibUV(); cmSystemTools::FindCMakeResources(argv[0]); cmDocumentation doc; doc.addCMakeStandardDocSections(); if (doc.CheckOptions(argc, argv)) { cmake hcm(cmake::RoleInternal, cmState::Unknown); hcm.SetHomeDirectory(""); hcm.SetHomeOutputDirectory(""); hcm.AddCMakePaths(); auto generators = hcm.GetGeneratorsDocumentation(); doc.SetName("ccmake"); doc.SetSection("Name", cmDocumentationName); doc.SetSection("Usage", cmDocumentationUsage); if (argc == 1) { doc.AppendSection("Usage", cmDocumentationUsageNote); } doc.AppendSection("Generators", generators); doc.PrependSection("Options", cmDocumentationOptions); return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1; } bool debug = false; unsigned int i; int j; std::vector args; for (j = 0; j < argc; ++j) { if (strcmp(argv[j], "-debug") == 0) { debug = true; } else { args.emplace_back(argv[j]); } } std::string cacheDir = cmSystemTools::GetCurrentWorkingDirectory(); for (i = 1; i < args.size(); ++i) { std::string const& arg = args[i]; if (cmHasPrefix(arg, "-B")) { cacheDir = arg.substr(2); } } cmSystemTools::DisableRunCommandOutput(); if (debug) { cmCursesForm::DebugStart(); } if (initscr() == nullptr) { fprintf(stderr, "Error: ncurses initialization failed\n"); exit(1); } noecho(); /* Echo off */ cbreak(); /* nl- or cr not needed */ keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ cmCursesColor::InitColors(); signal(SIGWINCH, onsig); int x; int y; getmaxyx(stdscr, y, x); if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) { endwin(); std::cerr << "Window is too small. A size of at least " << cmCursesMainForm::MIN_WIDTH << " x " << cmCursesMainForm::MIN_HEIGHT << " is required to run ccmake." << std::endl; return 1; } cmCursesMainForm* myform; myform = new cmCursesMainForm(args, x); if (myform->LoadCache(cacheDir.c_str())) { curses_clear(); touchwin(stdscr); endwin(); delete myform; std::cerr << "Error running cmake::LoadCache(). Aborting.\n"; return 1; } /* * The message is stored in a list by the form which will be * joined by '\n' before display. * Removing any trailing '\n' avoid extra empty lines in the final results */ auto cleanMessage = [](const std::string& message) -> std::string { auto msg = message; if (!msg.empty() && msg.back() == '\n') { msg.pop_back(); } return msg; }; cmSystemTools::SetMessageCallback( [&](const std::string& message, const cmMessageMetadata& md) { myform->AddError(cleanMessage(message), md.title); }); cmSystemTools::SetStderrCallback([&](const std::string& message) { myform->AddError(cleanMessage(message), ""); }); cmSystemTools::SetStdoutCallback([&](const std::string& message) { myform->UpdateProgress(cleanMessage(message), -1); }); cmCursesForm::CurrentForm = myform; myform->InitializeUI(); if (myform->Configure(1) == 0) { myform->Render(1, 1, x, y); myform->HandleInput(); } // Need to clean-up better curses_clear(); touchwin(stdscr); endwin(); delete cmCursesForm::CurrentForm; cmCursesForm::CurrentForm = nullptr; std::cout << std::endl << std::endl; return 0; }