libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
command.hpp
1
20 void 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
51 RamFS::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
109 RamFS::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
151 void 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 write_stream_.Commit();
225 write_mutex_->Unlock();
226 ans->Run(arg_number_, arg_tab_);
227 write_mutex_->Lock();
228 }
229
238 void AutoComplete()
239 {
240 /* skip space */
241 char* path = &input_line_[0];
242 while (*path == ' ')
243 {
244 path++;
245 }
246
247 /* find last '/' in first argument */
248 char *tmp = path, *path_end = path;
249
250 while (*tmp != ' ' && *tmp != '\0')
251 {
252 if (*tmp == '/')
253 {
254 path_end = tmp;
255 }
256 tmp++;
257 }
258
259 /* return if not need complete */
260 if (tmp - &input_line_[0] != static_cast<int>(input_line_.Size() + offset_))
261 {
262 return;
263 }
264
265 /* get start of prefix */
266 char* prefix_start = nullptr;
267 RamFS::Dir* dir = nullptr;
268
269 if (path_end == path)
270 {
271 dir = current_dir_;
272 prefix_start = path_end;
273 }
274 else
275 {
276 prefix_start = path_end + 1;
277 }
278
279 /* find dir*/
280 if (dir == nullptr)
281 {
282 *path_end = '\0';
283 dir = Path2Dir(path);
284 *path_end = '/';
285 if (dir == nullptr)
286 {
287 return;
288 }
289 }
290
291 /* prepre for match */
292 RamFS::FsNode* ans_node = nullptr;
293 uint32_t number = 0;
294 size_t shared_prefix_len = 0;
295
296 if (*prefix_start == '/')
297 {
298 prefix_start++;
299 }
300
301 int prefix_len = static_cast<int>(tmp - prefix_start);
302
303 auto foreach_fun_find = [&](RamFS::FsNode& node)
304 {
305 if (strncmp(node.GetName(), prefix_start, prefix_len) == 0)
306 {
307 ans_node = &node;
308 number++;
309 }
310
311 return ErrorCode::OK;
312 };
313
314 /* start match */
315 dir->Foreach(foreach_fun_find);
316
317 if (number == 0)
318 {
319 return;
320 }
321 else if (number == 1)
322 {
323 auto name_len = strlen(ans_node->GetName());
324 for (size_t i = 0; i < name_len - prefix_len; i++)
325 {
326 DisplayChar(ans_node->GetName()[i + prefix_len]);
327 }
328 }
329 else
330 {
331 ans_node = nullptr;
332 LineFeed();
333
334 auto foreach_fun_show = [&](RamFS::FsNode& node)
335 {
336 if (strncmp(node.GetName(), prefix_start, prefix_len) == 0)
337 {
338 auto name_len = strlen(node.GetName());
339 write_stream_ << ConstRawData(node.GetName(), name_len);
340 this->LineFeed();
341 if (ans_node == nullptr)
342 {
343 ans_node = &node;
344 shared_prefix_len = name_len;
345 return ErrorCode::OK;
346 }
347
348 for (size_t i = 0; i < name_len; i++)
349 {
350 if (node.GetName()[i] != ans_node->GetName()[i])
351 {
352 shared_prefix_len = i;
353 break;
354 }
355 }
356
357 // Once one candidate is shorter than the previously retained shared
358 // prefix, the shared prefix must shrink to this candidate length.
359 if (shared_prefix_len > name_len)
360 {
361 shared_prefix_len = name_len;
362 }
363
364 ans_node = &node;
365 }
366
367 return ErrorCode::OK;
368 };
369
370 dir->Foreach(foreach_fun_show);
371
372 ShowHeader();
373 write_stream_ << ConstRawData(&input_line_[0], input_line_.Size());
374
375 for (size_t i = 0; i < shared_prefix_len - prefix_len; i++)
376 {
377 DisplayChar(ans_node->GetName()[i + prefix_len]);
378 }
379 }
380 }