1 // SoftEther VPN Source Code - Stable Edition Repository
2 // Cedar Communication Module
3 //
4 // SoftEther VPN Server, Client and Bridge are free software under the Apache License, Version 2.0.
5 //
6 // Copyright (c) Daiyuu Nobori.
7 // Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan.
8 // Copyright (c) SoftEther Corporation.
9 // Copyright (c) all contributors on SoftEther VPN project in GitHub.
10 //
11 // All Rights Reserved.
12 //
13 // http://www.softether.org/
14 //
15 // This stable branch is officially managed by Daiyuu Nobori, the owner of SoftEther VPN Project.
16 // Pull requests should be sent to the Developer Edition Master Repository on https://github.com/SoftEtherVPN/SoftEtherVPN
17 //
18 // License: The Apache License, Version 2.0
19 // https://www.apache.org/licenses/LICENSE-2.0
20 //
21 // DISCLAIMER
22 // ==========
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 // SOFTWARE.
31 //
32 // THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN, UNDER
33 // JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY, MERGE, PUBLISH,
34 // DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS SOFTWARE, THAT ANY
35 // JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS SOFTWARE OR ITS CONTENTS,
36 // AGAINST US (SOFTETHER PROJECT, SOFTETHER CORPORATION, DAIYUU NOBORI OR OTHER
37 // SUPPLIERS), OR ANY JURIDICAL DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND
38 // OF USING, COPYING, MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING,
39 // AND/OR SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
40 // CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO EXCLUSIVE
41 // JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO, JAPAN. YOU MUST WAIVE
42 // ALL DEFENSES OF LACK OF PERSONAL JURISDICTION AND FORUM NON CONVENIENS.
43 // PROCESS MAY BE SERVED ON EITHER PARTY IN THE MANNER AUTHORIZED BY APPLICABLE
44 // LAW OR COURT RULE.
45 //
46 // USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS YOU HAVE
47 // A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY CRIMINAL LAWS OR CIVIL
48 // RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS SOFTWARE IN OTHER COUNTRIES IS
49 // COMPLETELY AT YOUR OWN RISK. THE SOFTETHER VPN PROJECT HAS DEVELOPED AND
50 // DISTRIBUTED THIS SOFTWARE TO COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING
51 // CIVIL RIGHTS INCLUDING PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER
52 // COUNTRIES' LAWS OR CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES.
53 // WE HAVE NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
54 // INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+ COUNTRIES
55 // AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE WORLD, WITH
56 // DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY COUNTRIES' LAWS, REGULATIONS
57 // AND CIVIL RIGHTS TO MAKE THE SOFTWARE COMPLY WITH ALL COUNTRIES' LAWS BY THE
58 // PROJECT. EVEN IF YOU WILL BE SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A
59 // PUBLIC SERVANT IN YOUR COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE
60 // LIABLE TO RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
61 // RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT JUST A
62 // STATEMENT FOR WARNING AND DISCLAIMER.
63 //
64 // READ AND UNDERSTAND THE 'WARNING.TXT' FILE BEFORE USING THIS SOFTWARE.
65 // SOME SOFTWARE PROGRAMS FROM THIRD PARTIES ARE INCLUDED ON THIS SOFTWARE WITH
66 // LICENSE CONDITIONS WHICH ARE DESCRIBED ON THE 'THIRD_PARTY.TXT' FILE.
67 //
68 //
69 // SOURCE CODE CONTRIBUTION
70 // ------------------------
71 //
72 // Your contribution to SoftEther VPN Project is much appreciated.
73 // Please send patches to us through GitHub.
74 // Read the SoftEther VPN Patch Acceptance Policy in advance:
75 // http://www.softether.org/5-download/src/9.patch
76 //
77 //
78 // DEAR SECURITY EXPERTS
79 // ---------------------
80 //
81 // If you find a bug or a security vulnerability please kindly inform us
82 // about the problem immediately so that we can fix the security problem
83 // to protect a lot of users around the world as soon as possible.
84 //
85 // Our e-mail address for security reports is:
86 // softether-vpn-security [at] softether.org
87 //
88 // Please note that the above e-mail address is not a technical support
89 // inquiry address. If you need technical assistance, please visit
90 // http://www.softether.org/ and ask your question on the users forum.
91 //
92 // Thank you for your cooperation.
93 //
94 //
95 // NO MEMORY OR RESOURCE LEAKS
96 // ---------------------------
97 //
98 // The memory-leaks and resource-leaks verification under the stress
99 // test has been passed before release this source code.
100
101
102 // Console.c
103 // Console Service
104
105 #include "CedarPch.h"
106
107
108 // Display the help for the command
PrintCmdHelp(CONSOLE * c,char * cmd_name,TOKEN_LIST * param_list)109 void PrintCmdHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *param_list)
110 {
111 wchar_t tmp[MAX_SIZE];
112 wchar_t *buf;
113 UINT buf_size;
114 wchar_t *description, *args, *help;
115 UNI_TOKEN_LIST *t;
116 UINT width;
117 UINT i;
118 char *space;
119 // Validate arguments
120 if (c == NULL || cmd_name == NULL || param_list == NULL)
121 {
122 return;
123 }
124
125 width = GetConsoleWidth(c) - 2;
126
127 buf_size = sizeof(wchar_t) * (width + 32);
128 buf = Malloc(buf_size);
129
130 GetCommandHelpStr(cmd_name, &description, &args, &help);
131
132 space = MakeCharArray(' ', 2);
133
134 // Title
135 UniFormat(tmp, sizeof(tmp), _UU("CMD_HELP_TITLE"), cmd_name);
136 c->Write(c, tmp);
137 c->Write(c, L"");
138
139 // Purpose
140 c->Write(c, _UU("CMD_HELP_DESCRIPTION"));
141 t = SeparateStringByWidth(description, width - 2);
142 for (i = 0;i < t->NumTokens;i++)
143 {
144 UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
145 c->Write(c, buf);
146 }
147 UniFreeToken(t);
148 c->Write(c, L"");
149
150 // Description
151 c->Write(c, _UU("CMD_HELP_HELP"));
152 t = SeparateStringByWidth(help, width - 2);
153 for (i = 0;i < t->NumTokens;i++)
154 {
155 UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
156 c->Write(c, buf);
157 }
158 UniFreeToken(t);
159 c->Write(c, L"");
160
161 // Usage
162 c->Write(c, _UU("CMD_HELP_USAGE"));
163 t = SeparateStringByWidth(args, width - 2);
164 for (i = 0;i < t->NumTokens;i++)
165 {
166 UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
167 c->Write(c, buf);
168 }
169 UniFreeToken(t);
170
171 // Arguments
172 if (param_list->NumTokens >= 1)
173 {
174 c->Write(c, L"");
175 c->Write(c, _UU("CMD_HELP_ARGS"));
176 PrintCandidateHelp(c, cmd_name, param_list, 2);
177 }
178
179 Free(space);
180
181 Free(buf);
182 }
183
184 // Evaluate whether it is SafeStr
CmdEvalSafe(CONSOLE * c,wchar_t * str,void * param)185 bool CmdEvalSafe(CONSOLE *c, wchar_t *str, void *param)
186 {
187 wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_SAFE") : (wchar_t *)param;
188
189 if (IsSafeUniStr(str))
190 {
191 return true;
192 }
193
194 c->Write(c, p);
195
196 return false;
197 }
198
199 // String input prompt
CmdPrompt(CONSOLE * c,void * param)200 wchar_t *CmdPrompt(CONSOLE *c, void *param)
201 {
202 wchar_t *p = (param == NULL) ? _UU("CMD_PROMPT") : (wchar_t *)param;
203
204 return c->ReadLine(c, p, true);
205 }
206
207 // Evaluation whether the specified file exists
CmdEvalIsFile(CONSOLE * c,wchar_t * str,void * param)208 bool CmdEvalIsFile(CONSOLE *c, wchar_t *str, void *param)
209 {
210 wchar_t tmp[MAX_PATH];
211 // Validate arguments
212 if (c == NULL || str == NULL)
213 {
214 return false;
215 }
216
217 UniStrCpy(tmp, sizeof(tmp), str);
218
219 if (IsEmptyUniStr(tmp))
220 {
221 c->Write(c, _UU("CMD_FILE_NAME_EMPTY"));
222 return false;
223 }
224
225 if (IsFileExistsW(tmp) == false)
226 {
227 wchar_t tmp2[MAX_SIZE];
228
229 UniFormat(tmp2, sizeof(tmp2), _UU("CMD_FILE_NOT_FOUND"), tmp);
230 c->Write(c, tmp2);
231
232 return false;
233 }
234
235 return true;
236 }
237
238 // Evaluation of integer
CmdEvalInt1(CONSOLE * c,wchar_t * str,void * param)239 bool CmdEvalInt1(CONSOLE *c, wchar_t *str, void *param)
240 {
241 wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_INT") : (wchar_t *)param;
242
243 if (UniToInt(str) == 0)
244 {
245 c->Write(c, p);
246
247 return false;
248 }
249
250 return true;
251 }
252
253 // Evaluation of the parameters that a blank cannot be specified to
CmdEvalNotEmpty(CONSOLE * c,wchar_t * str,void * param)254 bool CmdEvalNotEmpty(CONSOLE *c, wchar_t *str, void *param)
255 {
256 wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_NOT_EMPTY") : (wchar_t *)param;
257
258 if (UniIsEmptyStr(str) == false)
259 {
260 return true;
261 }
262
263 c->Write(c, p);
264
265 return false;
266 }
267
268 // Evaluation function for minimum / maximum value of the parameter
CmdEvalMinMax(CONSOLE * c,wchar_t * str,void * param)269 bool CmdEvalMinMax(CONSOLE *c, wchar_t *str, void *param)
270 {
271 CMD_EVAL_MIN_MAX *e;
272 wchar_t *tag;
273 UINT v;
274 // Validate arguments
275 if (param == NULL)
276 {
277 return false;
278 }
279
280 e = (CMD_EVAL_MIN_MAX *)param;
281
282 if (e->StrName == NULL)
283 {
284 tag = _UU("CMD_EVAL_MIN_MAX");
285 }
286 else
287 {
288 tag = _UU(e->StrName);
289 }
290
291 v = UniToInt(str);
292
293 if (v >= e->MinValue && v <= e->MaxValue)
294 {
295 return true;
296 }
297 else
298 {
299 wchar_t tmp[MAX_SIZE];
300
301 UniFormat(tmp, sizeof(tmp), tag, e->MinValue, e->MaxValue);
302 c->Write(c, tmp);
303
304 return false;
305 }
306 }
307
308 // Get the help string of command
GetCommandHelpStr(char * command_name,wchar_t ** description,wchar_t ** args,wchar_t ** help)309 void GetCommandHelpStr(char *command_name, wchar_t **description, wchar_t **args, wchar_t **help)
310 {
311 char tmp1[128], tmp2[128], tmp3[128];
312
313 Format(tmp1, sizeof(tmp1), "CMD_%s", command_name);
314 Format(tmp2, sizeof(tmp2), "CMD_%s_ARGS", command_name);
315 Format(tmp3, sizeof(tmp3), "CMD_%s_HELP", command_name);
316
317 if (description != NULL)
318 {
319 *description = _UU(tmp1);
320 if (UniIsEmptyStr(*description))
321 {
322 *description = _UU("CMD_UNKNOWM");
323 }
324 }
325
326 if (args != NULL)
327 {
328 *args = _UU(tmp2);
329 if (UniIsEmptyStr(*args))
330 {
331 *args = _UU("CMD_UNKNOWN_ARGS");
332 }
333 }
334
335 if (help != NULL)
336 {
337 *help = _UU(tmp3);
338 if (UniIsEmptyStr(*help))
339 {
340 *help = _UU("CMD_UNKNOWN_HELP");
341 }
342 }
343 }
344
345 // Get the help string for parameter
GetCommandParamHelpStr(char * command_name,char * param_name,wchar_t ** description)346 void GetCommandParamHelpStr(char *command_name, char *param_name, wchar_t **description)
347 {
348 char tmp[160];
349 if (description == NULL)
350 {
351 return;
352 }
353
354 Format(tmp, sizeof(tmp), "CMD_%s_%s", command_name, param_name);
355
356 *description = _UU(tmp);
357
358 if (UniIsEmptyStr(*description))
359 {
360 *description = _UU("CMD_UNKNOWN_PARAM");
361 }
362 }
363
364 // String comparison function
CompareCandidateStr(void * p1,void * p2)365 int CompareCandidateStr(void *p1, void *p2)
366 {
367 char *s1, *s2;
368 if (p1 == NULL || p2 == NULL)
369 {
370 return 0;
371 }
372 s1 = *(char **)p1;
373 s2 = *(char **)p2;
374 if (s1 == NULL || s2 == NULL)
375 {
376 return 0;
377 }
378
379 if (s1[0] == '[' && s2[0] != '[')
380 {
381 return -1;
382 }
383 else if (s2[0] == '[' && s1[0] != '[')
384 {
385 return 1;
386 }
387
388 return StrCmp(s1, s2);
389 }
390
391 // Display the help of the candidate list
PrintCandidateHelp(CONSOLE * c,char * cmd_name,TOKEN_LIST * candidate_list,UINT left_space)392 void PrintCandidateHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *candidate_list, UINT left_space)
393 {
394 UINT console_width;
395 UINT max_keyword_width;
396 LIST *o;
397 UINT i;
398 wchar_t *tmpbuf;
399 UINT tmpbuf_size;
400 char *left_space_array;
401 char *max_space_array;
402 // Validate arguments
403 if (c == NULL || candidate_list == NULL)
404 {
405 return;
406 }
407
408 // Get the width of the screen
409 console_width = GetConsoleWidth(c) - 1;
410
411 tmpbuf_size = sizeof(wchar_t) * (console_width + 32);
412 tmpbuf = Malloc(tmpbuf_size);
413
414 left_space_array = MakeCharArray(' ', left_space);
415
416 // Sort and enlist the command name
417 // no need to sort the parameter name
418 o = NewListFast(cmd_name == NULL ? CompareCandidateStr : NULL);
419
420 max_keyword_width = 0;
421
422 for (i = 0;i < candidate_list->NumTokens;i++)
423 {
424 UINT keyword_width;
425
426 // Get the width of each keyword
427 Insert(o, candidate_list->Token[i]);
428
429 keyword_width = StrWidth(candidate_list->Token[i]);
430 if (cmd_name != NULL)
431 {
432 if (candidate_list->Token[i][0] != '[')
433 {
434 keyword_width += 1;
435 }
436 else
437 {
438 keyword_width -= 2;
439 }
440 }
441
442 max_keyword_width = MAX(max_keyword_width, keyword_width);
443 }
444
445 max_space_array = MakeCharArray(' ', max_keyword_width);
446
447 // Display the candidate
448 for (i = 0;i < LIST_NUM(o);i++)
449 {
450 char tmp[128];
451 char *name = LIST_DATA(o, i);
452 UNI_TOKEN_LIST *t;
453 wchar_t *help;
454 UINT j;
455 UINT keyword_start_width = left_space;
456 UINT descript_start_width = left_space + max_keyword_width + 1;
457 UINT descript_width;
458 char *space;
459
460 if (console_width >= (descript_start_width + 5))
461 {
462 descript_width = console_width - descript_start_width - 3;
463 }
464 else
465 {
466 descript_width = 2;
467 }
468
469 // Generate the name
470 if (cmd_name != NULL && name[0] != '[')
471 {
472 // Prepend a "/" in the case of a parameter
473 Format(tmp, sizeof(tmp), "/%s", name);
474 }
475 else
476 {
477 // Use the characters as it is in the case of a command name
478 if (cmd_name == NULL)
479 {
480 StrCpy(tmp, sizeof(tmp), name);
481 }
482 else
483 {
484 StrCpy(tmp, sizeof(tmp), name + 1);
485 if (StrLen(tmp) >= 1)
486 {
487 tmp[StrLen(tmp) - 1] = 0;
488 }
489 }
490 }
491
492 // Get the help string
493 if (cmd_name == NULL)
494 {
495 GetCommandHelpStr(name, &help, NULL, NULL);
496 }
497 else
498 {
499 GetCommandParamHelpStr(cmd_name, name, &help);
500 }
501
502 space = MakeCharArray(' ', max_keyword_width - StrWidth(name) - (cmd_name == NULL ? 0 : (name[0] != '[' ? 1 : -2)));
503
504 t = SeparateStringByWidth(help, descript_width);
505
506 for (j = 0;j < t->NumTokens;j++)
507 {
508 if (j == 0)
509 {
510 UniFormat(tmpbuf, tmpbuf_size, L"%S%S%S - %s",
511 left_space_array, tmp, space, t->Token[j]);
512 }
513 else
514 {
515 UniFormat(tmpbuf, tmpbuf_size, L"%S%S %s",
516 left_space_array, max_space_array, t->Token[j]);
517 }
518
519 c->Write(c, tmpbuf);
520 }
521
522 Free(space);
523
524 UniFreeToken(t);
525 }
526
527 ReleaseList(o);
528
529 Free(max_space_array);
530 Free(tmpbuf);
531 Free(left_space_array);
532 }
533
534 // Acquisition whether word characters
IsWordChar(wchar_t c)535 bool IsWordChar(wchar_t c)
536 {
537 if (c >= L'a' && c <= 'z')
538 {
539 return true;
540 }
541 if (c >= L'A' && c <= 'Z')
542 {
543 return true;
544 }
545 if (c >= L'0' && c <= '9')
546 {
547 return true;
548 }
549 if (c == L'_')
550 {
551 return true;
552 }
553 if (c == L'.')
554 {
555 return true;
556 }
557 if (c == L'\"')
558 {
559 return true;
560 }
561 if (c == L'\'')
562 {
563 return true;
564 }
565 if (c == L',')
566 {
567 return true;
568 }
569 if (c == L')')
570 {
571 return true;
572 }
573 if (c == L']')
574 {
575 return true;
576 }
577
578 return false;
579 }
580
581 // Get the character width of the word that comes next
GetNextWordWidth(wchar_t * str)582 UINT GetNextWordWidth(wchar_t *str)
583 {
584 UINT i;
585 UINT ret;
586 // Validate arguments
587 if (str == NULL)
588 {
589 return 0;
590 }
591
592 ret = 0;
593
594 for (i = 0;;i++)
595 {
596 wchar_t c = str[i];
597
598 if (c == 0)
599 {
600 break;
601 }
602
603 if (IsWordChar(c) == false)
604 {
605 break;
606 }
607
608 ret++;
609 }
610
611 return ret;
612 }
613
614 // Split a string into specified width
SeparateStringByWidth(wchar_t * str,UINT width)615 UNI_TOKEN_LIST *SeparateStringByWidth(wchar_t *str, UINT width)
616 {
617 UINT wp;
618 wchar_t *tmp;
619 UINT len, i;
620 LIST *o;
621 UNI_TOKEN_LIST *ret;
622 // Validate arguments
623 if (str == NULL)
624 {
625 return UniNullToken();
626 }
627 if (width == 0)
628 {
629 width = 1;
630 }
631
632 o = NewListFast(NULL);
633
634 len = UniStrLen(str);
635 tmp = ZeroMalloc(sizeof(wchar_t) * (len + 32));
636 wp = 0;
637
638 for (i = 0;i < (len + 1);i++)
639 {
640 wchar_t c = str[i];
641 UINT next_word_width;
642 UINT remain_width;
643
644 switch (c)
645 {
646 case 0:
647 case L'\r':
648 case L'\n':
649 if (c == L'\r')
650 {
651 if (str[i + 1] == L'\n')
652 {
653 i++;
654 }
655 }
656
657 tmp[wp++] = 0;
658 wp = 0;
659
660 Insert(o, UniCopyStr(tmp));
661 break;
662
663 default:
664 next_word_width = GetNextWordWidth(&str[i]);
665 remain_width = (width - UniStrWidth(tmp));
666
667 if ((remain_width >= 1) && (next_word_width > remain_width) && (next_word_width <= width))
668 {
669 tmp[wp++] = 0;
670 wp = 0;
671
672 Insert(o, UniCopyStr(tmp));
673 }
674
675 tmp[wp++] = c;
676 tmp[wp] = 0;
677 if (UniStrWidth(tmp) >= width)
678 {
679 tmp[wp++] = 0;
680 wp = 0;
681
682 Insert(o, UniCopyStr(tmp));
683 }
684 break;
685 }
686 }
687
688 if (LIST_NUM(o) == 0)
689 {
690 Insert(o, CopyUniStr(L""));
691 }
692
693 ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
694 ret->NumTokens = LIST_NUM(o);
695 ret->Token = ZeroMalloc(sizeof(wchar_t *) * ret->NumTokens);
696
697 for (i = 0;i < LIST_NUM(o);i++)
698 {
699 wchar_t *s = LIST_DATA(o, i);
700
701 UniTrimLeft(s);
702
703 ret->Token[i] = s;
704 }
705
706 ReleaseList(o);
707 Free(tmp);
708
709 return ret;
710 }
711
712 // Check whether the specified string means 'help'
IsHelpStr(char * str)713 bool IsHelpStr(char *str)
714 {
715 // Validate arguments
716 if (str == NULL)
717 {
718 return false;
719 }
720
721 if (StrCmpi(str, "help") == 0 || StrCmpi(str, "?") == 0 ||
722 StrCmpi(str, "man") == 0 || StrCmpi(str, "/man") == 0 ||
723 StrCmpi(str, "-man") == 0 || StrCmpi(str, "--man") == 0 ||
724 StrCmpi(str, "/help") == 0 || StrCmpi(str, "/?") == 0 ||
725 StrCmpi(str, "-help") == 0 || StrCmpi(str, "-?") == 0 ||
726 StrCmpi(str, "/h") == 0 || StrCmpi(str, "--help") == 0 ||
727 StrCmpi(str, "--?") == 0)
728 {
729 return true;
730 }
731
732 return false;
733 }
734
735 // Execution of the command
DispatchNextCmd(CONSOLE * c,char * prompt,CMD cmd[],UINT num_cmd,void * param)736 bool DispatchNextCmd(CONSOLE *c, char *prompt, CMD cmd[], UINT num_cmd, void *param)
737 {
738 return DispatchNextCmdEx(c, NULL, prompt, cmd, num_cmd, param);
739 }
DispatchNextCmdEx(CONSOLE * c,wchar_t * exec_command,char * prompt,CMD cmd[],UINT num_cmd,void * param)740 bool DispatchNextCmdEx(CONSOLE *c, wchar_t *exec_command, char *prompt, CMD cmd[], UINT num_cmd, void *param)
741 {
742 wchar_t *str;
743 wchar_t *tmp;
744 char *cmd_name;
745 bool b_exit = false;
746 wchar_t *cmd_param;
747 UINT ret = ERR_NO_ERROR;
748 TOKEN_LIST *t;
749 TOKEN_LIST *candidate;
750 bool no_end_crlf = false;
751 UINT i;
752 // Validate arguments
753 if (c == NULL || (num_cmd >= 1 && cmd == NULL))
754 {
755 return false;
756 }
757
758 if (exec_command == NULL)
759 {
760 // Show the prompt
761 RETRY:
762 tmp = CopyStrToUni(prompt);
763
764 if (c->ProgrammingMode)
765 {
766 wchar_t tmp2[MAX_PATH];
767
768 UniFormat(tmp2, sizeof(tmp2), L"[PROMPT:%u:%s]\r\n", c->RetCode, tmp);
769
770 Free(tmp);
771
772 tmp = CopyUniStr(tmp2);
773 }
774
775 str = c->ReadLine(c, tmp, false);
776 Free(tmp);
777
778 if (str != NULL && IsEmptyUniStr(str))
779 {
780 Free(str);
781 goto RETRY;
782 }
783 }
784 else
785 {
786 wchar_t tmp[MAX_SIZE];
787 // Use exec_command
788 if (UniStartWith(exec_command, L"vpncmd") == false)
789 {
790 if (prompt != NULL)
791 {
792 if (c->ConsoleType != CONSOLE_CSV)
793 {
794 UniFormat(tmp, sizeof(tmp), L"%S%s", prompt, exec_command);
795 c->Write(c, tmp);
796 }
797 }
798 }
799 str = CopyUniStr(exec_command);
800 }
801
802 if (str == NULL)
803 {
804 // User canceled
805 return false;
806 }
807
808 UniTrimCrlf(str);
809 UniTrim(str);
810
811 if (UniIsEmptyStr(str))
812 {
813 // Do Nothing
814 Free(str);
815 return true;
816 }
817
818 // Divide into command name and parameter
819 if (SeparateCommandAndParam(str, &cmd_name, &cmd_param) == false)
820 {
821 // Do Nothing
822 Free(str);
823 return true;
824 }
825
826 if (StrLen(cmd_name) >= 2 && cmd_name[0] == '?' && cmd_name[1] != '?')
827 {
828 char tmp[MAX_SIZE];
829 wchar_t *s;
830
831 StrCpy(tmp, sizeof(tmp), cmd_name + 1);
832 StrCpy(cmd_name, 0, tmp);
833
834 s = UniCopyStr(L"/?");
835 Free(cmd_param);
836
837 cmd_param = s;
838 }
839
840 if (StrLen(cmd_name) >= 2 && EndWith(cmd_name, "?") && cmd_name[StrLen(cmd_name) - 2] != '?')
841 {
842 wchar_t *s;
843
844 cmd_name[StrLen(cmd_name) - 1] = 0;
845
846 s = UniCopyStr(L"/?");
847 Free(cmd_param);
848
849 cmd_param = s;
850 }
851
852 // Get the candidate of command
853 t = ZeroMalloc(sizeof(TOKEN_LIST));
854 t->NumTokens = num_cmd;
855 t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
856 for (i = 0;i < t->NumTokens;i++)
857 {
858 t->Token[i] = CopyStr(cmd[i].Name);
859 }
860
861 if (IsHelpStr(cmd_name))
862 {
863 if (UniIsEmptyStr(cmd_param))
864 {
865 wchar_t tmp[MAX_SIZE];
866
867 // Display the list of commands that can be used
868 UniFormat(tmp, sizeof(tmp), _UU("CMD_HELP_1"), t->NumTokens);
869 c->Write(c, tmp);
870
871 PrintCandidateHelp(c, NULL, t, 1);
872
873 c->Write(c, L"");
874 c->Write(c, _UU("CMD_HELP_2"));
875 }
876 else
877 {
878 char *cmd_name;
879
880 // Display the help for the specified command
881 if (SeparateCommandAndParam(cmd_param, &cmd_name, NULL))
882 {
883 bool b = true;
884
885 if (IsHelpStr(cmd_name))
886 {
887 b = false;
888 }
889
890 if (b)
891 {
892 wchar_t str[MAX_SIZE];
893
894 UniFormat(str, sizeof(str), L"%S /help", cmd_name);
895 DispatchNextCmdEx(c, str, NULL, cmd, num_cmd, param);
896 no_end_crlf = true;
897 }
898
899 Free(cmd_name);
900 }
901 }
902 }
903 else if (StrCmpi(cmd_name, "exit") == 0 || StrCmpi(cmd_name, "quit") == 0)
904 {
905 // Exit
906 b_exit = true;
907 }
908 else
909 {
910 candidate = GetRealnameCandidate(cmd_name, t);
911
912 if (candidate == NULL || candidate->NumTokens == 0)
913 {
914 wchar_t tmp[MAX_SIZE];
915
916 // No candidate
917 UniFormat(tmp, sizeof(tmp), _UU("CON_UNKNOWN_CMD"), cmd_name);
918 c->Write(c, tmp);
919
920 c->RetCode = ERR_BAD_COMMAND_OR_PARAM;
921 }
922 else if (candidate->NumTokens >= 2)
923 {
924 wchar_t tmp[MAX_SIZE];
925
926 // There is more than one candidate
927 UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_CMD"), cmd_name);
928 c->Write(c, tmp);
929 c->Write(c, _UU("CON_AMBIGIOUS_CMD_1"));
930 PrintCandidateHelp(c, NULL, candidate, 1);
931 c->Write(c, _UU("CON_AMBIGIOUS_CMD_2"));
932
933 c->RetCode = ERR_BAD_COMMAND_OR_PARAM;
934 }
935 else
936 {
937 char *real_cmd_name;
938 UINT i;
939
940 // The candidate was shortlisted to one
941 real_cmd_name = candidate->Token[0];
942
943 for (i = 0;i < num_cmd;i++)
944 {
945 if (StrCmpi(cmd[i].Name, real_cmd_name) == 0)
946 {
947 if (cmd[i].Proc != NULL)
948 {
949 // Show the description of the command if it isn't in CSV mode
950 if(c->ConsoleType != CONSOLE_CSV)
951 {
952 wchar_t tmp[256];
953 wchar_t *note;
954
955 GetCommandHelpStr(cmd[i].Name, ¬e, NULL, NULL);
956 UniFormat(tmp, sizeof(tmp), _UU("CMD_EXEC_MSG_NAME"), cmd[i].Name, note);
957 c->Write(c, tmp);
958 }
959
960 // Call the procedure of the command
961 ret = cmd[i].Proc(c, cmd[i].Name, cmd_param, param);
962
963 if (ret == INFINITE)
964 {
965 // Exit command
966 b_exit = true;
967 }
968 else
969 {
970 c->RetCode = ret;
971 }
972 }
973 }
974 }
975 }
976
977 FreeToken(candidate);
978 }
979
980 FreeToken(t);
981 Free(str);
982 Free(cmd_name);
983 Free(cmd_param);
984
985 if (no_end_crlf == false)
986 {
987 //c->Write(c, L"");
988 }
989
990 if (b_exit)
991 {
992 return false;
993 }
994
995 return true;
996 }
997
998 // Get the width of the current console
GetConsoleWidth(CONSOLE * c)999 UINT GetConsoleWidth(CONSOLE *c)
1000 {
1001 UINT size;
1002
1003 size = c->GetWidth(c);
1004
1005 if (size == 0)
1006 {
1007 size = 80;
1008 }
1009
1010 if (size < 32)
1011 {
1012 size = 32;
1013 }
1014
1015 if (size > 65536)
1016 {
1017 size = 65535;
1018 }
1019
1020 return size;
1021 }
1022
1023 // Separate the command line into the command and the parameters
SeparateCommandAndParam(wchar_t * src,char ** cmd,wchar_t ** param)1024 bool SeparateCommandAndParam(wchar_t *src, char **cmd, wchar_t **param)
1025 {
1026 UINT i, len, wp;
1027 wchar_t *tmp;
1028 wchar_t *src_tmp;
1029 // Validate arguments
1030 if (src == NULL)
1031 {
1032 return false;
1033 }
1034 if (cmd != NULL)
1035 {
1036 *cmd = NULL;
1037 }
1038 if (param != NULL)
1039 {
1040 *param = NULL;
1041 }
1042
1043 src_tmp = UniCopyStr(src);
1044 UniTrimCrlf(src_tmp);
1045 UniTrim(src_tmp);
1046
1047 len = UniStrLen(src_tmp);
1048 tmp = Malloc(sizeof(wchar_t) * (len + 32));
1049 wp = 0;
1050
1051 for (i = 0;i < (len + 1);i++)
1052 {
1053 wchar_t c = src_tmp[i];
1054
1055 switch (c)
1056 {
1057 case 0:
1058 case L' ':
1059 case L'\t':
1060 tmp[wp] = 0;
1061 if (UniIsEmptyStr(tmp))
1062 {
1063 Free(tmp);
1064 Free(src_tmp);
1065 return false;
1066 }
1067 if (cmd != NULL)
1068 {
1069 *cmd = CopyUniToStr(tmp);
1070 Trim(*cmd);
1071 }
1072 goto ESCAPE;
1073
1074 default:
1075 tmp[wp++] = c;
1076 break;
1077 }
1078 }
1079
1080 ESCAPE:
1081 if (param != NULL)
1082 {
1083 *param = CopyUniStr(&src_tmp[wp]);
1084 UniTrim(*param);
1085 }
1086
1087 Free(tmp);
1088 Free(src_tmp);
1089
1090 return true;
1091 }
1092
1093 // Get the candidates list of of the real command name whose abbreviation matches to the command specified by the user
GetRealnameCandidate(char * input_name,TOKEN_LIST * real_name_list)1094 TOKEN_LIST *GetRealnameCandidate(char *input_name, TOKEN_LIST *real_name_list)
1095 {
1096 TOKEN_LIST *ret;
1097 LIST *o;
1098 UINT i;
1099 bool ok = false;
1100 // Validate arguments
1101 if (input_name == NULL || real_name_list == NULL)
1102 {
1103 return NullToken();
1104 }
1105
1106 o = NewListFast(NULL);
1107
1108 for (i = 0;i < real_name_list->NumTokens;i++)
1109 {
1110 char *name = real_name_list->Token[i];
1111
1112 // Search for an exact match with the highest priority first
1113 if (StrCmpi(name, input_name) == 0)
1114 {
1115 Insert(o, name);
1116 ok = true;
1117 break;
1118 }
1119 }
1120
1121 if (ok == false)
1122 {
1123 // If there is no command to exact match, check whether it matches to a short form command
1124 for (i = 0;i < real_name_list->NumTokens;i++)
1125 {
1126 char *name = real_name_list->Token[i];
1127
1128 if (IsOmissionName(input_name, name) || IsNameInRealName(input_name, name))
1129 {
1130 // A abbreviation is found
1131 Insert(o, name);
1132 ok = true;
1133 }
1134 }
1135 }
1136
1137 if (ok)
1138 {
1139 // One or more candidate is found
1140 ret = ListToTokenList(o);
1141 }
1142 else
1143 {
1144 ret = NullToken();
1145 }
1146
1147 ReleaseList(o);
1148
1149 return ret;
1150 }
1151
1152 // Check whether the command specified by the user is a abbreviation of existing commands
IsOmissionName(char * input_name,char * real_name)1153 bool IsOmissionName(char *input_name, char *real_name)
1154 {
1155 char oname[128];
1156 // Validate arguments
1157 if (input_name == NULL || real_name == NULL)
1158 {
1159 return false;
1160 }
1161
1162 if (IsAllUpperStr(real_name))
1163 {
1164 // Command of all capital letters do not take abbreviations
1165 return false;
1166 }
1167
1168 GetOmissionName(oname, sizeof(oname), real_name);
1169
1170 if (IsEmptyStr(oname))
1171 {
1172 return false;
1173 }
1174
1175 if (StartWith(oname, input_name))
1176 {
1177 // Example: The oname of AccountSecureCertSet is "ascs".
1178 // But if the user enters "asc", returns true
1179 return true;
1180 }
1181
1182 if (StartWith(input_name, oname))
1183 {
1184 // Example: When two commands AccountCreate and AccountConnect exist,
1185 // if the user enter "aconnect" , only AccountConnect is true
1186
1187 if (EndWith(real_name, &input_name[StrLen(oname)]))
1188 {
1189 return true;
1190 }
1191 }
1192
1193 return false;
1194 }
1195
1196 // Get the short name of the specified command
GetOmissionName(char * dst,UINT size,char * src)1197 void GetOmissionName(char *dst, UINT size, char *src)
1198 {
1199 UINT i, len;
1200 // Validate arguments
1201 if (dst == NULL || src == NULL)
1202 {
1203 return;
1204 }
1205
1206 StrCpy(dst, size, "");
1207 len = StrLen(src);
1208
1209 for (i = 0;i < len;i++)
1210 {
1211 char c = src[i];
1212
1213 if ((c >= '0' && c <= '9') ||
1214 (c >= 'A' && c <= 'Z'))
1215 {
1216 char tmp[2];
1217 tmp[0] = c;
1218 tmp[1] = 0;
1219
1220 StrCat(dst, size, tmp);
1221 }
1222 }
1223 }
1224
1225 // Check whether the command specified by the user matches the existing commands
IsNameInRealName(char * input_name,char * real_name)1226 bool IsNameInRealName(char *input_name, char *real_name)
1227 {
1228 // Validate arguments
1229 if (input_name == NULL || real_name == NULL)
1230 {
1231 return false;
1232 }
1233
1234 if (StartWith(real_name, input_name))
1235 {
1236 return true;
1237 }
1238
1239 return false;
1240 }
1241
1242 // Parse the command list
ParseCommandList(CONSOLE * c,char * cmd_name,wchar_t * command,PARAM param[],UINT num_param)1243 LIST *ParseCommandList(CONSOLE *c, char *cmd_name, wchar_t *command, PARAM param[], UINT num_param)
1244 {
1245 UINT i;
1246 LIST *o;
1247 bool ok = true;
1248 TOKEN_LIST *param_list;
1249 TOKEN_LIST *real_name_list;
1250 bool help_mode = false;
1251 wchar_t *tmp;
1252 // Validate arguments
1253 if (c == NULL || command == NULL || (num_param >= 1 && param == NULL) || cmd_name == NULL)
1254 {
1255 return NULL;
1256 }
1257
1258 // Initialization
1259 for (i = 0;i < num_param;i++)
1260 {
1261 if (IsEmptyStr(param[i].Name) == false)
1262 {
1263 if (param[i].Name[0] == '[')
1264 {
1265 param[i].Tmp = "";
1266 }
1267 else
1268 {
1269 param[i].Tmp = NULL;
1270 }
1271 }
1272 else
1273 {
1274 param[i].Tmp = "";
1275 }
1276 }
1277
1278 real_name_list = ZeroMalloc(sizeof(TOKEN_LIST));
1279 real_name_list->NumTokens = num_param;
1280 real_name_list->Token = ZeroMalloc(sizeof(char *) * real_name_list->NumTokens);
1281
1282 for (i = 0;i < real_name_list->NumTokens;i++)
1283 {
1284 real_name_list->Token[i] = CopyStr(param[i].Name);
1285 }
1286
1287 // Generate a list of parameter name specified by the user
1288 param_list = GetCommandNameList(command);
1289
1290 for (i = 0;i < param_list->NumTokens;i++)
1291 {
1292 char *s = param_list->Token[i];
1293
1294 if (StrCmpi(s, "help") == 0 || StrCmpi(s, "?") == 0)
1295 {
1296 help_mode = true;
1297 break;
1298 }
1299 }
1300
1301 tmp = ParseCommand(command, L"");
1302 if (tmp != NULL)
1303 {
1304 if (UniStrCmpi(tmp, L"?") == 0)
1305 {
1306 help_mode = true;
1307 }
1308 Free(tmp);
1309 }
1310
1311 if (help_mode)
1312 {
1313 // Show the help
1314 PrintCmdHelp(c, cmd_name, real_name_list);
1315 FreeToken(param_list);
1316 FreeToken(real_name_list);
1317 return NULL;
1318 }
1319
1320 for (i = 0;i < param_list->NumTokens;i++)
1321 {
1322 // Get the corresponding commands for all parameter names which is specified by the user
1323 TOKEN_LIST *candidate = GetRealnameCandidate(param_list->Token[i], real_name_list);
1324
1325 if (candidate != NULL && candidate->NumTokens >= 1)
1326 {
1327 if (candidate->NumTokens >= 2)
1328 {
1329 wchar_t tmp[MAX_SIZE];
1330
1331 // There is more than one candidate
1332 UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_PARAM"), param_list->Token[i]);
1333 c->Write(c, tmp);
1334 UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_PARAM_1"), cmd_name);
1335 c->Write(c, tmp);
1336
1337 PrintCandidateHelp(c, cmd_name, candidate, 1);
1338
1339 c->Write(c, _UU("CON_AMBIGIOUS_PARAM_2"));
1340
1341 ok = false;
1342 }
1343 else
1344 {
1345 UINT j;
1346 char *real_name = candidate->Token[0];
1347
1348 // There is only one candidate
1349 for (j = 0;j < num_param;j++)
1350 {
1351 if (StrCmpi(param[j].Name, real_name) == 0)
1352 {
1353 param[j].Tmp = param_list->Token[i];
1354 }
1355 }
1356 }
1357 }
1358 else
1359 {
1360 wchar_t tmp[MAX_SIZE];
1361
1362 // No candidate
1363 UniFormat(tmp, sizeof(tmp), _UU("CON_INVALID_PARAM"), param_list->Token[i], cmd_name, cmd_name);
1364 c->Write(c, tmp);
1365
1366 ok = false;
1367 }
1368
1369 FreeToken(candidate);
1370 }
1371
1372 if (ok == false)
1373 {
1374 FreeToken(param_list);
1375 FreeToken(real_name_list);
1376
1377 return NULL;
1378 }
1379
1380 // Creating a list
1381 o = NewParamValueList();
1382
1383 // Read all the parameters of the specified name in the parameter list
1384 for (i = 0;i < num_param;i++)
1385 {
1386 bool prompt_input_value = false;
1387 PARAM *p = ¶m[i];
1388
1389 if (p->Tmp != NULL || p->PromptProc != NULL)
1390 {
1391 wchar_t *name = CopyStrToUni(p->Name);
1392 wchar_t *tmp;
1393 wchar_t *str;
1394
1395 if (p->Tmp != NULL)
1396 {
1397 tmp = CopyStrToUni(p->Tmp);
1398 }
1399 else
1400 {
1401 tmp = CopyStrToUni(p->Name);
1402 }
1403
1404 str = ParseCommand(command, tmp);
1405 Free(tmp);
1406 if (str != NULL)
1407 {
1408 wchar_t *unistr;
1409 bool ret;
1410 EVAL_VALUE:
1411 // Reading succeeded
1412 unistr = str;
1413
1414 if (p->EvalProc != NULL)
1415 {
1416 // Evaluate the value if EvalProc is specified
1417 ret = p->EvalProc(c, unistr, p->EvalProcParam);
1418 }
1419 else
1420 {
1421 // Accept any value if EvalProc is not specified
1422 ret = true;
1423 }
1424
1425 if (ret == false)
1426 {
1427 // The specified value is invalid
1428 if (p->PromptProc == NULL)
1429 {
1430 // Cancel
1431 ok = false;
1432 Free(name);
1433 Free(str);
1434 break;
1435 }
1436 else if (c->ProgrammingMode)
1437 {
1438 // In the programming mode, return the error immediately.
1439 ok = false;
1440 Free(name);
1441 Free(str);
1442 break;
1443 }
1444 else
1445 {
1446 // Request to re-enter
1447 Free(str);
1448 str = NULL;
1449 goto SHOW_PROMPT;
1450 }
1451 }
1452 else
1453 {
1454 PARAM_VALUE *v;
1455 // Finished loading, add it to the list
1456 v = ZeroMalloc(sizeof(PARAM_VALUE));
1457 v->Name = CopyStr(p->Name);
1458 v->StrValue = CopyUniToStr(str);
1459 v->UniStrValue = CopyUniStr(str);
1460 v->IntValue = ToInt(v->StrValue);
1461 Insert(o, v);
1462 }
1463 }
1464 else
1465 {
1466 // Failed to read. The parameter is not specified
1467 if (p->PromptProc != NULL)
1468 {
1469 wchar_t *tmp;
1470 SHOW_PROMPT:
1471 // Prompt because it is a mandatory parameter
1472 tmp = NULL;
1473 if (c->ProgrammingMode == false)
1474 {
1475 tmp = p->PromptProc(c, p->PromptProcParam);
1476 }
1477 if (tmp == NULL)
1478 {
1479 // User canceled
1480 ok = false;
1481 Free(str);
1482 Free(name);
1483 break;
1484 }
1485 else
1486 {
1487 // Entered by the user
1488 c->Write(c, L"");
1489 str = tmp;
1490 prompt_input_value = true;
1491 goto EVAL_VALUE;
1492 }
1493 }
1494 }
1495
1496 Free(str);
1497 Free(name);
1498 }
1499 }
1500
1501 FreeToken(param_list);
1502 FreeToken(real_name_list);
1503
1504 if (ok)
1505 {
1506 return o;
1507 }
1508 else
1509 {
1510 FreeParamValueList(o);
1511 return NULL;
1512 }
1513 }
1514
1515 // Acquisition of [Yes] or [No]
GetParamYes(LIST * o,char * name)1516 bool GetParamYes(LIST *o, char *name)
1517 {
1518 char *s;
1519 char tmp[64];
1520 // Validate arguments
1521 if (o == NULL)
1522 {
1523 return false;
1524 }
1525
1526 s = GetParamStr(o, name);
1527 if (s == NULL)
1528 {
1529 return false;
1530 }
1531
1532 StrCpy(tmp, sizeof(tmp), s);
1533 Trim(tmp);
1534
1535 if (StartWith(tmp, "y"))
1536 {
1537 return true;
1538 }
1539
1540 if (StartWith(tmp, "t"))
1541 {
1542 return true;
1543 }
1544
1545 if (ToInt(tmp) != 0)
1546 {
1547 return true;
1548 }
1549
1550 return false;
1551 }
1552
1553 // Acquisition of parameter value Int
GetParamInt(LIST * o,char * name)1554 UINT GetParamInt(LIST *o, char *name)
1555 {
1556 PARAM_VALUE *v;
1557 // Validate arguments
1558 if (o == NULL)
1559 {
1560 return 0;
1561 }
1562
1563 v = FindParamValue(o, name);
1564 if (v == NULL)
1565 {
1566 return 0;
1567 }
1568 else
1569 {
1570 return v->IntValue;
1571 }
1572 }
1573
1574 // Acquisition of parameter value Unicode string
GetParamUniStr(LIST * o,char * name)1575 wchar_t *GetParamUniStr(LIST *o, char *name)
1576 {
1577 PARAM_VALUE *v;
1578 // Validate arguments
1579 if (o == NULL)
1580 {
1581 return NULL;
1582 }
1583
1584 v = FindParamValue(o, name);
1585 if (v == NULL)
1586 {
1587 return NULL;
1588 }
1589 else
1590 {
1591 return v->UniStrValue;
1592 }
1593 }
1594
1595 // Acquisition of the parameter value string
GetParamStr(LIST * o,char * name)1596 char *GetParamStr(LIST *o, char *name)
1597 {
1598 PARAM_VALUE *v;
1599 // Validate arguments
1600 if (o == NULL)
1601 {
1602 return NULL;
1603 }
1604
1605 v = FindParamValue(o, name);
1606 if (v == NULL)
1607 {
1608 return NULL;
1609 }
1610 else
1611 {
1612 return v->StrValue;
1613 }
1614 }
1615
1616 // Acquisition of parameter value
FindParamValue(LIST * o,char * name)1617 PARAM_VALUE *FindParamValue(LIST *o, char *name)
1618 {
1619 PARAM_VALUE t, *ret;
1620 // Validate arguments
1621 if (o == NULL)
1622 {
1623 return NULL;
1624 }
1625 if (name == NULL)
1626 {
1627 name = "";
1628 }
1629
1630 Zero(&t, sizeof(t));
1631 t.Name = name;
1632
1633 ret = Search(o, &t);
1634
1635 return ret;
1636 }
1637
1638 // Release of the parameter value list
FreeParamValueList(LIST * o)1639 void FreeParamValueList(LIST *o)
1640 {
1641 UINT i;
1642 // Validate arguments
1643 if (o == NULL)
1644 {
1645 return;
1646 }
1647
1648 for (i = 0;i < LIST_NUM(o);i++)
1649 {
1650 PARAM_VALUE *v = LIST_DATA(o, i);
1651
1652 Free(v->StrValue);
1653 Free(v->UniStrValue);
1654 Free(v->Name);
1655 Free(v);
1656 }
1657
1658 ReleaseList(o);
1659 }
1660
1661 // Parameter value list sort function
CmpParamValue(void * p1,void * p2)1662 int CmpParamValue(void *p1, void *p2)
1663 {
1664 PARAM_VALUE *v1, *v2;
1665 if (p1 == NULL || p2 == NULL)
1666 {
1667 return 0;
1668 }
1669 v1 = *(PARAM_VALUE **)p1;
1670 v2 = *(PARAM_VALUE **)p2;
1671 if (v1 == NULL || v2 == NULL)
1672 {
1673 return 0;
1674 }
1675
1676 if (IsEmptyStr(v1->Name) && IsEmptyStr(v2->Name))
1677 {
1678 return 0;
1679 }
1680 return StrCmpi(v1->Name, v2->Name);
1681 }
1682
1683 // Generation of the parameter value list
NewParamValueList()1684 LIST *NewParamValueList()
1685 {
1686 return NewListFast(CmpParamValue);
1687 }
1688
1689 // Get the list of parameter names that were included in the entered command
GetCommandNameList(wchar_t * str)1690 TOKEN_LIST *GetCommandNameList(wchar_t *str)
1691 {
1692 TOKEN_LIST *t;
1693 // Validate arguments
1694 if (str == NULL)
1695 {
1696 return NullToken();
1697 }
1698
1699 Free(ParseCommandEx(str, L"dummy_str", &t));
1700
1701 return t;
1702 }
1703
1704 // Get the commands that start with the specified name
ParseCommand(wchar_t * str,wchar_t * name)1705 wchar_t *ParseCommand(wchar_t *str, wchar_t *name)
1706 {
1707 return ParseCommandEx(str, name, NULL);
1708 }
ParseCommandEx(wchar_t * str,wchar_t * name,TOKEN_LIST ** param_list)1709 wchar_t *ParseCommandEx(wchar_t *str, wchar_t *name, TOKEN_LIST **param_list)
1710 {
1711 UNI_TOKEN_LIST *t;
1712 UINT i;
1713 wchar_t *tmp;
1714 wchar_t *ret = NULL;
1715 LIST *o;
1716 // Validate arguments
1717 if (str == NULL)
1718 {
1719 return NULL;
1720 }
1721 if (name != NULL && UniIsEmptyStr(name))
1722 {
1723 name = NULL;
1724 }
1725
1726 o = NULL;
1727 if (param_list != NULL)
1728 {
1729 o = NewListFast(CompareStr);
1730 }
1731
1732 tmp = CopyUniStr(str);
1733 UniTrim(tmp);
1734
1735 i = UniSearchStrEx(tmp, L"/CMD ", 0, false);
1736
1737 if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
1738 {
1739 i = INFINITE;
1740 }
1741 if (i == INFINITE)
1742 {
1743 i = UniSearchStrEx(tmp, L"/CMD\t", 0, false);
1744 if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
1745 {
1746 i = INFINITE;
1747 }
1748 }
1749 if (i == INFINITE)
1750 {
1751 i = UniSearchStrEx(tmp, L"/CMD:", 0, false);
1752 if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
1753 {
1754 i = INFINITE;
1755 }
1756 }
1757 if (i == INFINITE)
1758 {
1759 i = UniSearchStrEx(tmp, L"/CMD=", 0, false);
1760 if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
1761 {
1762 i = INFINITE;
1763 }
1764 }
1765 if (i == INFINITE)
1766 {
1767 i = UniSearchStrEx(tmp, L"-CMD ", 0, false);
1768 if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
1769 {
1770 i = INFINITE;
1771 }
1772 }
1773 if (i == INFINITE)
1774 {
1775 i = UniSearchStrEx(tmp, L"-CMD\t", 0, false);
1776 if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
1777 {
1778 i = INFINITE;
1779 }
1780 }
1781 if (i == INFINITE)
1782 {
1783 i = UniSearchStrEx(tmp, L"-CMD:", 0, false);
1784 if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
1785 {
1786 i = INFINITE;
1787 }
1788 }
1789 if (i == INFINITE)
1790 {
1791 i = UniSearchStrEx(tmp, L"-CMD=", 0, false);
1792 if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
1793 {
1794 i = INFINITE;
1795 }
1796 }
1797
1798 if (i != INFINITE)
1799 {
1800 char *s = CopyStr("CMD");
1801 if (InsertStr(o, s) == false)
1802 {
1803 Free(s);
1804 }
1805 if (UniStrCmpi(name, L"CMD") == 0)
1806 {
1807 ret = CopyUniStr(&str[i + 5]);
1808 UniTrim(ret);
1809 }
1810 else
1811 {
1812 tmp[i] = 0;
1813 }
1814 }
1815
1816 if (ret == NULL)
1817 {
1818 t = UniParseCmdLine(tmp);
1819
1820 if (t != NULL)
1821 {
1822 for (i = 0;i < t->NumTokens;i++)
1823 {
1824 wchar_t *token = t->Token[i];
1825
1826 if ((token[0] == L'-' && token[1] != L'-') ||
1827 (UniStrCmpi(token, L"--help") == 0) ||
1828 (token[0] == L'/' && token[1] != L'/'))
1829 {
1830 UINT i;
1831
1832 // Named parameter
1833 // Examine whether there is a colon character
1834
1835 if (UniStrCmpi(token, L"--help") == 0)
1836 {
1837 token++;
1838 }
1839
1840 i = UniSearchStrEx(token, L":", 0, false);
1841 if (i == INFINITE)
1842 {
1843 i = UniSearchStrEx(token, L"=", 0, false);
1844 }
1845 if (i != INFINITE)
1846 {
1847 wchar_t *tmp;
1848 char *a;
1849
1850 // There is a colon character
1851 tmp = CopyUniStr(token);
1852 tmp[i] = 0;
1853
1854 a = CopyUniToStr(&tmp[1]);
1855 if (InsertStr(o, a) == false)
1856 {
1857 Free(a);
1858 }
1859
1860 if (UniStrCmpi(name, &tmp[1]) == 0)
1861 {
1862 if (ret == NULL)
1863 {
1864 // Content
1865 ret = UniCopyStr(&token[i + 1]);
1866 }
1867 }
1868
1869 Free(tmp);
1870 }
1871 else
1872 {
1873 // There is no colon character
1874 char *a;
1875
1876 a = CopyUniToStr(&token[1]);
1877 if (InsertStr(o, a) == false)
1878 {
1879 Free(a);
1880 }
1881
1882 if (UniStrCmpi(name, &token[1]) == 0)
1883 {
1884 if (ret == NULL)
1885 {
1886 // Empty character
1887 ret = UniCopyStr(L"");
1888 }
1889 }
1890 }
1891 }
1892 else
1893 {
1894 // Nameless argument
1895 if (name == NULL)
1896 {
1897 if (ret == NULL)
1898 {
1899 if (token[0] == L'-' && token[1] == L'-')
1900 {
1901 ret = UniCopyStr(&token[1]);
1902 }
1903 else if (token[0] == L'/' && token[1] == L'/')
1904 {
1905 ret = UniCopyStr(&token[1]);
1906 }
1907 else
1908 {
1909 ret = UniCopyStr(token);
1910 }
1911 }
1912 }
1913 }
1914 }
1915
1916 UniFreeToken(t);
1917 }
1918 }
1919
1920 Free(tmp);
1921
1922 if (o != NULL)
1923 {
1924 TOKEN_LIST *t = ZeroMalloc(sizeof(TOKEN_LIST));
1925 UINT i;
1926
1927 t->NumTokens = LIST_NUM(o);
1928 t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
1929
1930 for (i = 0;i < t->NumTokens;i++)
1931 {
1932 t->Token[i] = LIST_DATA(o, i);
1933 }
1934
1935 ReleaseList(o);
1936
1937 *param_list = t;
1938 }
1939
1940 if (UniStrCmpi(ret, L"none") == 0 || UniStrCmpi(ret, L"null") == 0)
1941 {
1942 // Null and none are reserved words
1943 ret[0] = 0;
1944 }
1945
1946 return ret;
1947 }
ParseCommandA(wchar_t * str,char * name)1948 char *ParseCommandA(wchar_t *str, char *name)
1949 {
1950 wchar_t *tmp1, *tmp2;
1951 char *ret;
1952 // Validate arguments
1953 if (str == NULL)
1954 {
1955 return NULL;
1956 }
1957
1958 if (name != NULL)
1959 {
1960 tmp1 = CopyStrToUni(name);
1961 }
1962 else
1963 {
1964 tmp1 = NULL;
1965 }
1966
1967 tmp2 = ParseCommand(str, tmp1);
1968
1969 if (tmp2 == NULL)
1970 {
1971 ret = NULL;
1972 }
1973 else
1974 {
1975 ret = CopyUniToStr(tmp2);
1976 Free(tmp2);
1977 }
1978
1979 Free(tmp1);
1980
1981 return ret;
1982 }
1983
1984 // Password prompt
PasswordPrompt(char * password,UINT size)1985 bool PasswordPrompt(char *password, UINT size)
1986 {
1987 UINT wp;
1988 bool escape = false;
1989 void *console;
1990 // Validate arguments
1991 if (password == NULL || size <= 1)
1992 {
1993 if (size >= 1)
1994 {
1995 password[0] = 0;
1996 }
1997 return false;
1998 }
1999
2000 wp = 0;
2001
2002 Zero(password, size);
2003
2004 console = SetConsoleRaw();
2005
2006 while (true)
2007 {
2008 int c;
2009
2010 #ifdef OS_WIN32
2011 c = getch();
2012 #else // OS_WIN32
2013 c = getc(stdin);
2014 #endif // OS_WIN32
2015
2016 if (c >= 0x20 && c <= 0x7E)
2017 {
2018 // Character
2019 if ((wp + 1) < size)
2020 {
2021 password[wp++] = (char)c;
2022 putc('*', stdout);
2023 }
2024 }
2025 else if (c == 0x03)
2026 {
2027 // Break
2028 exit(0);
2029 }
2030 else if (c == 0x04 || c == 0x1a || c == 0x0D || c==0x0A)
2031 {
2032 // Exit
2033 if (c == 0x04 || c == 0x1a)
2034 {
2035 escape = true;
2036 }
2037 break;
2038 }
2039 else if (c == 0xE0)
2040 {
2041 // Read one more character
2042 c = getch();
2043 if (c == 0x4B || c == 0x53)
2044 {
2045 // Backspace
2046 goto BACKSPACE;
2047 }
2048 }
2049 else if (c == 0x08)
2050 {
2051 BACKSPACE:
2052 // Backspace
2053 if (wp >= 1)
2054 {
2055 password[--wp] = 0;
2056 putc(0x08, stdout);
2057 putc(' ', stdout);
2058 putc(0x08, stdout);
2059 }
2060 }
2061 }
2062 Print("\n");
2063
2064 RestoreConsole(console);
2065
2066 return (escape ? false : true);
2067 }
2068
2069 // Show the prompt
Prompt(wchar_t * prompt_str)2070 wchar_t *Prompt(wchar_t *prompt_str)
2071 {
2072 wchar_t *ret = NULL;
2073 wchar_t *tmp = NULL;
2074 // Validate arguments
2075 if (prompt_str == NULL)
2076 {
2077 prompt_str = L"";
2078 }
2079
2080 #ifdef OS_WIN32
2081 UniPrint(L"%s", prompt_str);
2082 tmp = Malloc(MAX_PROMPT_STRSIZE);
2083 if (fgetws(tmp, MAX_PROMPT_STRSIZE - 1, stdin) != NULL)
2084 {
2085 bool escape = false;
2086 UINT i, len;
2087
2088 len = UniStrLen(tmp);
2089 for (i = 0;i < len;i++)
2090 {
2091 if (tmp[i] == 0x04 || tmp[i] == 0x1A)
2092 {
2093 escape = true;
2094 break;
2095 }
2096 }
2097
2098 if (escape == false)
2099 {
2100 UniTrimCrlf(tmp);
2101
2102 ret = UniCopyStr(tmp);
2103 }
2104 }
2105 Free(tmp);
2106 #else // OS_WIN32
2107 {
2108 char *prompt = CopyUniToStr(prompt_str);
2109 char *s = readline(prompt);
2110 Free(prompt);
2111
2112 if (s != NULL)
2113 {
2114 TrimCrlf(s);
2115 Trim(s);
2116
2117 if (IsEmptyStr(s) == false)
2118 {
2119 add_history(s);
2120 }
2121
2122 ret = CopyStrToUni(s);
2123
2124 free(s);
2125 }
2126 }
2127 #endif // OS_WIN32
2128
2129 if (ret == NULL)
2130 {
2131 Print("\n");
2132 }
2133
2134 return ret;
2135 }
PromptA(wchar_t * prompt_str)2136 char *PromptA(wchar_t *prompt_str)
2137 {
2138 wchar_t *str = Prompt(prompt_str);
2139
2140 if (str == NULL)
2141 {
2142 return NULL;
2143 }
2144 else
2145 {
2146 char *ret = CopyUniToStr(str);
2147
2148 Free(str);
2149 return ret;
2150 }
2151 }
2152
2153 // Set the console to raw mode
SetConsoleRaw()2154 void *SetConsoleRaw()
2155 {
2156 #ifdef OS_UNIX
2157 struct termios t, *ret;
2158
2159 Zero(&t, sizeof(t));
2160 if (tcgetattr(0, &t) != 0)
2161 {
2162 // Failed
2163 return NULL;
2164 }
2165
2166 // Copy the current settings
2167 ret = Clone(&t, sizeof(t));
2168
2169 // Change the settings
2170 t.c_lflag &= (~ICANON);
2171 t.c_lflag &= (~ECHO);
2172 t.c_cc[VTIME] = 0;
2173 t.c_cc[VMIN] = 1;
2174 tcsetattr(0, TCSANOW, &t);
2175
2176 return ret;
2177 #else // OS_UNIX
2178 return Malloc(0);
2179 #endif // OS_UNIX
2180 }
2181
2182 // Restore the mode of the console
RestoreConsole(void * p)2183 void RestoreConsole(void *p)
2184 {
2185 #ifdef OS_UNIX
2186 struct termios *t;
2187 // Validate arguments
2188 if (p == NULL)
2189 {
2190 return;
2191 }
2192
2193 t = (struct termios *)p;
2194
2195 // Restore the settings
2196 tcsetattr(0, TCSANOW, t);
2197
2198 Free(t);
2199 #else // OS_UNIX
2200 if (p != NULL)
2201 {
2202 Free(p);
2203 }
2204 #endif // OS_UNIX
2205 }
2206
2207 ////////////////////////////
2208 // Local console function
2209
2210 // Creating a new local console
NewLocalConsole(wchar_t * infile,wchar_t * outfile)2211 CONSOLE *NewLocalConsole(wchar_t *infile, wchar_t *outfile)
2212 {
2213 IO *in_io = NULL, *out_io = NULL;
2214 CONSOLE *c = ZeroMalloc(sizeof(CONSOLE));
2215 LOCAL_CONSOLE_PARAM *p;
2216 UINT old_size = 0;
2217
2218 #ifdef OS_WIN32
2219 if (MsGetConsoleWidth() == 80)
2220 {
2221 //old_size = MsSetConsoleWidth(WIN32_DEFAULT_CONSOLE_WIDTH);
2222 }
2223 #endif // OS_WIN32
2224
2225 c->ConsoleType = CONSOLE_LOCAL;
2226 c->Free = ConsoleLocalFree;
2227 c->ReadLine = ConsoleLocalReadLine;
2228 c->ReadPassword = ConsoleLocalReadPassword;
2229 c->Write = ConsoleLocalWrite;
2230 c->GetWidth = ConsoleLocalGetWidth;
2231 c->OutputLock = NewLock();
2232
2233 if (UniIsEmptyStr(infile) == false)
2234 {
2235 // Input file is specified
2236 in_io = FileOpenW(infile, false);
2237 if (in_io == NULL)
2238 {
2239 wchar_t tmp[MAX_SIZE];
2240
2241 UniFormat(tmp, sizeof(tmp), _UU("CON_INFILE_ERROR"), infile);
2242 c->Write(c, tmp);
2243 Free(c);
2244 return NULL;
2245 }
2246 else
2247 {
2248 wchar_t tmp[MAX_SIZE];
2249
2250 UniFormat(tmp, sizeof(tmp), _UU("CON_INFILE_START"), infile);
2251 c->Write(c, tmp);
2252 }
2253 }
2254
2255 if (UniIsEmptyStr(outfile) == false)
2256 {
2257 // Output file is specified
2258 out_io = FileCreateW(outfile);
2259 if (out_io == NULL)
2260 {
2261 wchar_t tmp[MAX_SIZE];
2262
2263 UniFormat(tmp, sizeof(tmp), _UU("CON_OUTFILE_ERROR"), outfile);
2264 c->Write(c, tmp);
2265 Free(c);
2266
2267 if (in_io != NULL)
2268 {
2269 FileClose(in_io);
2270 }
2271 return NULL;
2272 }
2273 else
2274 {
2275 wchar_t tmp[MAX_SIZE];
2276
2277 UniFormat(tmp, sizeof(tmp), _UU("CON_OUTFILE_START"), outfile);
2278 c->Write(c, tmp);
2279 }
2280 }
2281
2282 p = ZeroMalloc(sizeof(LOCAL_CONSOLE_PARAM));
2283 c->Param = p;
2284
2285 p->InFile = in_io;
2286 p->OutFile = out_io;
2287 p->Win32_OldConsoleWidth = old_size;
2288
2289 if (in_io != NULL)
2290 {
2291 UINT size;
2292 void *buf;
2293
2294 size = FileSize(in_io);
2295 buf = ZeroMalloc(size + 1);
2296 FileRead(in_io, buf, size);
2297
2298 p->InBuf = NewBuf();
2299 WriteBuf(p->InBuf, buf, size);
2300 Free(buf);
2301
2302 p->InBuf->Current = 0;
2303 }
2304
2305 return c;
2306 }
2307
2308 // Release Console
ConsoleLocalFree(CONSOLE * c)2309 void ConsoleLocalFree(CONSOLE *c)
2310 {
2311 LOCAL_CONSOLE_PARAM *p;
2312 // Validate arguments
2313 if (c == NULL)
2314 {
2315 return;
2316 }
2317
2318 p = (LOCAL_CONSOLE_PARAM *)c->Param;
2319
2320 #ifdef OS_WIN32
2321 if (p->Win32_OldConsoleWidth != 0)
2322 {
2323 MsSetConsoleWidth(p->Win32_OldConsoleWidth);
2324 }
2325 #endif // OS_WIN32
2326
2327 if (p != NULL)
2328 {
2329 if (p->InFile != NULL)
2330 {
2331 FileClose(p->InFile);
2332 FreeBuf(p->InBuf);
2333 }
2334
2335 if (p->OutFile != NULL)
2336 {
2337 FileClose(p->OutFile);
2338 }
2339
2340 Free(p);
2341 }
2342
2343 DeleteLock(c->OutputLock);
2344
2345 // Memory release
2346 Free(c);
2347 }
2348
2349 // Get the width of the screen
ConsoleLocalGetWidth(CONSOLE * c)2350 UINT ConsoleLocalGetWidth(CONSOLE *c)
2351 {
2352 UINT ret = 0;
2353 // Validate arguments
2354 if (c == NULL)
2355 {
2356 return 0;
2357 }
2358
2359 #ifdef OS_WIN32
2360 ret = MsGetConsoleWidth();
2361 #else // OS_WIN32
2362 {
2363 struct winsize t;
2364
2365 Zero(&t, sizeof(t));
2366
2367 if (ioctl(1, TIOCGWINSZ, &t) == 0)
2368 {
2369 ret = t.ws_col;
2370 }
2371 }
2372 #endif // OS_WIN32
2373
2374 return ret;
2375 }
2376
2377 // Read one line from the console
ConsoleLocalReadLine(CONSOLE * c,wchar_t * prompt,bool nofile)2378 wchar_t *ConsoleLocalReadLine(CONSOLE *c, wchar_t *prompt, bool nofile)
2379 {
2380 wchar_t *ret;
2381 LOCAL_CONSOLE_PARAM *p;
2382 // Validate arguments
2383 if (c == NULL)
2384 {
2385 return NULL;
2386 }
2387 p = (LOCAL_CONSOLE_PARAM *)c->Param;
2388 if (prompt == NULL)
2389 {
2390 prompt = L">";
2391 }
2392
2393 ConsoleWriteOutFile(c, prompt, false);
2394
2395 if (nofile == false && p->InBuf != NULL)
2396 {
2397 // Read the next line from the file
2398 ret = ConsoleReadNextFromInFile(c);
2399
2400 if (ret != NULL)
2401 {
2402 // Display the pseudo prompt
2403 UniPrint(L"%s", prompt);
2404
2405 // Display on the screen
2406 UniPrint(L"%s\n", ret);
2407 }
2408 }
2409 else
2410 {
2411 // Read the following line from the console
2412 ret = Prompt(prompt);
2413 }
2414
2415 if (ret != NULL)
2416 {
2417 ConsoleWriteOutFile(c, ret, true);
2418 }
2419 else
2420 {
2421 ConsoleWriteOutFile(c, _UU("CON_USER_CANCEL"), true);
2422 }
2423
2424 return ret;
2425 }
2426
2427 // Read the password from the console
ConsoleLocalReadPassword(CONSOLE * c,wchar_t * prompt)2428 char *ConsoleLocalReadPassword(CONSOLE *c, wchar_t *prompt)
2429 {
2430 char tmp[64];
2431 // Validate arguments
2432 if (c == NULL)
2433 {
2434 return NULL;
2435 }
2436 if (prompt == NULL)
2437 {
2438 prompt = L"Password>";
2439 }
2440
2441 UniPrint(L"%s", prompt);
2442 ConsoleWriteOutFile(c, prompt, false);
2443
2444 if (PasswordPrompt(tmp, sizeof(tmp)))
2445 {
2446 ConsoleWriteOutFile(c, L"********", true);
2447 return CopyStr(tmp);
2448 }
2449 else
2450 {
2451 ConsoleWriteOutFile(c, _UU("CON_USER_CANCEL"), true);
2452 return NULL;
2453 }
2454 }
2455
2456 // Display a string to the console
ConsoleLocalWrite(CONSOLE * c,wchar_t * str)2457 bool ConsoleLocalWrite(CONSOLE *c, wchar_t *str)
2458 {
2459 // Validate arguments
2460 if (c == NULL || str == NULL)
2461 {
2462 return false;
2463 }
2464
2465 UniPrint(L"%s%s", str, (UniEndWith(str, L"\n") ? L"" : L"\n"));
2466
2467 ConsoleWriteOutFile(c, str, true);
2468
2469 return true;
2470 }
2471
2472 // Read the next line from the input file
ConsoleReadNextFromInFile(CONSOLE * c)2473 wchar_t *ConsoleReadNextFromInFile(CONSOLE *c)
2474 {
2475 LOCAL_CONSOLE_PARAM *p;
2476 char *str;
2477 // Validate arguments
2478 if (c == NULL)
2479 {
2480 return NULL;
2481 }
2482
2483 p = (LOCAL_CONSOLE_PARAM *)c->Param;
2484
2485 if (p->InBuf == NULL)
2486 {
2487 return NULL;
2488 }
2489
2490 while (true)
2491 {
2492 str = CfgReadNextLine(p->InBuf);
2493
2494 if (str == NULL)
2495 {
2496 return NULL;
2497 }
2498
2499 Trim(str);
2500
2501 if (IsEmptyStr(str) == false)
2502 {
2503 UINT size;
2504 wchar_t *ret;
2505
2506 size = CalcUtf8ToUni((BYTE *)str, StrLen(str));
2507 ret = ZeroMalloc(size + 32);
2508 Utf8ToUni(ret, size, (BYTE *)str, StrLen(str));
2509
2510 Free(str);
2511
2512 return ret;
2513 }
2514
2515 Free(str);
2516 }
2517 }
2518
2519 // Write when the output file is specified
ConsoleWriteOutFile(CONSOLE * c,wchar_t * str,bool add_last_crlf)2520 void ConsoleWriteOutFile(CONSOLE *c, wchar_t *str, bool add_last_crlf)
2521 {
2522 LOCAL_CONSOLE_PARAM *p;
2523 // Validate arguments
2524 if (c == NULL || str == NULL)
2525 {
2526 return;
2527 }
2528
2529 p = (LOCAL_CONSOLE_PARAM *)c->Param;
2530
2531 if (p != NULL && p->OutFile != NULL)
2532 {
2533 wchar_t *tmp = UniNormalizeCrlf(str);
2534 UINT utf8_size;
2535 UCHAR *utf8;
2536
2537 utf8_size = CalcUniToUtf8(tmp);
2538 utf8 = ZeroMalloc(utf8_size + 1);
2539 UniToUtf8(utf8, utf8_size + 1, tmp);
2540
2541 FileWrite(p->OutFile, utf8, utf8_size);
2542
2543 if (UniEndWith(str, L"\n") == false && add_last_crlf)
2544 {
2545 char *crlf = "\r\n";
2546 FileWrite(p->OutFile, "\r\n", StrLen(crlf));
2547 }
2548
2549 Free(utf8);
2550 Free(tmp);
2551 }
2552
2553 }
2554
2555