GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
cmdio_util.cpp
[詳解]
1
3
4// Copyright(c) 2023-2025 Design Engineering Laboratory, Saitama University
5// Released under the MIT license
6// https://opensource.org/licenses/mit-license.php
7
8#include "cmdio_util.h"
9
10#include <cstdlib>
11#include <iostream>
12#include <magic_enum.hpp>
13#include <sstream>
14#include <string>
15#include <vector>
16
17#include "cassert_define.h"
18#include "string_util.h"
19
20namespace designlab {
21
23
24bool do_output = true;
25
26bool is_initialized = false;
27
29 output_limit = limit;
30
31 if (!is_initialized) {
32 // これを記述しておくと実行速度が早くなる.
33 // そのかわり printf を使用できなくなる.
34 std::cin.tie(&std::cout);
35 std::ios_base::sync_with_stdio(true);
36
37 is_initialized = true;
38 }
39
40 // 出力の許可範囲を設定したことを通知.
41 OutputF(OutputDetail::kSystem, "Output limit is set to '{}'.",
43}
44
45void cmdio::DoOutput(const bool do_output_) { do_output = do_output_; }
46
47void cmdio::Output(const std::string& str, const OutputDetail detail) {
48 assert(is_initialized); // SetOutputLimitを呼んでから使用すること.
49
50 // 出力を許可している かつ
51 // 出力する文字列の詳細が設定ファイルで許可されている場合
52 // または,出力を許可していない かつ
53 // 出力する文字列の詳細がシステムメッセージの場合.
54
55 if ((detail <= output_limit && do_output) ||
56 (detail == OutputDetail::kSystem && !do_output)) {
57 if (str == "") {
58 std::cout << std::endl;
59 return;
60 }
61
62 // システムメッセージでない場合は,タグをつける.
63 const std::string tag =
64 (detail == OutputDetail::kSystem
65 ? ""
66 : " [" + string_util::EnumToStringRemoveTopK(detail) + "] ");
67
68#if defined(DESIGNLAB_USE_COLOR_OUTPUT)
69
70 if (detail == OutputDetail::kError) {
71 std::cout << "\x1b[31m";
72 } // 赤色.
73 if (detail == OutputDetail::kWarning) {
74 std::cout << "\x1b[33m";
75 } // 黄色.
76 if (detail == OutputDetail::kInfo) {
77 std::cout << "\x1b[36m";
78 } // シアン.
79 if (detail == OutputDetail::kDebug) {
80 std::cout << "\x1b[32m";
81 } // 緑色.
82
83#endif // DESIGNLAB_USE_COLOR_OUTPUT
84
85 std::cout << tag;
86
87 // タグと同じ長さの空白を出力する.
88 const std::string space(tag.size(), ' ');
89
90 // 改行ごとに文字列を取り出す.
91 const auto line = string_util::Split(str, "\n");
92
93 for (size_t i = 0; i < line.size(); i++) {
94 if (i != 0) {
95 std::cout << space;
96 }
97
98 if (detail != OutputDetail::kSystem) {
99 std::cout << "| ";
100 }
101
102 std::cout << line[i] << std::endl;
103 }
104
105#if defined(DESIGNLAB_USE_COLOR_OUTPUT)
106 std::cout << "\x1b[0m"; // 色をリセット.
107#endif // DESIGNLAB_USE_COLOR_OUTPUT
108 }
109}
110
111void cmdio::SpacedOutput(const std::string& str, OutputDetail detail) {
112 OutputNewLine(1, detail);
113 Output(str, detail);
114 OutputNewLine(1, detail);
115}
116
117void cmdio::OutputCenter(const std::string& str, const OutputDetail detail) {
118 // 改行ごとに文字列を取り出す.
119 std::stringstream ss(str);
120 std::string line;
121
122 while (std::getline(ss, line)) {
123 if (kHorizontalLineLength > line.length()) {
124 std::string space;
125
126 const int space_num =
127 (kHorizontalLineLength - static_cast<int>(line.length())) / 2;
128
129 for (int i = 0; i < space_num; ++i) {
130 space += " ";
131 }
132
133 Output(space + line, detail);
134 } else {
135 Output(line, detail);
136 }
137 }
138}
139
140void cmdio::OutputRight(const std::string& str, const OutputDetail detail) {
141 // 改行ごとに文字列を取り出す.
142 std::stringstream ss(str);
143 std::string line;
144
145 while (std::getline(ss, line)) {
146 if (kHorizontalLineLength > line.length()) {
147 std::string space;
148
149 const int space_num =
150 kHorizontalLineLength - static_cast<int>(line.length());
151
152 for (int i = 0; i < space_num; ++i) {
153 space += " ";
154 }
155
156 Output(space + line, detail);
157 } else {
158 Output(line, detail);
159 }
160 }
161}
162
163void cmdio::OutputNewLine(const int num, const OutputDetail detail) {
164 if (num <= 0) {
165 return;
166 }
167
168 for (int i = 0; i < num; i++) {
169 Output("", detail);
170 }
171}
172
173void cmdio::OutputHorizontalLine(const std::string& line_visual,
174 const OutputDetail detail) {
175 if (line_visual.size() != 1) {
176 return;
177 }
178
179 std::string str;
180
181 for (int i = 0; i < kHorizontalLineLength; i++) {
182 str += line_visual;
183 }
184
185 Output(str, detail);
186}
187
188void cmdio::OutputTitle(const std::string& title_name, bool output_copy_right) {
190
191 OutputNewLine(1, detail);
192 OutputHorizontalLine("=", detail);
193 OutputNewLine(1, detail);
194 OutputCenter(title_name, detail);
195 OutputNewLine(1, detail);
196
197 if (output_copy_right) {
198 OutputRight("(C) 2023 Design Engineering Laboratory ", detail);
199 OutputNewLine(1, detail);
200 }
201
202 OutputHorizontalLine("=", detail);
203 OutputNewLine(1, detail);
204}
205
206void cmdio::WaitAnyKey(const std::string& str) {
208
209 // 何かキーを押すまで待機.
210 system("PAUSE");
211}
212
213int cmdio::InputInt(const int min, const int max, const int default_num,
214 const std::string& str) {
215 assert(min <= max); // 最小値は最大値より小さい.
216
217 OutputF(OutputDetail::kSystem, "{} ( {} ~ {} ) ", str, min, max);
218
219 std::string input_str;
220 std::cout << ">>" << std::flush;
221 std::cin >> input_str;
222
223 int res = default_num;
224
225 try {
226 res = std::stoi(input_str); // 入力された文字列を int 型に変換.
227
228 if (res < min || res > max) {
230 "The entered value '{}' is out of range. Use the default "
231 "value, '{}'.",
232 input_str, default_num);
233
234 res = default_num;
235 }
236 } catch (...) {
237 // 整数値への変換で例外が発生した場合,ここに処理が飛ぶ.
239 "The entered value '{}' cannot be evaluated. Use the default "
240 "value, '{}'.",
241 input_str, default_num);
242
243 res = default_num;
244 }
245
246 return res;
247}
248
249bool cmdio::InputYesNo(const std::string& str) {
250 Output(str + " ( y / n ) ", OutputDetail::kSystem);
251
252 while (true) {
253 std::string input_str;
254 std::cout << ">>" << std::flush;
255 std::cin >> input_str;
256
257 if (input_str == "y" || input_str == "yes" || input_str == "Y" ||
258 input_str == "Yes" || input_str == "YES") {
259 return true;
260 } else if (input_str == "n" || input_str == "no" || input_str == "N" ||
261 input_str == "No" || input_str == "NO") {
262 return false;
263 }
264
266 "The entered value '{}' cannot be evaluated. Enter 'y' or 'n'.",
267 input_str);
268 }
269}
270
271std::string cmdio::InputDirName(const std::string& str) {
273
274 const std::vector<std::string> invalid_chars = {"\\", "/", ":", "*", "?",
275 "\"", "<", ">", "|"};
276 constexpr int kMaxDirNameLength = 255;
277
278 while (true) {
279 std::string input_str;
280 std::cout << ">>" << std::flush;
281 std::cin >> input_str;
282
283 bool is_invalid = true;
284
285 for (const auto& invalid_char : invalid_chars) {
286 if (input_str.find(invalid_char) != std::string::npos) {
288 "Directory names cannot contain the following characters : \\ / : "
289 "* ? \" < > |");
290 is_invalid = false;
291 break;
292 }
293 }
294
295 if (input_str.find(" ") != std::string::npos) {
296 SystemOutput("Directory names cannot contain spaces.");
297 is_invalid = false;
298 }
299
300 if (input_str.length() > kMaxDirNameLength) {
302 "The entered value '{}' is too long. Enter a value of {} "
303 "characters or less.",
304 input_str, kMaxDirNameLength);
305 is_invalid = false;
306 }
307
308 if (input_str.length() == 0) {
309 SystemOutput("Directory names cannot be empty.");
310 is_invalid = false;
311 }
312
313 if (is_invalid) {
314 return input_str;
315 }
316
317 SystemOutput("Retype the directory name.");
318 }
319}
320
321} // namespace designlab
void OutputF(OutputDetail detail, const std::format_string< Args... > str, Args &&... args)
コマンドラインに文字を出力する関数, format した文字列を出力する. SetOutputLimit() で設定した出力の許可範囲内であれば出力される.
Definition cmdio_util.h:91
std::string InputDirName(const std::string &str="Enter a directory name. (Japanese is not recommended).")
ディレクトリ名を入力させる関数. 出力される文字列は,必ず OutputDetail::kSystem で出力される. ディレクトリ名には次の文字は使えない....
void SpacedOutput(const std::string &str, OutputDetail detail)
コマンドラインに文字を出力する関数. 前と後ろに改行を挿入する.
void OutputHorizontalLine(const std::string &line_visual, OutputDetail detail)
コマンドラインに水平線を出力する関数.
void OutputCenter(const std::string &str, OutputDetail detail)
中央に文字を出力する関数. 文字列が長すぎる場合は普通に左詰めで出力される.
void WaitAnyKey(const std::string &str="Waiting for input.")
入力待ちをする関数. 出力される文字列は, 必ず OutputDetail::kSystem で出力される.
void SystemOutput(const std::string &str)
コマンドラインに文字を出力する関数. System 用の出力.
Definition cmdio_util.h:75
void OutputRight(const std::string &str, OutputDetail detail)
右端に文字を出力する関数. 文字列が長すぎる場合は普通に左詰めで出力される.
int InputInt(int min, int max, int default_num, const std::string &str="Please enter an integer.")
整数を入力させる関数. 出力される文字列は, 必ず OutputDetail::kSystem で出力される.
void OutputNewLine(int num, OutputDetail detail)
コマンドラインで改行をする関数.
void OutputTitle(const std::string &title_name, bool output_copy_right=false)
コマンドラインにこのソフトのタイトルを出力する関数. 出力される文字列は,必ず OutputDetail::kSystem で出力される.
void DoOutput(bool do_output)
そもそも出力をするかを設定する関数. false に設定しても システムメッセージは出力される.
void Output(const std::string &str, OutputDetail detail)
コマンドラインに文字を出力する関数. SetOutputLimit 関数で設定した出力の許可範囲内であれば出力される.
constexpr int kHorizontalLineLength
水平線の長さ.
Definition cmdio_util.h:218
void SetOutputLimit(OutputDetail limit)
出力するメッセージをどこまで許可するかを設定する関数. この関数を呼び出してから出ないと,他の関数を使えない. 例えば kError に設定すると, kError 未満の出力( kInfo とか...
bool InputYesNo(const std::string &str="Are you sure?")
yesかnoを入力させる関数.返り値で yes なら true, no なら false を返す. 出力される文字列は,必ず OutputDetail::kSystem で出力される.
std::vector< std::string > Split(const std::string &str, const std::string &separator)
文字列を分割する関数.指定した文字で文字列を分割する. 分割した結果,空白が含まれる場合や文字列がない場合は,そのまま返す. 最後が区切り文字で終わる場合は,...
std::string EnumToStringRemoveTopK(const T &enum_value)
enumを文字列に変換する関数. Google C++ coding style だと enumの要素は 先頭にkをつけてキャメルケースで書くことが推奨されている....
Definition string_util.h:52
OutputDetail
コマンドラインに文字を出力する際に,その詳細を指定するための列挙体.
@ kInfo
優先度低めの情報.
@ kSystem
システムメッセージ,常に出力する.
@ kDebug
デバッグ時のみ出力,一番優先度が低い.
@ kError
エラーメッセージ.
@ kWarning
警告メッセージ,エラーではないが注意が必要なメッセージ.
bool do_output
OutputDetail output_limit
bool is_initialized