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, &note, 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 = &param[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