fixed missing tinyxml2 header path dependency for Win32
[mfgtools.git] / libuuu / cmd.cpp
blob485a5698301762c8c135924bfbf6662ee0dd075a
1 /*
2 * Copyright 2018 NXP.
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this
11 * list of conditions and the following disclaimer in the documentation and/or
12 * other materials provided with the distribution.
14 * Neither the name of the NXP Semiconductor nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
32 #include <regex>
33 #include <iterator>
34 #include <memory>
35 #include <string.h>
36 #include "cmd.h"
37 #include "libcomm.h"
38 #include "liberror.h"
39 #include "libuuu.h"
40 #include "config.h"
41 #include "trans.h"
42 #include "sdps.h"
43 #include <atomic>
44 #include "buffer.h"
45 #include "sdp.h"
46 #include "fastboot.h"
47 #include <sys/stat.h>
48 #include <thread>
50 #include <stdio.h>
51 #include <stdlib.h>
53 static CmdMap g_cmd_map;
54 static CmdObjCreateMap g_cmd_create_map;
55 static string g_cmd_list_file;
57 static map<thread::id, map<string, string>> g_environment;
59 int insert_env_variable(string key, string value)
61 g_environment[std::this_thread::get_id()][key] = value;
62 return 0;
65 string get_env_variable(string key)
67 return g_environment[std::this_thread::get_id()][key];
70 int clear_env()
72 return g_environment.erase(std::this_thread::get_id());
75 bool is_env_exist(string key)
77 return g_environment[std::this_thread::get_id()].find(key) != g_environment[std::this_thread::get_id()].end();
80 int get_string_in_square_brackets(const std::string &cmd, std::string &context);
81 int parser_cmd_list_file(shared_ptr<DataBuffer> pbuff, CmdMap *pCmdMap = nullptr);
82 std::string remove_square_brackets(const std::string &cmd);
84 template <class T>
85 void * create_object() { return new T; }
87 typedef void * (*FN)();
89 FN g_fn = create_object<int>;
91 CmdCtx::~CmdCtx()
95 CmdBase::~CmdBase()
99 int CmdBase::parser(char *p)
101 size_t pos = 0;
102 string param;
104 if (parser_protocol(p, pos))
105 return -1;
107 if (pos < m_cmd.size())
108 param = get_next_param(m_cmd, pos);
110 size_t index = 0;
112 while (pos < m_cmd.size())
114 param = get_next_param(m_cmd, pos);
116 struct Param *pp = nullptr;
118 if (m_NoKeyParam)
120 if (index > m_param.size())
122 set_last_err_string("More parameter then expected");
123 return -1;
125 pp = &(m_param[index]);
126 index++;
128 else
130 for (size_t i = 0; i < m_param.size(); i++)
132 string key = string(m_param[i].key);
133 if (compare_str(param, key, m_param[i].ignore_case))
135 pp = &(m_param[i]);
136 break;
141 if (pp == nullptr)
143 string err;
144 err = "unknown Option";
145 err += param;
146 set_last_err_string(err);
147 return -1;
150 if (pp->type == Param::Type::e_uint32)
152 if (!m_NoKeyParam)
153 param = get_next_param(m_cmd, pos);
154 *(uint32_t*)pp->pData = str_to_uint32(param);
157 if (pp->type == Param::Type::e_uint64)
159 if (!m_NoKeyParam)
160 param = get_next_param(m_cmd, pos);
161 *(uint64_t*)pp->pData = str_to_uint64(param);
164 if (pp->type == Param::Type::e_string_filename)
166 if (!m_NoKeyParam)
167 param = get_next_param(m_cmd, pos);
168 *(string*)pp->pData = param;
170 if (!check_file_exist(param))
171 return -1;
174 if (pp->type == Param::Type::e_string)
176 if (!m_NoKeyParam)
177 param = get_next_param(m_cmd, pos);
178 *(string*)pp->pData = remove_quota(param);
181 if (pp->type == Param::Type::e_bool)
183 *(bool*)pp->pData = true;
186 if (pp->type == Param::Type::e_null)
191 if (m_bCheckTotalParam)
193 if (index < m_param.size())
195 string str;
196 str += "Missed: ";
197 str += m_param[index].Error;
198 set_last_err_string(str);
199 return -1;
202 return 0;
205 int CmdBase::parser_protocol(char *p, size_t &pos)
207 if (p)
208 m_cmd = *p;
210 string prot = get_next_param(m_cmd, pos, ':');
211 string param;
212 if (get_string_in_square_brackets(prot, param))
213 return -1;
215 if (!param.empty())
217 size_t param_pos = 0;
218 string s = get_next_param(param, param_pos);
220 if (s == "-t")
222 string timeout;
223 timeout = get_next_param(param, param_pos);
224 m_timeout = str_to_uint32(timeout);
226 else
228 string err;
229 err = "Unknown option: ";
230 err += s;
231 err += " for protocol: ";
232 err += remove_square_brackets(prot);
233 set_last_err_string(err);
234 return -1;
237 return 0;
240 int CmdBase::dump()
242 uuu_notify nt;
243 nt.type = uuu_notify::NOTIFY_CMD_INFO;
245 string str = m_cmd;
246 str += "\n";
247 nt.str = (char*)str.c_str();
248 call_notify(nt);
250 return 0;
253 int CmdList::run_all(CmdCtx *p, bool dry)
255 CmdList::iterator it;
256 int ret;
258 uuu_notify nt;
259 nt.type = uuu_notify::NOTIFY_CMD_TOTAL;
260 nt.total = size();
261 call_notify(nt);
263 int i = 0;
265 for (it = begin(); it != end(); it++, i++)
267 uuu_notify nt;
269 nt.type = uuu_notify::NOTIFY_CMD_INDEX;
270 nt.index = i;
271 call_notify(nt);
273 nt.type = uuu_notify::NOTIFY_CMD_START;
274 nt.str = (char *)(*it)->get_cmd().c_str();
275 call_notify(nt);
277 if (dry)
278 ret = (*it)->dump();
279 else
280 ret = (*it)->run(p);
282 nt.type = uuu_notify::NOTIFY_CMD_END;
283 nt.status = ret;
284 call_notify(nt);
285 if (ret)
286 return ret;
288 if ((*it)->get_lastcmd())
289 break;
291 return ret;
294 int CmdMap::run_all(const std::string &protocol, CmdCtx *p, bool dry_run)
296 if (find(protocol) == end())
298 set_last_err_id(-1);
299 std::string err;
300 err.append("Unknown Protocol:");
301 err.append(protocol);
302 set_last_err_string(err);
303 return -1;
305 return at(protocol)->run_all(p, dry_run);
308 string get_next_param(const string &cmd, size_t &pos, char separate)
310 string str;
311 if (pos == string::npos)
312 return str;
313 if (pos >= cmd.size())
314 return str;
316 //trim left space
317 while (cmd[pos] == separate && pos < cmd.size())
318 pos++;
320 bool quote = false;
321 size_t end = string::npos;
323 for (size_t s = pos; s < cmd.size(); s++)
325 if (cmd[s] == '"')
326 quote = !quote;
328 if (!quote && cmd[s] == separate)
330 end = s;
331 break;
335 if (end == cmd.npos)
336 end = cmd.size();
338 str = cmd.substr(pos, end - pos);
339 pos = end + 1;
341 return str;
344 string remove_square_brackets(const string &cmd)
346 size_t sz=cmd.find('[');
347 return cmd.substr(0, sz);
350 int get_string_in_square_brackets(const string &cmd, string &context)
352 size_t start = cmd.find('[');
353 if (start == string::npos)
355 context.clear();
356 return 0;
359 size_t end = cmd.find(']', start);
360 if (end == string::npos)
362 set_last_err_string("missed ]");
363 return -1;
366 context = cmd.substr(start + 1, end - start - 1);
367 return 0;
370 template<typename T, uint64_t MAX_VAL>
371 T str_to_uint(const std::string &str, bool * conversion_succeeded)
373 if (conversion_succeeded) *conversion_succeeded = false;
375 int base = 10;
376 if (str.size() > 2)
378 if (str.substr(0, 2).compare("0x") == 0)
380 base = 16;
384 try {
385 const auto tmp_val = std::stoull(str, nullptr, base);
386 if (tmp_val <= MAX_VAL)
388 if (conversion_succeeded) *conversion_succeeded = true;
389 return static_cast<T>(tmp_val);
391 } catch (const std::invalid_argument &) {
392 } catch (const std::out_of_range &) {
395 set_last_err_string("Conversion of string to unsigned failed");
397 return MAX_VAL;
400 uint16_t str_to_uint16(const string &str, bool * conversion_succeeded)
402 return str_to_uint<uint16_t, UINT16_MAX>(str, conversion_succeeded);
405 uint32_t str_to_uint32(const string &str, bool * conversion_succeeded)
407 return str_to_uint<uint32_t, UINT32_MAX>(str, conversion_succeeded);
410 uint64_t str_to_uint64(const string &str, bool * conversion_succeeded)
412 return str_to_uint<uint64_t, UINT64_MAX>(str, conversion_succeeded);
415 template <class T> shared_ptr<CmdBase> new_cmd_obj(char *p)
417 return shared_ptr<CmdBase>(new T(p));
420 CmdObjCreateMap::CmdObjCreateMap()
422 (*this)["CFG:"] = new_cmd_obj<CfgCmd>;
424 (*this)["SDPS:BOOT"] = new_cmd_obj<SDPSCmd>;
426 (*this)["SDP:DCD"] = new_cmd_obj<SDPDcdCmd>;
427 (*this)["SDP:JUMP"] = new_cmd_obj<SDPJumpCmd>;
428 (*this)["SDP:RDMEM"] = new_cmd_obj<SDPReadMemCmd>;
429 (*this)["SDP:WRMEM"] = new_cmd_obj<SDPWriteMemCmd>;
430 (*this)["SDP:WRITE"] = new_cmd_obj<SDPWriteCmd>;
431 (*this)["SDP:STATUS"] = new_cmd_obj<SDPStatusCmd>;
432 (*this)["SDP:BOOT"] = new_cmd_obj<SDPBootCmd>;
433 (*this)["SDP:BLOG"] = new_cmd_obj<SDPBootlogCmd>;
435 (*this)["SDPU:JUMP"] = new_cmd_obj<SDPJumpCmd>;
436 (*this)["SDPU:WRITE"] = new_cmd_obj<SDPWriteCmd>;
437 (*this)["SDPU:BLOG"] = new_cmd_obj<SDPBootlogCmd>;
439 (*this)["SDPV:JUMP"] = new_cmd_obj<SDPJumpCmd>;
440 (*this)["SDPV:WRITE"] = new_cmd_obj<SDPWriteCmd>;
441 (*this)["SDPV:BLOG"] = new_cmd_obj<SDPBootlogCmd>;
443 (*this)["FB:GETVAR"] = new_cmd_obj<FBGetVar>;
444 (*this)["FASTBOOT:GETVAR"] = new_cmd_obj<FBGetVar>;
445 (*this)["FB:UCMD"] = new_cmd_obj<FBUCmd>;
446 (*this)["FASTBOOT:UCMD"] = new_cmd_obj<FBUCmd>;
447 (*this)["FB:CRC"] = new_cmd_obj<FBCRC>;
448 (*this)["FASTBOOT:CRC"] = new_cmd_obj<FBCRC>;
449 (*this)["FB:WRITE"] = new_cmd_obj<FBWrite>;
450 (*this)["FASTBOOT:WRITE"] = new_cmd_obj<FBWrite>;
451 (*this)["FB:ACMD"] = new_cmd_obj<FBACmd>;
452 (*this)["FASTBOOT:ACMD"] = new_cmd_obj<FBACmd>;
453 (*this)["FB:DOWNLOAD"] = new_cmd_obj<FBDownload>;
454 (*this)["FASTBOOT:DOWNLOAD"] = new_cmd_obj<FBDownload>;
455 (*this)["FB:UPLOAD"] = new_cmd_obj<FBUpload>;
456 (*this)["FASTBOOT:UPLOAD"] = new_cmd_obj<FBUpload>;
457 (*this)["FB:FLASH"] = new_cmd_obj<FBFlashCmd>;
458 (*this)["FASTBOOT:FLASH"] = new_cmd_obj<FBFlashCmd>;
459 (*this)["FB:ERASE"] = new_cmd_obj<FBEraseCmd>;
460 (*this)["FASTBOOT:ERASE"] = new_cmd_obj<FBEraseCmd>;
461 (*this)["FB:REBOOT"] = new_cmd_obj<FBRebootCmd>;
462 (*this)["FASTBOOT:REBOOT"] = new_cmd_obj<FBRebootCmd>;
463 (*this)["FB:OEM"] = new_cmd_obj<FBOemCmd>;
464 (*this)["FASTBOOT:OEM"] = new_cmd_obj<FBOemCmd>;
465 (*this)["FB:FLASHING"] = new_cmd_obj<FBFlashingCmd>;
466 (*this)["FASTBOOT:FLASHING"] = new_cmd_obj<FBFlashingCmd>;
467 (*this)["FB:SET_ACTIVE"] = new_cmd_obj<FBSetActiveCmd>;
468 (*this)["FASTBOOT:SET_ACTIVE"] = new_cmd_obj<FBSetActiveCmd>;
469 (*this)["FB:BOOT"] = new_cmd_obj<FBBootCmd>;
470 (*this)["FASTBOOT:BOOT"] = new_cmd_obj<FBBootCmd>;
471 (*this)["FB:CONTINUE"] = new_cmd_obj<FBContinueCmd>;
472 (*this)["FASTBOOT:CONTINUE"] = new_cmd_obj<FBContinueCmd>;
474 (*this)["FB:UPDATE-SUPER"] = new_cmd_obj<FBUpdateSuper>;
475 (*this)["FASTBOOT:UPDATE-SUPER"] = new_cmd_obj<FBUpdateSuper>;
476 (*this)["FB:CREATE-LOGICAL-PARTITION"] = new_cmd_obj<FBCreatePartition>;
477 (*this)["FASTBOOT:CREATE-LOGICAL-PARTITION"] = new_cmd_obj<FBCreatePartition>;
478 (*this)["FB:DELETE-LOGICAL-PARTITION"] = new_cmd_obj<FBDelPartition>;
479 (*this)["FASTBOOT:DELETE-LOGICAL-PARTITION"] = new_cmd_obj<FBDelPartition>;
480 (*this)["FB:RESIZE-LOGICAL-PARTITION"] = new_cmd_obj<FBResizePartition>;
481 (*this)["FASTBOOT:RESIZE-LOGICAL-PARTITION"] = new_cmd_obj<FBResizePartition>;
483 (*this)["FBK:UCMD"] = new_cmd_obj<FBUCmd>;
484 (*this)["FBK:ACMD"] = new_cmd_obj<FBACmd>;
485 (*this)["FBK:SYNC"] = new_cmd_obj<FBSyncCmd>;
486 (*this)["FBK:UCP"] = new_cmd_obj<FBCopy>;
488 (*this)["_ALL:DONE"] = new_cmd_obj<CmdDone>;
489 (*this)["_ALL:DELAY"] = new_cmd_obj<CmdDelay>;
490 (*this)["_ALL:SH"] = new_cmd_obj<CmdShell>;
491 (*this)["_ALL:SHELL"] = new_cmd_obj<CmdShell>;
492 (*this)["_ALL:<"] = new_cmd_obj<CmdShell>;
493 (*this)["_ALL:@"] = new_cmd_obj<CmdEnv>;
494 (*this)["_ALL:ERROR"] = new_cmd_obj<CmdError>;
495 (*this)["_ALL:IF"] = new_cmd_obj<CmdIf>;
499 shared_ptr<CmdBase> create_cmd_obj(string cmd)
501 string param;
502 size_t pos = 0;
503 param = get_next_param(cmd, pos, ':');
504 param = remove_square_brackets(param);
505 param += ":";
506 param = str_to_upper(param);
508 if (g_cmd_create_map.find(param) == g_cmd_create_map.end())
510 string s = param;
511 param = get_next_param(cmd, pos);
512 s += str_to_upper(param);
513 if (g_cmd_create_map.find(s) != g_cmd_create_map.end())
514 return g_cmd_create_map[s]((char*)cmd.c_str());
516 string commoncmd = "_ALL:";
517 commoncmd += str_to_upper(param);
518 if (g_cmd_create_map.find(commoncmd) != g_cmd_create_map.end())
519 return g_cmd_create_map[commoncmd]((char*)cmd.c_str());
521 else
523 return g_cmd_create_map[param]((char*)cmd.c_str());
526 string err;
527 err = "Unknown Command:";
528 err += cmd;
529 set_last_err_string(err);
530 return nullptr;
533 int uuu_run_cmd(const char * cmd, int dry)
535 return run_cmd(nullptr, cmd, dry);
538 int run_cmd(CmdCtx *pCtx, const char * cmd, int dry)
540 shared_ptr<CmdBase> p;
541 p = create_cmd_obj(cmd);
542 int ret;
544 if (p == nullptr)
545 return -1;
547 uuu_notify nt;
548 nt.type = uuu_notify::NOTIFY_CMD_TOTAL;
549 nt.total = 1;
550 call_notify(nt);
552 nt.type = uuu_notify::NOTIFY_CMD_START;
553 nt.str = (char *)p->get_cmd().c_str();
554 call_notify(nt);
556 if (typeid(*p) != typeid(CfgCmd))
558 size_t pos = 0;
559 string c = cmd;
561 string pro = get_next_param(c, pos, ':');
562 pro = remove_square_brackets(pro);
563 pro += ":";
565 if (p->parser())
566 ret = -1;
567 else
569 if (dry)
571 ret = p->dump();
572 }else
574 CmdUsbCtx ctx;
575 if (pCtx == nullptr)
577 ret = ctx.look_for_match_device(pro.c_str());
578 if (ret)
579 return ret;
581 pCtx = &ctx;
584 ret = p->run(pCtx);
588 else
590 return ret = dry? p->dump() : p->run(nullptr);
593 nt.type = uuu_notify::NOTIFY_CMD_END;
594 nt.status = ret;
595 call_notify(nt);
597 return ret;
600 int CmdDone::run(CmdCtx *)
602 uuu_notify nt;
603 nt.type = uuu_notify::NOTIFY_DONE;
604 call_notify(nt);
605 return 0;
608 int CmdDelay::parser(char * /*p*/)
610 size_t pos = 0;
611 string param = get_next_param(m_cmd, pos);
613 if (param.find(':') != string::npos)
614 param = get_next_param(m_cmd, pos);
616 if (str_to_upper(param) != "DELAY")
618 string err = "Unknown Command:";
619 err += param;
620 set_last_err_string(err);
621 return -1;
624 string ms = get_next_param(m_cmd, pos);
625 m_ms = str_to_uint32(ms);
626 return 0;
629 int CmdDelay::run(CmdCtx *)
631 std::this_thread::sleep_for(std::chrono::milliseconds(m_ms));
632 return 0;
635 int CmdError::parser(char *p)
637 if (p)
638 m_cmd = p;
640 size_t pos = 0;
641 string s;
643 if (parser_protocol(p, pos))
644 return -1;
646 s = get_next_param(m_cmd, pos);
648 m_error = m_cmd.substr(pos);
650 return 0;
653 int CmdError::run(CmdCtx * /*pCtx*/)
655 set_last_err_string(m_error);
656 return -1;
659 int CmdShell::parser(char * p)
661 if (p)
662 m_cmd = p;
664 size_t pos = 0;
665 string s;
667 if (parser_protocol(p, pos))
668 return -1;
670 m_protocol = m_cmd.substr(0, pos);
672 s = get_next_param(m_cmd, pos);
674 m_dyn = (s == "<");
676 if (pos != string::npos && pos < m_cmd.size())
677 m_shellcmd = m_cmd.substr(pos);
679 return 0;
682 int CmdShell::run(CmdCtx*pCtx)
684 #ifndef WIN32
685 #define _popen popen
686 #define _pclose pclose
687 #endif
688 FILE *pipe = _popen(m_shellcmd.c_str(), "r");
690 if (pipe == nullptr)
692 string err = "failure popen: ";
693 err += m_shellcmd.c_str();
694 set_last_err_string(err);
695 return -1;
698 string str;
699 str.resize(256);
700 while (fgets((char*)str.c_str(), str.size(), pipe))
702 if (m_dyn)
704 string cmd;
705 cmd = m_protocol;
706 str.resize(strlen(str.c_str()));
707 cmd += ' ';
708 cmd += str;
710 size_t pos = cmd.find_first_of("\r\n");
711 if (pos != string::npos)
712 cmd = cmd.substr(0, pos);
714 return run_cmd(pCtx, cmd.c_str(), 0);
716 uuu_notify nt;
717 nt.type = uuu_notify::NOTIFY_CMD_INFO;
718 nt.str = (char*)str.c_str();
719 call_notify(nt);
722 /* Close pipe and print return value of pPipe. */
723 if (feof(pipe))
725 int ret = _pclose(pipe);
726 string_ex str;
727 str.format("\nProcess returned %d\n", ret);;
728 if (ret)
730 set_last_err_string(str.c_str());
731 return ret;
734 else
736 set_last_err_string("Error: Failed to read the end of the pipe.\n");
737 return -1;
740 return 0;
743 int CmdEnv::parser(char *p)
745 if (p)
746 m_cmd = p;
748 size_t pos = 0;
750 if (parser_protocol(p, pos))
751 return -1;
752 if (pos == string::npos || pos >= m_cmd.size())
753 return -1;
755 m_unfold_cmd = m_cmd.substr(0, pos);
756 m_unfold_cmd.append(" ");
758 // read the '@'
759 get_next_param(m_cmd, pos);
761 auto cmd = m_cmd.substr(pos);
763 regex expr { "@[0-9a-zA-Z_]+@" };
764 smatch result;
765 auto last_pos = static_cast<const string&>(cmd).begin();
766 auto cmd_end = static_cast<const string&>(cmd).end();
767 while (regex_search(last_pos, cmd_end, result, expr)) {
768 for (auto &i : result) {
769 string key { i.first + 1, i.second - 1 };
770 auto value = [&key]() -> pair<bool, string> {
771 #ifndef WIN32
772 auto ptr = getenv(key.c_str());
773 if (ptr)
774 return {true, ptr};
775 return {true, "\0"};
776 #else
777 size_t len;
778 getenv_s(&len, nullptr, 0, key.c_str());
779 if (!len){
780 /* To have the same behavior as Linux when uuu is provided with variables in the way : -e var=
781 * We return null char as windows cannot store empty environment variables
783 return {true, "\0"};
785 string value(len-1, '\0');
786 getenv_s(&len, &value[0], len, key.c_str());
787 return {true, value};
788 #endif
789 }();
790 if (!value.first) {
791 set_last_err_string("variable '" + key + "' is not defined");
792 return -1;
794 auto begin = value.second.begin();
795 auto end = value.second.end();
796 auto pos = find_if(begin, end, [](char c){ return c == '\r' || c == '\n'; });
797 m_unfold_cmd.append(&*last_pos, distance(last_pos, i.first));
798 m_unfold_cmd.append(begin, pos);
799 last_pos = i.second;
803 if(last_pos != cmd.end())
804 m_unfold_cmd.append(&*last_pos);
806 return 0;
809 int CmdIf::parser(char *p)
811 if (p)
812 m_cmd = p;
814 string s;
816 size_t pos = 0;
818 if (parser_protocol(p, pos))
819 return -1;
821 m_protocol = m_cmd.substr(0, pos);
823 if (pos == string::npos || pos >= m_cmd.size())
824 return -1;
826 s = get_next_param(m_cmd, pos);
827 if (str_to_upper(s) != "IF")
829 string err = "Unknown command: ";
830 err += s;
831 set_last_err_string(s);
832 return -1;
834 size_t lc = pos;
835 get_next_param(m_cmd, pos);
837 size_t end = m_cmd.find("then", pos);
839 if (end == string::npos)
841 set_last_err_string("missed key word: then");
842 return -1;
845 m_condition = m_cmd.substr(lc, end - lc);
846 m_true_cmd = m_cmd.substr(end + 4);
847 return 0;
850 void CmdIf::build_map(CmdCtx*p)
852 string_ex s;
854 s.format("0x%04X", p->m_config_item->m_vid);
855 insert_env_variable("@VID@", s);
857 s.format("0x%04X", p->m_config_item->m_pid);
858 insert_env_variable("@PID@", s);
860 s.format("0x%04X", p->m_current_bcd);
861 insert_env_variable("@BCD@", s);
863 insert_env_variable("@CHIP@", p->m_config_item->m_chip);
867 int CmdIf::run(CmdCtx *p)
869 string l, r;
870 string cmp[] = { "==", "!=", "" };
871 int i = 0;
872 for (i = 0; !cmp[i].empty(); i++)
874 size_t pos = m_condition.find(cmp[i], 0);
875 if (pos != string::npos)
877 l = m_condition.substr(0, pos);
878 r = m_condition.substr(pos + cmp[i].size() + 1);
879 break;
882 l = str_to_upper(trim(l));
883 r = str_to_upper(trim(r));
885 build_map(p);
887 if (is_env_exist(l))
888 l = get_env_variable(l);
890 if (is_env_exist(r))
891 r = get_env_variable(r);
893 switch (i)
895 case 0: // ==
896 if (l != r)
897 return 0;
898 break;
899 case 1: // !=
900 if (l == r)
901 return 0;
902 break;
903 default:
904 set_last_err_string("unknown if condition");
905 return -1;
908 //Pass condition check;
909 string cmd = m_protocol;
910 cmd += ' ';
911 cmd += this->m_true_cmd;
912 return run_cmd(p, cmd.c_str(), 0);
915 int CmdEnv::run(CmdCtx *p)
917 return run_cmd(p, m_unfold_cmd.c_str(), 0);
920 int run_cmds(const char *protocol, CmdCtx *p)
922 CmdMap cmdmap, *pCmdMap;
924 if (!g_cmd_list_file.empty())
926 shared_ptr<FileBuffer> pin = get_file_buffer(g_cmd_list_file);
927 if (pin == nullptr)
928 return -1;
930 shared_ptr<DataBuffer> pbuff = pin->request_data(0, UINT64_MAX);
931 if (!pbuff)
932 return -1;
933 if(parser_cmd_list_file(pbuff, &cmdmap))
934 return -1;
935 pCmdMap = &cmdmap;
937 else
939 pCmdMap = &g_cmd_map;
942 if (pCmdMap->find(protocol) == pCmdMap->end())
944 return 0;
947 return (*pCmdMap)[protocol]->run_all(p);
950 static int insert_one_cmd(const char * cmd, CmdMap *pCmdMap)
952 string s = cmd;
953 size_t pos = 0;
955 string pro = get_next_param(s, pos, ':');
956 pro = remove_square_brackets(pro);
957 pro += ":";
959 pro = str_to_upper(pro);
961 shared_ptr<CmdBase> p = create_cmd_obj(s);
962 if (p == nullptr)
963 return -1;
965 if (p->parser())
966 return -1;
968 if (pCmdMap->find(pro) == pCmdMap->end())
970 shared_ptr<CmdList> list(new CmdList);
971 (*pCmdMap)[pro] = list;
974 (*pCmdMap)[pro]->push_back(p);
976 return 0;
980 static int added_default_boot_cmd(const char *filename)
982 string str;
984 str = "SDPS: boot -f ";
985 str += "\"";
986 str += filename;
987 str += "\"";
989 int ret = insert_one_cmd(str.c_str(), &g_cmd_map);
990 if (ret) return ret;
992 insert_one_cmd("SDPS: done", &g_cmd_map);
994 str = "SDP: boot -f ";
995 str += "\"";
996 str += filename;
997 str += "\"";
999 ret = insert_one_cmd(str.c_str(), &g_cmd_map);
1000 if (ret) return ret;
1002 insert_one_cmd("SDP: done", &g_cmd_map);
1004 str = "SDPU: write -f ";
1005 str += "\"";
1006 str += filename;
1007 str += "\"";
1008 str += " -offset 0x57c00";
1009 insert_one_cmd(str.c_str(), &g_cmd_map);
1010 insert_one_cmd("SDPU: jump", &g_cmd_map);
1011 insert_one_cmd("SDPU: done", &g_cmd_map);
1013 str = "SDPV: write -f ";
1014 str += "\"";
1015 str += filename;
1016 str += "\"";
1017 str += " -skipspl";
1018 insert_one_cmd(str.c_str(), &g_cmd_map);
1019 insert_one_cmd("SDPV: jump", &g_cmd_map);
1020 insert_one_cmd("SDPV: done", &g_cmd_map);
1022 return 0;
1025 int check_version(string str)
1027 int x = 0;
1028 int ver = 0;
1029 for (size_t i = 0; i < str.size(); i++)
1031 char c = str[i];
1032 if (c >= '0' && c <= '9')
1034 x *= 10;
1035 x += c - '0';
1037 if (c == '.' || i == str.size()-1 || c == '\n')
1039 ver <<= 12;
1040 ver += x;
1041 x = 0;
1045 int cur = uuu_get_version();
1047 if (ver > cur)
1049 string str;
1050 str = "This version of uuu is too old, please download the latest one";
1051 set_last_err_string(str);
1052 return -1;
1054 return 0;
1057 int uuu_run_cmd_script(const char * buff, int /*dry*/)
1059 shared_ptr<DataBuffer> p(new DataBuffer((void*)buff, strlen(buff)));
1061 return parser_cmd_list_file(p);
1064 int parser_cmd_list_file(shared_ptr<DataBuffer> pbuff, CmdMap *pCmdMap)
1066 char uuu_version[] = "uuu_version";
1067 string str;
1069 if (pCmdMap == nullptr)
1070 pCmdMap = &g_cmd_map;
1072 pCmdMap->clear();
1074 for (size_t i = 0; i < pbuff->size(); i++)
1076 uint8_t c = pbuff->at(i);
1077 if (c == '\r')
1078 continue;
1080 if(c != '\n')
1081 str.push_back(c);
1083 if (c == '\n' || c == 0 || i == pbuff->size() - 1)
1085 if (str.substr(0, strlen(uuu_version)) == uuu_version)
1087 if (check_version(str.substr(strlen(uuu_version), 10)))
1089 return -1;
1091 }else if (str.size() > 1)
1093 if (str[0] != '#')
1094 if (insert_one_cmd(str.c_str(), pCmdMap))
1095 return -1;
1097 str.clear();
1100 return 0;
1103 int uuu_auto_detect_file(const char *filename)
1105 string_ex fn;
1106 fn += remove_quota(filename);
1107 fn.replace('\\', '/');
1109 if (fn.empty())
1110 fn += "./";
1112 string oldfn =fn;
1114 fn += "/uuu.auto";
1115 shared_ptr<FileBuffer> buffer = get_file_buffer(fn);
1116 if (buffer == nullptr)
1118 fn.clear();
1119 fn += oldfn;
1120 size_t pos = str_to_upper(fn).find("ZIP");
1121 if(pos == string::npos || pos != fn.size() - 3)
1123 pos = str_to_upper(fn).find("SDCARD");
1124 if (pos == string::npos || pos != fn.size() - 6)
1125 buffer = get_file_buffer(fn); //we don't try open a zip file here
1128 if(buffer == nullptr)
1129 return -1;
1132 string str= "uuu_version";
1133 shared_ptr<DataBuffer> pData = buffer->request_data(0, UINT_MAX);
1134 if (!pData)
1135 return -1;
1136 void *p1 = pData->data();
1137 void *p2 = (void*)str.data();
1138 if (memcmp(p1, p2, str.size()) == 0)
1140 size_t pos = fn.rfind('/');
1141 if (pos != string::npos)
1142 set_current_dir(fn.substr(0, pos + 1));
1144 g_cmd_list_file = fn.substr(pos+1);
1146 return parser_cmd_list_file(pData);
1149 //flash.bin or uboot.bin
1150 return added_default_boot_cmd(fn.c_str());
1153 int notify_done(uuu_notify nt, void *p)
1155 if(nt.type == uuu_notify::NOTIFY_DONE)
1156 *(std::atomic<int> *) p = 1;
1157 if (nt.type == uuu_notify::NOTIFY_CMD_END && nt.status)
1158 *(std::atomic<int> *) p = 1;
1160 return 0;
1162 int uuu_wait_uuu_finish(int deamon, int dry)
1164 std::atomic<int> exit;
1165 exit = 0;
1167 if(dry) {
1168 for(auto it=g_cmd_map.begin(); it != g_cmd_map.end(); it++)
1170 for(auto cmd = it->second->begin(); cmd != it->second->end(); cmd++)
1172 (*cmd)->dump();
1175 return 0;
1178 if (!deamon)
1179 uuu_register_notify_callback(notify_done, &exit);
1181 if(polling_usb(exit))
1182 return -1;
1184 clean_up_filemap();
1185 return 0;