libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
command.hpp
1
20void GetArgs()
21{
22 for (int i = 0; input_line_[i] != '\0'; i++)
23 {
24 if (input_line_[i] == ' ')
25 {
26 input_line_[i] = '\0';
27 }
28 else if (i == 0 || input_line_[i - 1] == '\0')
29 {
30 if (arg_number_ >= MAX_ARG_NUMBER)
31 {
32 return;
33 }
34 arg_tab_[arg_number_++] = &input_line_[i];
35 }
36 }
37}
38
51RamFS::Dir* Path2Dir(char* path)
52{
53 if (path == nullptr)
54 {
55 return nullptr;
56 }
57
58 size_t index = 0;
59 RamFS::Dir* dir = current_dir_;
60
61 if (*path == '/')
62 {
63 index++;
64 dir = &ramfs_.root_;
65 if (path[index] == '\0')
66 {
67 return dir;
68 }
69 }
70
71 for (size_t i = 0; i < MAX_LINE_SIZE; i++)
72 {
73 auto tmp = strchr(path + index, '/');
74 if (tmp == nullptr)
75 {
76 return dir->FindDir(path + index);
77 }
78 else if (tmp == path + index)
79 {
80 return nullptr;
81 }
82 else
83 {
84 tmp[0] = '\0';
85 dir = dir->FindDir(path + index);
86 tmp[0] = '/';
87 index = static_cast<size_t>(tmp - path + 1);
88 if (path[index] == '\0' || dir == nullptr)
89 {
90 return dir;
91 }
92 }
93 }
94
95 return nullptr;
96}
97
109RamFS::File* Path2File(char* path)
110{
111 if (path == nullptr)
112 {
113 return nullptr;
114 }
115
116 auto name = StrchrRev(path, '/');
117
118 if (name == nullptr)
119 {
120 return current_dir_->FindFile(path);
121 }
122
123 if (name[1] == '\0')
124 {
125 return nullptr;
126 }
127
128 *name = '\0';
129 RamFS::Dir* dir = name == path ? &ramfs_.root_ : Path2Dir(path);
130 *name = '/';
131 if (dir != nullptr)
132 {
133 return dir->FindFile(name + 1);
134 }
135 else
136 {
137 return nullptr;
138 }
139}
140
151void ExecuteCommand()
152{
153 AddHistory();
154
155 GetArgs();
156
157 if (arg_number_ < 1 || arg_number_ > MAX_ARG_NUMBER)
158 {
159 return;
160 }
161
162 if (strcmp(arg_tab_[0], "cd") == 0)
163 {
164 RamFS::Dir* dir = arg_number_ >= 2 ? Path2Dir(arg_tab_[1]) : nullptr;
165 if (dir != nullptr)
166 {
167 current_dir_ = dir;
168 }
169 LineFeed();
170 return;
171 }
172
173 if (strcmp(arg_tab_[0], "ls") == 0)
174 {
175 auto ls_fun = [&](RamFS::FsNode& item)
176 {
177 switch (item.GetNodeType())
178 {
179 case RamFS::FsNodeType::DIR:
180 write_stream_ << ConstRawData("d ");
181 break;
182 case RamFS::FsNodeType::FILE:
183 if (static_cast<RamFS::File&>(item).IsExecutable())
184 {
185 write_stream_ << ConstRawData("x ");
186 }
187 else
188 {
189 write_stream_ << ConstRawData("f ");
190 }
191 break;
192 case RamFS::FsNodeType::CUSTOM:
193 write_stream_ << ConstRawData("? ");
194 break;
195 default:
196 write_stream_ << ConstRawData("? ");
197 break;
198 }
199 write_stream_ << ConstRawData(item.GetName());
200 this->LineFeed();
201 return ErrorCode::OK;
202 };
203
204 current_dir_->Foreach(ls_fun);
205 return;
206 }
207
208 auto* ans = Path2File(arg_tab_[0]);
209
210 if (ans == nullptr)
211 {
212 write_stream_ << ConstRawData("Command not found.");
213 LineFeed();
214 return;
215 }
216
217 if (!ans->IsExecutable())
218 {
219 write_stream_ << ConstRawData("Not an executable file.");
220 LineFeed();
221 return;
222 }
223
224 // 输出尽力提交后执行命令 / Commit output on a best-effort basis before running it.
225 (void)write_stream_.Commit();
226 write_mutex_->Unlock();
227 ans->Run(arg_number_, arg_tab_);
228 write_mutex_->Lock();
229}
230
239void AutoComplete()
240{
241 /* skip space */
242 char* path = &input_line_[0];
243 while (*path == ' ')
244 {
245 path++;
246 }
247
248 /* find last '/' in first argument */
249 char *tmp = path, *path_end = path;
250
251 while (*tmp != ' ' && *tmp != '\0')
252 {
253 if (*tmp == '/')
254 {
255 path_end = tmp;
256 }
257 tmp++;
258 }
259
260 /* return if not need complete */
261 if (tmp - &input_line_[0] != static_cast<int>(input_line_.Size() + offset_))
262 {
263 return;
264 }
265
266 /* get start of prefix */
267 char* prefix_start = nullptr;
268 RamFS::Dir* dir = nullptr;
269
270 if (path_end == path)
271 {
272 dir = current_dir_;
273 prefix_start = path_end;
274 }
275 else
276 {
277 prefix_start = path_end + 1;
278 }
279
280 /* find dir*/
281 if (dir == nullptr)
282 {
283 *path_end = '\0';
284 dir = Path2Dir(path);
285 *path_end = '/';
286 if (dir == nullptr)
287 {
288 return;
289 }
290 }
291
292 /* prepre for match */
293 RamFS::FsNode* ans_node = nullptr;
294 uint32_t number = 0;
295 size_t shared_prefix_len = 0;
296
297 if (*prefix_start == '/')
298 {
299 prefix_start++;
300 }
301
302 int prefix_len = static_cast<int>(tmp - prefix_start);
303
304 auto foreach_fun_find = [&](RamFS::FsNode& node)
305 {
306 if (strncmp(node.GetName(), prefix_start, prefix_len) == 0)
307 {
308 ans_node = &node;
309 number++;
310 }
311
312 return ErrorCode::OK;
313 };
314
315 /* start match */
316 dir->Foreach(foreach_fun_find);
317
318 if (number == 0)
319 {
320 return;
321 }
322 else if (number == 1)
323 {
324 auto name_len = strlen(ans_node->GetName());
325 for (size_t i = 0; i < name_len - prefix_len; i++)
326 {
327 DisplayChar(ans_node->GetName()[i + prefix_len]);
328 }
329 }
330 else
331 {
332 ans_node = nullptr;
333 LineFeed();
334
335 auto foreach_fun_show = [&](RamFS::FsNode& node)
336 {
337 if (strncmp(node.GetName(), prefix_start, prefix_len) == 0)
338 {
339 auto name_len = strlen(node.GetName());
340 write_stream_ << ConstRawData(node.GetName(), name_len);
341 this->LineFeed();
342 if (ans_node == nullptr)
343 {
344 ans_node = &node;
345 shared_prefix_len = name_len;
346 return ErrorCode::OK;
347 }
348
349 for (size_t i = 0; i < name_len; i++)
350 {
351 if (node.GetName()[i] != ans_node->GetName()[i])
352 {
353 shared_prefix_len = i;
354 break;
355 }
356 }
357
358 // Once one candidate is shorter than the previously retained shared
359 // prefix, the shared prefix must shrink to this candidate length.
360 if (shared_prefix_len > name_len)
361 {
362 shared_prefix_len = name_len;
363 }
364
365 ans_node = &node;
366 }
367
368 return ErrorCode::OK;
369 };
370
371 dir->Foreach(foreach_fun_show);
372
373 ShowHeader();
374 write_stream_ << ConstRawData(&input_line_[0], input_line_.Size());
375
376 for (size_t i = 0; i < shared_prefix_len - prefix_len; i++)
377 {
378 DisplayChar(ans_node->GetName()[i + prefix_len]);
379 }
380 }
381}