Merge branch 'release-3.29'
[kiteware-cmake.git] / Source / CursesDialog / ccmake.cxx
blob18c1a807f1e2105d2a66f93d221aaa79cc7781cd
1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
4 #include <csignal>
5 #include <cstdio>
6 #include <cstdlib>
7 #include <cstring>
8 #include <iostream>
9 #include <string>
10 #include <vector>
12 #include "cmsys/Encoding.hxx"
14 #include "cmCursesColor.h"
15 #include "cmCursesForm.h"
16 #include "cmCursesMainForm.h"
17 #include "cmCursesStandardIncludes.h"
18 #include "cmDocumentation.h"
19 #include "cmDocumentationEntry.h"
20 #include "cmMessageMetadata.h"
21 #include "cmState.h"
22 #include "cmStringAlgorithms.h"
23 #include "cmSystemTools.h"
24 #include "cmake.h"
26 namespace {
27 const cmDocumentationEntry cmDocumentationName = {
28 {},
29 " ccmake - Curses Interface for CMake."
32 const cmDocumentationEntry cmDocumentationUsage[2] = {
33 { {},
34 " ccmake <path-to-source>\n"
35 " ccmake <path-to-existing-build>" },
36 { {},
37 "Specify a source directory to (re-)generate a build system for "
38 "it in the current working directory. Specify an existing build "
39 "directory to re-generate its build system." },
42 const cmDocumentationEntry cmDocumentationUsageNote = {
43 {},
44 "Run 'ccmake --help' for more information."
47 #ifndef _WIN32
48 extern "C" {
50 void onsig(int /*unused*/)
52 if (cmCursesForm::CurrentForm) {
53 cmCursesForm::CurrentForm->HandleResize();
55 signal(SIGWINCH, onsig);
58 #endif // _WIN32
59 } // anonymous namespace
61 cmCursesForm* cmCursesForm::CurrentForm = nullptr;
63 int main(int argc, char const* const* argv)
65 cmSystemTools::EnsureStdPipes();
66 cmsys::Encoding::CommandLineArguments encoding_args =
67 cmsys::Encoding::CommandLineArguments::Main(argc, argv);
68 argc = encoding_args.argc();
69 argv = encoding_args.argv();
71 cmSystemTools::InitializeLibUV();
72 cmSystemTools::FindCMakeResources(argv[0]);
73 cmDocumentation doc;
74 doc.addCMakeStandardDocSections();
75 if (doc.CheckOptions(argc, argv)) {
76 cmake hcm(cmake::RoleInternal, cmState::Help);
77 hcm.SetHomeDirectory("");
78 hcm.SetHomeOutputDirectory("");
79 hcm.AddCMakePaths();
80 auto generators = hcm.GetGeneratorsDocumentation();
81 doc.SetName("ccmake");
82 doc.SetSection("Name", cmDocumentationName);
83 doc.SetSection("Usage", cmDocumentationUsage);
84 if (argc == 1) {
85 doc.AppendSection("Usage", cmDocumentationUsageNote);
87 doc.AppendSection("Generators", generators);
88 doc.PrependSection("Options", cmake::CMAKE_STANDARD_OPTIONS_TABLE);
89 return !doc.PrintRequestedDocumentation(std::cout);
92 bool debug = false;
93 unsigned int i;
94 int j;
95 std::vector<std::string> args;
96 for (j = 0; j < argc; ++j) {
97 if (strcmp(argv[j], "-debug") == 0) {
98 debug = true;
99 } else {
100 args.emplace_back(argv[j]);
104 std::string cacheDir = cmSystemTools::GetCurrentWorkingDirectory();
105 for (i = 1; i < args.size(); ++i) {
106 std::string const& arg = args[i];
107 if (cmHasPrefix(arg, "-B")) {
108 cacheDir = arg.substr(2);
112 cmSystemTools::DisableRunCommandOutput();
114 if (debug) {
115 cmCursesForm::DebugStart();
118 if (initscr() == nullptr) {
119 fprintf(stderr, "Error: ncurses initialization failed\n");
120 exit(1);
122 noecho(); /* Echo off */
123 cbreak(); /* nl- or cr not needed */
124 keypad(stdscr, true); /* Use key symbols as KEY_DOWN */
125 cmCursesColor::InitColors();
127 #ifndef _WIN32
128 signal(SIGWINCH, onsig);
129 #endif // _WIN32
131 int x;
132 int y;
133 getmaxyx(stdscr, y, x);
134 if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) {
135 endwin();
136 std::cerr << "Window is too small. A size of at least "
137 << cmCursesMainForm::MIN_WIDTH << " x "
138 << cmCursesMainForm::MIN_HEIGHT << " is required to run ccmake."
139 << std::endl;
140 return 1;
143 cmCursesMainForm* myform;
145 myform = new cmCursesMainForm(args, x);
146 if (myform->LoadCache(cacheDir.c_str())) {
147 curses_clear();
148 touchwin(stdscr);
149 endwin();
150 delete myform;
151 std::cerr << "Error running cmake::LoadCache(). Aborting.\n";
152 return 1;
156 * The message is stored in a list by the form which will be
157 * joined by '\n' before display.
158 * Removing any trailing '\n' avoid extra empty lines in the final results
160 auto cleanMessage = [](const std::string& message) -> std::string {
161 auto msg = message;
162 if (!msg.empty() && msg.back() == '\n') {
163 msg.pop_back();
165 return msg;
167 cmSystemTools::SetMessageCallback(
168 [&](const std::string& message, const cmMessageMetadata& md) {
169 myform->AddError(cleanMessage(message), md.title);
171 cmSystemTools::SetStderrCallback([&](const std::string& message) {
172 myform->AddError(cleanMessage(message), "");
174 cmSystemTools::SetStdoutCallback([&](const std::string& message) {
175 myform->UpdateProgress(cleanMessage(message), -1);
178 cmCursesForm::CurrentForm = myform;
180 myform->InitializeUI();
181 if (myform->Configure(1) == 0) {
182 myform->Render(1, 1, x, y);
183 myform->HandleInput();
186 // Need to clean-up better
187 curses_clear();
188 touchwin(stdscr);
189 endwin();
190 delete cmCursesForm::CurrentForm;
191 cmCursesForm::CurrentForm = nullptr;
193 std::cout << std::endl << std::endl;
195 return 0;