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