mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2026-01-26 13:20:12 +03:00
The password input handling on Linux to match the behavior on Windows. It allows deleting characters using the Backspace, Delete, and Left arrow keys, and correctly handles other input sequences are handling correctly.
2528 lines
44 KiB
C
2528 lines
44 KiB
C
// SoftEther VPN Source Code - Developer Edition Master Branch
|
|
// Cedar Communication Module
|
|
|
|
|
|
// Console.c
|
|
// Console Service
|
|
|
|
#include "Console.h"
|
|
|
|
#include "Cedar.h"
|
|
|
|
#include "Mayaqua/Cfg.h"
|
|
#include "Mayaqua/FileIO.h"
|
|
#include "Mayaqua/Internat.h"
|
|
#include "Mayaqua/Mayaqua.h"
|
|
#include "Mayaqua/Memory.h"
|
|
#include "Mayaqua/Microsoft.h"
|
|
#include "Mayaqua/Object.h"
|
|
#include "Mayaqua/Str.h"
|
|
#include "Mayaqua/Table.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifdef OS_WIN32
|
|
#include <conio.h>
|
|
#else
|
|
#include <termios.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <readline/readline.h>
|
|
#include <readline/history.h>
|
|
#endif
|
|
|
|
// Display the help for the command
|
|
void PrintCmdHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *param_list)
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
wchar_t *buf;
|
|
UINT buf_size;
|
|
wchar_t *description, *args, *help;
|
|
UNI_TOKEN_LIST *t;
|
|
UINT width;
|
|
UINT i;
|
|
char *space;
|
|
// Validate arguments
|
|
if (c == NULL || cmd_name == NULL || param_list == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
width = GetConsoleWidth(c) - 2;
|
|
|
|
buf_size = sizeof(wchar_t) * (width + 32);
|
|
buf = Malloc(buf_size);
|
|
|
|
GetCommandHelpStr(cmd_name, &description, &args, &help);
|
|
|
|
space = MakeCharArray(' ', 2);
|
|
|
|
// Title
|
|
UniFormat(tmp, sizeof(tmp), _UU("CMD_HELP_TITLE"), cmd_name);
|
|
c->Write(c, tmp);
|
|
c->Write(c, L"");
|
|
|
|
// Purpose
|
|
c->Write(c, _UU("CMD_HELP_DESCRIPTION"));
|
|
t = SeparateStringByWidth(description, width - 2);
|
|
for (i = 0;i < t->NumTokens;i++)
|
|
{
|
|
UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
|
|
c->Write(c, buf);
|
|
}
|
|
UniFreeToken(t);
|
|
c->Write(c, L"");
|
|
|
|
// Description
|
|
c->Write(c, _UU("CMD_HELP_HELP"));
|
|
t = SeparateStringByWidth(help, width - 2);
|
|
for (i = 0;i < t->NumTokens;i++)
|
|
{
|
|
UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
|
|
c->Write(c, buf);
|
|
}
|
|
UniFreeToken(t);
|
|
c->Write(c, L"");
|
|
|
|
// Usage
|
|
c->Write(c, _UU("CMD_HELP_USAGE"));
|
|
t = SeparateStringByWidth(args, width - 2);
|
|
for (i = 0;i < t->NumTokens;i++)
|
|
{
|
|
UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
|
|
c->Write(c, buf);
|
|
}
|
|
UniFreeToken(t);
|
|
|
|
// Arguments
|
|
if (param_list->NumTokens >= 1)
|
|
{
|
|
c->Write(c, L"");
|
|
c->Write(c, _UU("CMD_HELP_ARGS"));
|
|
PrintCandidateHelp(c, cmd_name, param_list, 2);
|
|
}
|
|
|
|
Free(space);
|
|
|
|
Free(buf);
|
|
}
|
|
|
|
// Evaluate whether it is SafeStr
|
|
bool CmdEvalSafe(CONSOLE *c, wchar_t *str, void *param)
|
|
{
|
|
wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_SAFE") : (wchar_t *)param;
|
|
|
|
if (IsSafeUniStr(str))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
c->Write(c, p);
|
|
|
|
return false;
|
|
}
|
|
|
|
// String input prompt
|
|
wchar_t *CmdPrompt(CONSOLE *c, void *param)
|
|
{
|
|
wchar_t *p = (param == NULL) ? _UU("CMD_PROMPT") : (wchar_t *)param;
|
|
|
|
return c->ReadLine(c, p, true);
|
|
}
|
|
|
|
// Evaluation whether the specified file exists
|
|
bool CmdEvalIsFile(CONSOLE *c, wchar_t *str, void *param)
|
|
{
|
|
wchar_t tmp[MAX_PATH];
|
|
// Validate arguments
|
|
if (c == NULL || str == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
UniStrCpy(tmp, sizeof(tmp), str);
|
|
|
|
if (IsEmptyUniStr(tmp))
|
|
{
|
|
c->Write(c, _UU("CMD_FILE_NAME_EMPTY"));
|
|
return false;
|
|
}
|
|
|
|
if (IsFileExistsW(tmp) == false)
|
|
{
|
|
wchar_t tmp2[MAX_SIZE];
|
|
|
|
UniFormat(tmp2, sizeof(tmp2), _UU("CMD_FILE_NOT_FOUND"), tmp);
|
|
c->Write(c, tmp2);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Evaluation of integer
|
|
bool CmdEvalInt1(CONSOLE *c, wchar_t *str, void *param)
|
|
{
|
|
wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_INT") : (wchar_t *)param;
|
|
|
|
if (UniToInt(str) == 0)
|
|
{
|
|
c->Write(c, p);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Evaluation of the parameters that a blank cannot be specified to
|
|
bool CmdEvalNotEmpty(CONSOLE *c, wchar_t *str, void *param)
|
|
{
|
|
wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_NOT_EMPTY") : (wchar_t *)param;
|
|
|
|
if (UniIsEmptyStr(str) == false)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
c->Write(c, p);
|
|
|
|
return false;
|
|
}
|
|
|
|
// Evaluation function for minimum / maximum value of the parameter
|
|
bool CmdEvalMinMax(CONSOLE *c, wchar_t *str, void *param)
|
|
{
|
|
CMD_EVAL_MIN_MAX *e;
|
|
wchar_t *tag;
|
|
UINT v;
|
|
// Validate arguments
|
|
if (param == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
e = (CMD_EVAL_MIN_MAX *)param;
|
|
|
|
if (e->StrName == NULL)
|
|
{
|
|
tag = _UU("CMD_EVAL_MIN_MAX");
|
|
}
|
|
else
|
|
{
|
|
tag = _UU(e->StrName);
|
|
}
|
|
|
|
v = UniToInt(str);
|
|
|
|
if (v >= e->MinValue && v <= e->MaxValue)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
|
|
UniFormat(tmp, sizeof(tmp), tag, e->MinValue, e->MaxValue);
|
|
c->Write(c, tmp);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Get the help string of command
|
|
void GetCommandHelpStr(char *command_name, wchar_t **description, wchar_t **args, wchar_t **help)
|
|
{
|
|
char tmp1[128], tmp2[128], tmp3[128];
|
|
|
|
Format(tmp1, sizeof(tmp1), "CMD_%s", command_name);
|
|
Format(tmp2, sizeof(tmp2), "CMD_%s_ARGS", command_name);
|
|
Format(tmp3, sizeof(tmp3), "CMD_%s_HELP", command_name);
|
|
|
|
if (description != NULL)
|
|
{
|
|
*description = _UU(tmp1);
|
|
if (UniIsEmptyStr(*description))
|
|
{
|
|
*description = _UU("CMD_UNKNOWM");
|
|
}
|
|
}
|
|
|
|
if (args != NULL)
|
|
{
|
|
*args = _UU(tmp2);
|
|
if (UniIsEmptyStr(*args))
|
|
{
|
|
*args = _UU("CMD_UNKNOWN_ARGS");
|
|
}
|
|
}
|
|
|
|
if (help != NULL)
|
|
{
|
|
*help = _UU(tmp3);
|
|
if (UniIsEmptyStr(*help))
|
|
{
|
|
*help = _UU("CMD_UNKNOWN_HELP");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the help string for parameter
|
|
void GetCommandParamHelpStr(char *command_name, char *param_name, wchar_t **description)
|
|
{
|
|
char tmp[160];
|
|
if (description == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Format(tmp, sizeof(tmp), "CMD_%s_%s", command_name, param_name);
|
|
|
|
*description = _UU(tmp);
|
|
|
|
if (UniIsEmptyStr(*description))
|
|
{
|
|
*description = _UU("CMD_UNKNOWN_PARAM");
|
|
}
|
|
}
|
|
|
|
// String comparison function
|
|
int CompareCandidateStr(void *p1, void *p2)
|
|
{
|
|
char *s1, *s2;
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
s1 = *(char **)p1;
|
|
s2 = *(char **)p2;
|
|
if (s1 == NULL || s2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (s1[0] == '[' && s2[0] != '[')
|
|
{
|
|
return -1;
|
|
}
|
|
else if (s2[0] == '[' && s1[0] != '[')
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return StrCmp(s1, s2);
|
|
}
|
|
|
|
// Display the help of the candidate list
|
|
void PrintCandidateHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *candidate_list, UINT left_space)
|
|
{
|
|
UINT console_width;
|
|
UINT max_keyword_width;
|
|
LIST *o;
|
|
UINT i;
|
|
wchar_t *tmpbuf;
|
|
UINT tmpbuf_size;
|
|
char *left_space_array;
|
|
char *max_space_array;
|
|
// Validate arguments
|
|
if (c == NULL || candidate_list == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get the width of the screen
|
|
console_width = GetConsoleWidth(c) - 1;
|
|
|
|
tmpbuf_size = sizeof(wchar_t) * (console_width + 32);
|
|
tmpbuf = Malloc(tmpbuf_size);
|
|
|
|
left_space_array = MakeCharArray(' ', left_space);
|
|
|
|
// Sort and enlist the command name
|
|
// no need to sort the parameter name
|
|
o = NewListFast(cmd_name == NULL ? CompareCandidateStr : NULL);
|
|
|
|
max_keyword_width = 0;
|
|
|
|
for (i = 0;i < candidate_list->NumTokens;i++)
|
|
{
|
|
UINT keyword_width;
|
|
|
|
// Get the width of each keyword
|
|
Insert(o, candidate_list->Token[i]);
|
|
|
|
keyword_width = StrWidth(candidate_list->Token[i]);
|
|
if (cmd_name != NULL)
|
|
{
|
|
if (candidate_list->Token[i][0] != '[')
|
|
{
|
|
keyword_width += 1;
|
|
}
|
|
else
|
|
{
|
|
keyword_width -= 2;
|
|
}
|
|
}
|
|
|
|
max_keyword_width = MAX(max_keyword_width, keyword_width);
|
|
}
|
|
|
|
max_space_array = MakeCharArray(' ', max_keyword_width);
|
|
|
|
// Display the candidate
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
char tmp[128];
|
|
char *name = LIST_DATA(o, i);
|
|
UNI_TOKEN_LIST *t;
|
|
wchar_t *help;
|
|
UINT j;
|
|
UINT keyword_start_width = left_space;
|
|
UINT descript_start_width = left_space + max_keyword_width + 1;
|
|
UINT descript_width;
|
|
char *space;
|
|
|
|
if (console_width >= (descript_start_width + 5))
|
|
{
|
|
descript_width = console_width - descript_start_width - 3;
|
|
}
|
|
else
|
|
{
|
|
descript_width = 2;
|
|
}
|
|
|
|
// Generate the name
|
|
if (cmd_name != NULL && name[0] != '[')
|
|
{
|
|
// Prepend a "/" in the case of a parameter
|
|
Format(tmp, sizeof(tmp), "/%s", name);
|
|
}
|
|
else
|
|
{
|
|
// Use the characters as it is in the case of a command name
|
|
if (cmd_name == NULL)
|
|
{
|
|
StrCpy(tmp, sizeof(tmp), name);
|
|
}
|
|
else
|
|
{
|
|
StrCpy(tmp, sizeof(tmp), name + 1);
|
|
if (StrLen(tmp) >= 1)
|
|
{
|
|
tmp[StrLen(tmp) - 1] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the help string
|
|
if (cmd_name == NULL)
|
|
{
|
|
GetCommandHelpStr(name, &help, NULL, NULL);
|
|
}
|
|
else
|
|
{
|
|
GetCommandParamHelpStr(cmd_name, name, &help);
|
|
}
|
|
|
|
space = MakeCharArray(' ', max_keyword_width - StrWidth(name) - (cmd_name == NULL ? 0 : (name[0] != '[' ? 1 : -2)));
|
|
|
|
t = SeparateStringByWidth(help, descript_width);
|
|
|
|
for (j = 0;j < t->NumTokens;j++)
|
|
{
|
|
if (j == 0)
|
|
{
|
|
UniFormat(tmpbuf, tmpbuf_size, L"%S%S%S - %s",
|
|
left_space_array, tmp, space, t->Token[j]);
|
|
}
|
|
else
|
|
{
|
|
UniFormat(tmpbuf, tmpbuf_size, L"%S%S %s",
|
|
left_space_array, max_space_array, t->Token[j]);
|
|
}
|
|
|
|
c->Write(c, tmpbuf);
|
|
}
|
|
|
|
Free(space);
|
|
|
|
UniFreeToken(t);
|
|
}
|
|
|
|
ReleaseList(o);
|
|
|
|
Free(max_space_array);
|
|
Free(tmpbuf);
|
|
Free(left_space_array);
|
|
}
|
|
|
|
// Acquisition whether word characters
|
|
bool IsWordChar(wchar_t c)
|
|
{
|
|
if (c >= L'a' && c <= 'z')
|
|
{
|
|
return true;
|
|
}
|
|
if (c >= L'A' && c <= 'Z')
|
|
{
|
|
return true;
|
|
}
|
|
if (c >= L'0' && c <= '9')
|
|
{
|
|
return true;
|
|
}
|
|
if (c == L'_')
|
|
{
|
|
return true;
|
|
}
|
|
if (c == L'.')
|
|
{
|
|
return true;
|
|
}
|
|
if (c == L'\"')
|
|
{
|
|
return true;
|
|
}
|
|
if (c == L'\'')
|
|
{
|
|
return true;
|
|
}
|
|
if (c == L',')
|
|
{
|
|
return true;
|
|
}
|
|
if (c == L')')
|
|
{
|
|
return true;
|
|
}
|
|
if (c == L']')
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Get the character width of the word that comes next
|
|
UINT GetNextWordWidth(wchar_t *str)
|
|
{
|
|
UINT i;
|
|
UINT ret;
|
|
// Validate arguments
|
|
if (str == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
for (i = 0;;i++)
|
|
{
|
|
wchar_t c = str[i];
|
|
|
|
if (c == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (IsWordChar(c) == false)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ret++;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Split a string into specified width
|
|
UNI_TOKEN_LIST *SeparateStringByWidth(wchar_t *str, UINT width)
|
|
{
|
|
UINT wp;
|
|
wchar_t *tmp;
|
|
UINT len, i;
|
|
LIST *o;
|
|
UNI_TOKEN_LIST *ret;
|
|
// Validate arguments
|
|
if (str == NULL)
|
|
{
|
|
return UniNullToken();
|
|
}
|
|
if (width == 0)
|
|
{
|
|
width = 1;
|
|
}
|
|
|
|
o = NewListFast(NULL);
|
|
|
|
len = UniStrLen(str);
|
|
tmp = ZeroMalloc(sizeof(wchar_t) * (len + 32));
|
|
wp = 0;
|
|
|
|
for (i = 0;i < (len + 1);i++)
|
|
{
|
|
wchar_t c = str[i];
|
|
UINT next_word_width;
|
|
UINT remain_width;
|
|
|
|
switch (c)
|
|
{
|
|
case 0:
|
|
case L'\r':
|
|
case L'\n':
|
|
if (c == L'\r')
|
|
{
|
|
if (str[i + 1] == L'\n')
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
|
|
tmp[wp++] = 0;
|
|
wp = 0;
|
|
|
|
Insert(o, UniCopyStr(tmp));
|
|
break;
|
|
|
|
default:
|
|
next_word_width = GetNextWordWidth(&str[i]);
|
|
remain_width = (width - UniStrWidth(tmp));
|
|
|
|
if ((remain_width >= 1) && (next_word_width > remain_width) && (next_word_width <= width))
|
|
{
|
|
tmp[wp++] = 0;
|
|
wp = 0;
|
|
|
|
Insert(o, UniCopyStr(tmp));
|
|
}
|
|
|
|
tmp[wp++] = c;
|
|
tmp[wp] = 0;
|
|
if (UniStrWidth(tmp) >= width)
|
|
{
|
|
tmp[wp++] = 0;
|
|
wp = 0;
|
|
|
|
Insert(o, UniCopyStr(tmp));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (LIST_NUM(o) == 0)
|
|
{
|
|
Insert(o, CopyUniStr(L""));
|
|
}
|
|
|
|
ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
|
|
ret->NumTokens = LIST_NUM(o);
|
|
ret->Token = ZeroMalloc(sizeof(wchar_t *) * ret->NumTokens);
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
wchar_t *s = LIST_DATA(o, i);
|
|
|
|
UniTrimLeft(s);
|
|
|
|
ret->Token[i] = s;
|
|
}
|
|
|
|
ReleaseList(o);
|
|
Free(tmp);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Check whether the specified string means 'help'
|
|
bool IsHelpStr(char *str)
|
|
{
|
|
// Validate arguments
|
|
if (str == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (StrCmpi(str, "help") == 0 || StrCmpi(str, "?") == 0 ||
|
|
StrCmpi(str, "man") == 0 || StrCmpi(str, "/man") == 0 ||
|
|
StrCmpi(str, "-man") == 0 || StrCmpi(str, "--man") == 0 ||
|
|
StrCmpi(str, "/help") == 0 || StrCmpi(str, "/?") == 0 ||
|
|
StrCmpi(str, "-help") == 0 || StrCmpi(str, "-?") == 0 ||
|
|
StrCmpi(str, "/h") == 0 || StrCmpi(str, "--help") == 0 ||
|
|
StrCmpi(str, "--?") == 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Execution of the command
|
|
bool DispatchNextCmd(CONSOLE *c, char *prompt, CMD cmd[], UINT num_cmd, void *param)
|
|
{
|
|
return DispatchNextCmdEx(c, NULL, prompt, cmd, num_cmd, param);
|
|
}
|
|
bool DispatchNextCmdEx(CONSOLE *c, wchar_t *exec_command, char *prompt, CMD cmd[], UINT num_cmd, void *param)
|
|
{
|
|
wchar_t *str;
|
|
wchar_t *tmp;
|
|
char *cmd_name;
|
|
bool b_exit = false;
|
|
wchar_t *cmd_param;
|
|
UINT ret = ERR_NO_ERROR;
|
|
TOKEN_LIST *t;
|
|
TOKEN_LIST *candidate;
|
|
bool no_end_crlf = false;
|
|
UINT i;
|
|
// Validate arguments
|
|
if (c == NULL || (num_cmd >= 1 && cmd == NULL))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (exec_command == NULL)
|
|
{
|
|
// Show the prompt
|
|
RETRY:
|
|
tmp = CopyStrToUni(prompt);
|
|
|
|
if (c->ProgrammingMode)
|
|
{
|
|
wchar_t tmp2[MAX_PATH];
|
|
|
|
UniFormat(tmp2, sizeof(tmp2), L"[PROMPT:%u:%s]\r\n", c->RetCode, tmp);
|
|
|
|
Free(tmp);
|
|
|
|
tmp = CopyUniStr(tmp2);
|
|
}
|
|
|
|
str = c->ReadLine(c, tmp, false);
|
|
Free(tmp);
|
|
|
|
if (str != NULL && IsEmptyUniStr(str))
|
|
{
|
|
Free(str);
|
|
goto RETRY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
// Use exec_command
|
|
if (UniStartWith(exec_command, L"vpncmd") == false)
|
|
{
|
|
if (prompt != NULL)
|
|
{
|
|
if (c->ConsoleType != CONSOLE_CSV)
|
|
{
|
|
UniFormat(tmp, sizeof(tmp), L"%S%s", prompt, exec_command);
|
|
c->Write(c, tmp);
|
|
}
|
|
}
|
|
}
|
|
str = CopyUniStr(exec_command);
|
|
}
|
|
|
|
if (str == NULL)
|
|
{
|
|
// User canceled
|
|
return false;
|
|
}
|
|
|
|
UniTrimCrlf(str);
|
|
UniTrim(str);
|
|
|
|
if (UniIsEmptyStr(str))
|
|
{
|
|
// Do Nothing
|
|
Free(str);
|
|
return true;
|
|
}
|
|
|
|
// Divide into command name and parameter
|
|
if (SeparateCommandAndParam(str, &cmd_name, &cmd_param) == false)
|
|
{
|
|
// Do Nothing
|
|
Free(str);
|
|
return true;
|
|
}
|
|
|
|
if (StrLen(cmd_name) >= 2 && cmd_name[0] == '?' && cmd_name[1] != '?')
|
|
{
|
|
char tmp[MAX_SIZE];
|
|
wchar_t *s;
|
|
|
|
StrCpy(tmp, sizeof(tmp), cmd_name + 1);
|
|
StrCpy(cmd_name, 0, tmp);
|
|
|
|
s = UniCopyStr(L"/?");
|
|
Free(cmd_param);
|
|
|
|
cmd_param = s;
|
|
}
|
|
|
|
if (StrLen(cmd_name) >= 2 && EndWith(cmd_name, "?") && cmd_name[StrLen(cmd_name) - 2] != '?')
|
|
{
|
|
wchar_t *s;
|
|
|
|
cmd_name[StrLen(cmd_name) - 1] = 0;
|
|
|
|
s = UniCopyStr(L"/?");
|
|
Free(cmd_param);
|
|
|
|
cmd_param = s;
|
|
}
|
|
|
|
// Get the candidate of command
|
|
t = ZeroMalloc(sizeof(TOKEN_LIST));
|
|
t->NumTokens = num_cmd;
|
|
t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
|
|
for (i = 0;i < t->NumTokens;i++)
|
|
{
|
|
t->Token[i] = CopyStr(cmd[i].Name);
|
|
}
|
|
|
|
if (IsHelpStr(cmd_name))
|
|
{
|
|
if (UniIsEmptyStr(cmd_param))
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
|
|
// Display the list of commands that can be used
|
|
UniFormat(tmp, sizeof(tmp), _UU("CMD_HELP_1"), t->NumTokens);
|
|
c->Write(c, tmp);
|
|
|
|
PrintCandidateHelp(c, NULL, t, 1);
|
|
|
|
c->Write(c, L"");
|
|
c->Write(c, _UU("CMD_HELP_2"));
|
|
}
|
|
else
|
|
{
|
|
char *cmd_name;
|
|
|
|
// Display the help for the specified command
|
|
if (SeparateCommandAndParam(cmd_param, &cmd_name, NULL))
|
|
{
|
|
bool b = true;
|
|
|
|
if (IsHelpStr(cmd_name))
|
|
{
|
|
b = false;
|
|
}
|
|
|
|
if (b)
|
|
{
|
|
wchar_t str[MAX_SIZE];
|
|
|
|
UniFormat(str, sizeof(str), L"%S /help", cmd_name);
|
|
DispatchNextCmdEx(c, str, NULL, cmd, num_cmd, param);
|
|
no_end_crlf = true;
|
|
}
|
|
|
|
Free(cmd_name);
|
|
}
|
|
}
|
|
}
|
|
else if (StrCmpi(cmd_name, "exit") == 0 || StrCmpi(cmd_name, "quit") == 0)
|
|
{
|
|
// Exit
|
|
b_exit = true;
|
|
}
|
|
else
|
|
{
|
|
candidate = GetRealnameCandidate(cmd_name, t);
|
|
|
|
if (candidate == NULL || candidate->NumTokens == 0)
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
|
|
// No candidate
|
|
UniFormat(tmp, sizeof(tmp), _UU("CON_UNKNOWN_CMD"), cmd_name);
|
|
c->Write(c, tmp);
|
|
|
|
c->RetCode = ERR_BAD_COMMAND_OR_PARAM;
|
|
}
|
|
else if (candidate->NumTokens >= 2)
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
|
|
// There is more than one candidate
|
|
UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGUOUS_CMD"), cmd_name);
|
|
c->Write(c, tmp);
|
|
c->Write(c, _UU("CON_AMBIGUOUS_CMD_1"));
|
|
PrintCandidateHelp(c, NULL, candidate, 1);
|
|
c->Write(c, _UU("CON_AMBIGUOUS_CMD_2"));
|
|
|
|
c->RetCode = ERR_BAD_COMMAND_OR_PARAM;
|
|
}
|
|
else
|
|
{
|
|
char *real_cmd_name;
|
|
UINT i;
|
|
|
|
// The candidate was shortlisted to one
|
|
real_cmd_name = candidate->Token[0];
|
|
|
|
for (i = 0;i < num_cmd;i++)
|
|
{
|
|
if (StrCmpi(cmd[i].Name, real_cmd_name) == 0)
|
|
{
|
|
if (cmd[i].Proc != NULL)
|
|
{
|
|
// Show the description of the command if it isn't in CSV mode
|
|
if(c->ConsoleType != CONSOLE_CSV)
|
|
{
|
|
wchar_t tmp[256];
|
|
wchar_t *note;
|
|
|
|
GetCommandHelpStr(cmd[i].Name, ¬e, NULL, NULL);
|
|
UniFormat(tmp, sizeof(tmp), _UU("CMD_EXEC_MSG_NAME"), cmd[i].Name, note);
|
|
c->Write(c, tmp);
|
|
}
|
|
|
|
// Call the procedure of the command
|
|
ret = cmd[i].Proc(c, cmd[i].Name, cmd_param, param);
|
|
|
|
if (ret == INFINITE)
|
|
{
|
|
// Exit command
|
|
b_exit = true;
|
|
}
|
|
else
|
|
{
|
|
c->RetCode = ret;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FreeToken(candidate);
|
|
}
|
|
|
|
FreeToken(t);
|
|
Free(str);
|
|
Free(cmd_name);
|
|
Free(cmd_param);
|
|
|
|
if (no_end_crlf == false)
|
|
{
|
|
//c->Write(c, L"");
|
|
}
|
|
|
|
if (b_exit)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Get the width of the current console
|
|
UINT GetConsoleWidth(CONSOLE *c)
|
|
{
|
|
UINT size;
|
|
|
|
size = c->GetWidth(c);
|
|
|
|
if (size == 0)
|
|
{
|
|
size = 80;
|
|
}
|
|
|
|
if (size < 32)
|
|
{
|
|
size = 32;
|
|
}
|
|
|
|
if (size > 65536)
|
|
{
|
|
size = 65535;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
// Separate the command line into the command and the parameters
|
|
bool SeparateCommandAndParam(wchar_t *src, char **cmd, wchar_t **param)
|
|
{
|
|
UINT i, len, wp;
|
|
wchar_t *tmp;
|
|
wchar_t *src_tmp;
|
|
// Validate arguments
|
|
if (src == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
if (cmd != NULL)
|
|
{
|
|
*cmd = NULL;
|
|
}
|
|
if (param != NULL)
|
|
{
|
|
*param = NULL;
|
|
}
|
|
|
|
src_tmp = UniCopyStr(src);
|
|
UniTrimCrlf(src_tmp);
|
|
UniTrim(src_tmp);
|
|
|
|
len = UniStrLen(src_tmp);
|
|
tmp = Malloc(sizeof(wchar_t) * (len + 32));
|
|
wp = 0;
|
|
|
|
for (i = 0;i < (len + 1);i++)
|
|
{
|
|
wchar_t c = src_tmp[i];
|
|
|
|
switch (c)
|
|
{
|
|
case 0:
|
|
case L' ':
|
|
case L'\t':
|
|
tmp[wp] = 0;
|
|
if (UniIsEmptyStr(tmp))
|
|
{
|
|
Free(tmp);
|
|
Free(src_tmp);
|
|
return false;
|
|
}
|
|
if (cmd != NULL)
|
|
{
|
|
*cmd = CopyUniToStr(tmp);
|
|
Trim(*cmd);
|
|
}
|
|
goto ESCAPE;
|
|
|
|
default:
|
|
tmp[wp++] = c;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ESCAPE:
|
|
if (param != NULL)
|
|
{
|
|
*param = CopyUniStr(&src_tmp[wp]);
|
|
UniTrim(*param);
|
|
}
|
|
|
|
Free(tmp);
|
|
Free(src_tmp);
|
|
|
|
return true;
|
|
}
|
|
|
|
// Get the candidates list of of the real command name whose abbreviation matches to the command specified by the user
|
|
TOKEN_LIST *GetRealnameCandidate(char *input_name, TOKEN_LIST *real_name_list)
|
|
{
|
|
TOKEN_LIST *ret;
|
|
LIST *o;
|
|
UINT i;
|
|
bool ok = false;
|
|
// Validate arguments
|
|
if (input_name == NULL || real_name_list == NULL)
|
|
{
|
|
return NullToken();
|
|
}
|
|
|
|
o = NewListFast(NULL);
|
|
|
|
for (i = 0;i < real_name_list->NumTokens;i++)
|
|
{
|
|
char *name = real_name_list->Token[i];
|
|
|
|
// Search for an exact match with the highest priority first
|
|
if (StrCmpi(name, input_name) == 0)
|
|
{
|
|
Insert(o, name);
|
|
ok = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ok == false)
|
|
{
|
|
// If there is no command to exact match, check whether it matches to a short form command
|
|
for (i = 0;i < real_name_list->NumTokens;i++)
|
|
{
|
|
char *name = real_name_list->Token[i];
|
|
|
|
if (IsOmissionName(input_name, name) || IsNameInRealName(input_name, name))
|
|
{
|
|
// A abbreviation is found
|
|
Insert(o, name);
|
|
ok = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ok)
|
|
{
|
|
// One or more candidate is found
|
|
ret = ListToTokenList(o);
|
|
}
|
|
else
|
|
{
|
|
ret = NullToken();
|
|
}
|
|
|
|
ReleaseList(o);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Check whether the command specified by the user is a abbreviation of existing commands
|
|
bool IsOmissionName(char *input_name, char *real_name)
|
|
{
|
|
char oname[128];
|
|
// Validate arguments
|
|
if (input_name == NULL || real_name == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (IsAllUpperStr(real_name))
|
|
{
|
|
// Command of all capital letters do not take abbreviations
|
|
return false;
|
|
}
|
|
|
|
GetOmissionName(oname, sizeof(oname), real_name);
|
|
|
|
if (IsEmptyStr(oname))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (StartWith(oname, input_name))
|
|
{
|
|
// Example: The oname of AccountSecureCertSet is "ascs".
|
|
// But if the user enters "asc", returns true
|
|
return true;
|
|
}
|
|
|
|
if (StartWith(input_name, oname))
|
|
{
|
|
// Example: When two commands AccountCreate and AccountConnect exist,
|
|
// if the user enter "aconnect" , only AccountConnect is true
|
|
|
|
if (EndWith(real_name, &input_name[StrLen(oname)]))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Get the short name of the specified command
|
|
void GetOmissionName(char *dst, UINT size, char *src)
|
|
{
|
|
UINT i, len;
|
|
// Validate arguments
|
|
if (dst == NULL || src == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
StrCpy(dst, size, "");
|
|
len = StrLen(src);
|
|
|
|
for (i = 0;i < len;i++)
|
|
{
|
|
char c = src[i];
|
|
|
|
if ((c >= '0' && c <= '9') ||
|
|
(c >= 'A' && c <= 'Z'))
|
|
{
|
|
char tmp[2];
|
|
tmp[0] = c;
|
|
tmp[1] = 0;
|
|
|
|
StrCat(dst, size, tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check whether the command specified by the user matches the existing commands
|
|
bool IsNameInRealName(char *input_name, char *real_name)
|
|
{
|
|
// Validate arguments
|
|
if (input_name == NULL || real_name == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (StartWith(real_name, input_name))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Parse the command list
|
|
LIST *ParseCommandList(CONSOLE *c, char *cmd_name, wchar_t *command, PARAM param[], UINT num_param)
|
|
{
|
|
UINT i;
|
|
LIST *o;
|
|
bool ok = true;
|
|
TOKEN_LIST *param_list;
|
|
TOKEN_LIST *real_name_list;
|
|
bool help_mode = false;
|
|
wchar_t *tmp;
|
|
// Validate arguments
|
|
if (c == NULL || command == NULL || (num_param >= 1 && param == NULL) || cmd_name == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Initialization
|
|
for (i = 0;i < num_param;i++)
|
|
{
|
|
if (IsEmptyStr(param[i].Name) == false)
|
|
{
|
|
if (param[i].Name[0] == '[')
|
|
{
|
|
param[i].Tmp = "";
|
|
}
|
|
else
|
|
{
|
|
param[i].Tmp = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
param[i].Tmp = "";
|
|
}
|
|
}
|
|
|
|
real_name_list = ZeroMalloc(sizeof(TOKEN_LIST));
|
|
real_name_list->NumTokens = num_param;
|
|
real_name_list->Token = ZeroMalloc(sizeof(char *) * real_name_list->NumTokens);
|
|
|
|
for (i = 0;i < real_name_list->NumTokens;i++)
|
|
{
|
|
real_name_list->Token[i] = CopyStr(param[i].Name);
|
|
}
|
|
|
|
// Generate a list of parameter name specified by the user
|
|
param_list = GetCommandNameList(command);
|
|
|
|
for (i = 0;i < param_list->NumTokens;i++)
|
|
{
|
|
char *s = param_list->Token[i];
|
|
|
|
if (StrCmpi(s, "help") == 0 || StrCmpi(s, "?") == 0)
|
|
{
|
|
help_mode = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
tmp = ParseCommand(command, L"");
|
|
if (tmp != NULL)
|
|
{
|
|
if (UniStrCmpi(tmp, L"?") == 0)
|
|
{
|
|
help_mode = true;
|
|
}
|
|
Free(tmp);
|
|
}
|
|
|
|
if (help_mode)
|
|
{
|
|
// Show the help
|
|
PrintCmdHelp(c, cmd_name, real_name_list);
|
|
FreeToken(param_list);
|
|
FreeToken(real_name_list);
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0;i < param_list->NumTokens;i++)
|
|
{
|
|
// Get the corresponding commands for all parameter names which is specified by the user
|
|
TOKEN_LIST *candidate = GetRealnameCandidate(param_list->Token[i], real_name_list);
|
|
|
|
if (candidate != NULL && candidate->NumTokens >= 1)
|
|
{
|
|
if (candidate->NumTokens >= 2)
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
|
|
// There is more than one candidate
|
|
UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGUOUS_PARAM"), param_list->Token[i]);
|
|
c->Write(c, tmp);
|
|
UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGUOUS_PARAM_1"), cmd_name);
|
|
c->Write(c, tmp);
|
|
|
|
PrintCandidateHelp(c, cmd_name, candidate, 1);
|
|
|
|
c->Write(c, _UU("CON_AMBIGUOUS_PARAM_2"));
|
|
|
|
ok = false;
|
|
}
|
|
else
|
|
{
|
|
UINT j;
|
|
char *real_name = candidate->Token[0];
|
|
|
|
// There is only one candidate
|
|
for (j = 0;j < num_param;j++)
|
|
{
|
|
if (StrCmpi(param[j].Name, real_name) == 0)
|
|
{
|
|
param[j].Tmp = param_list->Token[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
|
|
// No candidate
|
|
UniFormat(tmp, sizeof(tmp), _UU("CON_INVALID_PARAM"), param_list->Token[i], cmd_name, cmd_name);
|
|
c->Write(c, tmp);
|
|
|
|
ok = false;
|
|
}
|
|
|
|
FreeToken(candidate);
|
|
}
|
|
|
|
if (ok == false)
|
|
{
|
|
FreeToken(param_list);
|
|
FreeToken(real_name_list);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Creating a list
|
|
o = NewParamValueList();
|
|
|
|
// Read all the parameters of the specified name in the parameter list
|
|
for (i = 0;i < num_param;i++)
|
|
{
|
|
bool prompt_input_value = false;
|
|
PARAM *p = ¶m[i];
|
|
|
|
if (p->Tmp != NULL || p->PromptProc != NULL)
|
|
{
|
|
wchar_t *name = CopyStrToUni(p->Name);
|
|
wchar_t *tmp;
|
|
wchar_t *str;
|
|
|
|
if (p->Tmp != NULL)
|
|
{
|
|
tmp = CopyStrToUni(p->Tmp);
|
|
}
|
|
else
|
|
{
|
|
tmp = CopyStrToUni(p->Name);
|
|
}
|
|
|
|
str = ParseCommand(command, tmp);
|
|
Free(tmp);
|
|
if (str != NULL)
|
|
{
|
|
wchar_t *unistr;
|
|
bool ret;
|
|
EVAL_VALUE:
|
|
// Reading succeeded
|
|
unistr = str;
|
|
|
|
if (p->EvalProc != NULL)
|
|
{
|
|
// Evaluate the value if EvalProc is specified
|
|
ret = p->EvalProc(c, unistr, p->EvalProcParam);
|
|
}
|
|
else
|
|
{
|
|
// Accept any value if EvalProc is not specified
|
|
ret = true;
|
|
}
|
|
|
|
if (ret == false)
|
|
{
|
|
// The specified value is invalid
|
|
if (p->PromptProc == NULL)
|
|
{
|
|
// Cancel
|
|
ok = false;
|
|
Free(name);
|
|
Free(str);
|
|
break;
|
|
}
|
|
else if (c->ProgrammingMode)
|
|
{
|
|
// In the programming mode, return the error immediately.
|
|
ok = false;
|
|
Free(name);
|
|
Free(str);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Request to re-enter
|
|
Free(str);
|
|
str = NULL;
|
|
goto SHOW_PROMPT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PARAM_VALUE *v;
|
|
// Finished loading, add it to the list
|
|
v = ZeroMalloc(sizeof(PARAM_VALUE));
|
|
v->Name = CopyStr(p->Name);
|
|
v->StrValue = CopyUniToStr(str);
|
|
v->UniStrValue = CopyUniStr(str);
|
|
v->IntValue = ToInt(v->StrValue);
|
|
Insert(o, v);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Failed to read. The parameter is not specified
|
|
if (p->PromptProc != NULL)
|
|
{
|
|
wchar_t *tmp;
|
|
SHOW_PROMPT:
|
|
// Prompt because it is a mandatory parameter
|
|
tmp = NULL;
|
|
if (c->ProgrammingMode == false)
|
|
{
|
|
tmp = p->PromptProc(c, p->PromptProcParam);
|
|
}
|
|
if (tmp == NULL)
|
|
{
|
|
// User canceled
|
|
ok = false;
|
|
Free(str);
|
|
Free(name);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Entered by the user
|
|
c->Write(c, L"");
|
|
str = tmp;
|
|
prompt_input_value = true;
|
|
goto EVAL_VALUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
Free(str);
|
|
Free(name);
|
|
}
|
|
}
|
|
|
|
FreeToken(param_list);
|
|
FreeToken(real_name_list);
|
|
|
|
if (ok)
|
|
{
|
|
return o;
|
|
}
|
|
else
|
|
{
|
|
FreeParamValueList(o);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Acquisition of [Yes] or [No]
|
|
bool GetParamYes(LIST *o, char *name)
|
|
{
|
|
char *s;
|
|
char tmp[64];
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
s = GetParamStr(o, name);
|
|
if (s == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
StrCpy(tmp, sizeof(tmp), s);
|
|
Trim(tmp);
|
|
|
|
if (StartWith(tmp, "y"))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (StartWith(tmp, "t"))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (ToInt(tmp) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Acquisition of parameter value Int
|
|
UINT GetParamInt(LIST *o, char *name)
|
|
{
|
|
PARAM_VALUE *v;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
v = FindParamValue(o, name);
|
|
if (v == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return v->IntValue;
|
|
}
|
|
}
|
|
|
|
// Acquisition of parameter value Unicode string
|
|
wchar_t *GetParamUniStr(LIST *o, char *name)
|
|
{
|
|
PARAM_VALUE *v;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
v = FindParamValue(o, name);
|
|
if (v == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
return v->UniStrValue;
|
|
}
|
|
}
|
|
|
|
// Acquisition of the parameter value string
|
|
char *GetParamStr(LIST *o, char *name)
|
|
{
|
|
PARAM_VALUE *v;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
v = FindParamValue(o, name);
|
|
if (v == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
return v->StrValue;
|
|
}
|
|
}
|
|
|
|
// Acquisition of parameter value
|
|
PARAM_VALUE *FindParamValue(LIST *o, char *name)
|
|
{
|
|
PARAM_VALUE t, *ret;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
if (name == NULL)
|
|
{
|
|
name = "";
|
|
}
|
|
|
|
Zero(&t, sizeof(t));
|
|
t.Name = name;
|
|
|
|
ret = Search(o, &t);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Release of the parameter value list
|
|
void FreeParamValueList(LIST *o)
|
|
{
|
|
UINT i;
|
|
// Validate arguments
|
|
if (o == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (i = 0;i < LIST_NUM(o);i++)
|
|
{
|
|
PARAM_VALUE *v = LIST_DATA(o, i);
|
|
|
|
Free(v->StrValue);
|
|
Free(v->UniStrValue);
|
|
Free(v->Name);
|
|
Free(v);
|
|
}
|
|
|
|
ReleaseList(o);
|
|
}
|
|
|
|
// Parameter value list sort function
|
|
int CmpParamValue(void *p1, void *p2)
|
|
{
|
|
PARAM_VALUE *v1, *v2;
|
|
if (p1 == NULL || p2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
v1 = *(PARAM_VALUE **)p1;
|
|
v2 = *(PARAM_VALUE **)p2;
|
|
if (v1 == NULL || v2 == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (IsEmptyStr(v1->Name) && IsEmptyStr(v2->Name))
|
|
{
|
|
return 0;
|
|
}
|
|
return StrCmpi(v1->Name, v2->Name);
|
|
}
|
|
|
|
// Generation of the parameter value list
|
|
LIST *NewParamValueList()
|
|
{
|
|
return NewListFast(CmpParamValue);
|
|
}
|
|
|
|
// Get the list of parameter names that were included in the entered command
|
|
TOKEN_LIST *GetCommandNameList(wchar_t *str)
|
|
{
|
|
TOKEN_LIST *t;
|
|
// Validate arguments
|
|
if (str == NULL)
|
|
{
|
|
return NullToken();
|
|
}
|
|
|
|
Free(ParseCommandEx(str, L"dummy_str", &t));
|
|
|
|
return t;
|
|
}
|
|
|
|
// Get the commands that start with the specified name
|
|
wchar_t *ParseCommand(wchar_t *str, wchar_t *name)
|
|
{
|
|
return ParseCommandEx(str, name, NULL);
|
|
}
|
|
wchar_t *ParseCommandEx(wchar_t *str, wchar_t *name, TOKEN_LIST **param_list)
|
|
{
|
|
UNI_TOKEN_LIST *t;
|
|
UINT i;
|
|
wchar_t *tmp;
|
|
wchar_t *ret = NULL;
|
|
LIST *o;
|
|
// Validate arguments
|
|
if (str == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
if (name != NULL && UniIsEmptyStr(name))
|
|
{
|
|
name = NULL;
|
|
}
|
|
|
|
o = NULL;
|
|
if (param_list != NULL)
|
|
{
|
|
o = NewListFast(CompareStr);
|
|
}
|
|
|
|
tmp = CopyUniStr(str);
|
|
UniTrim(tmp);
|
|
|
|
i = UniSearchStrEx(tmp, L"/CMD ", 0, false);
|
|
|
|
if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
|
|
{
|
|
i = INFINITE;
|
|
}
|
|
if (i == INFINITE)
|
|
{
|
|
i = UniSearchStrEx(tmp, L"/CMD\t", 0, false);
|
|
if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
|
|
{
|
|
i = INFINITE;
|
|
}
|
|
}
|
|
if (i == INFINITE)
|
|
{
|
|
i = UniSearchStrEx(tmp, L"/CMD:", 0, false);
|
|
if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
|
|
{
|
|
i = INFINITE;
|
|
}
|
|
}
|
|
if (i == INFINITE)
|
|
{
|
|
i = UniSearchStrEx(tmp, L"/CMD=", 0, false);
|
|
if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
|
|
{
|
|
i = INFINITE;
|
|
}
|
|
}
|
|
if (i == INFINITE)
|
|
{
|
|
i = UniSearchStrEx(tmp, L"-CMD ", 0, false);
|
|
if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
|
|
{
|
|
i = INFINITE;
|
|
}
|
|
}
|
|
if (i == INFINITE)
|
|
{
|
|
i = UniSearchStrEx(tmp, L"-CMD\t", 0, false);
|
|
if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
|
|
{
|
|
i = INFINITE;
|
|
}
|
|
}
|
|
if (i == INFINITE)
|
|
{
|
|
i = UniSearchStrEx(tmp, L"-CMD:", 0, false);
|
|
if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
|
|
{
|
|
i = INFINITE;
|
|
}
|
|
}
|
|
if (i == INFINITE)
|
|
{
|
|
i = UniSearchStrEx(tmp, L"-CMD=", 0, false);
|
|
if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
|
|
{
|
|
i = INFINITE;
|
|
}
|
|
}
|
|
|
|
if (i != INFINITE)
|
|
{
|
|
char *s = CopyStr("CMD");
|
|
if (InsertStr(o, s) == false)
|
|
{
|
|
Free(s);
|
|
}
|
|
if (UniStrCmpi(name, L"CMD") == 0)
|
|
{
|
|
ret = CopyUniStr(&str[i + 5]);
|
|
UniTrim(ret);
|
|
}
|
|
else
|
|
{
|
|
tmp[i] = 0;
|
|
}
|
|
}
|
|
|
|
if (ret == NULL)
|
|
{
|
|
t = UniParseCmdLine(tmp);
|
|
|
|
if (t != NULL)
|
|
{
|
|
for (i = 0;i < t->NumTokens;i++)
|
|
{
|
|
wchar_t *token = t->Token[i];
|
|
|
|
if ((token[0] == L'-' && token[1] != L'-') ||
|
|
(UniStrCmpi(token, L"--help") == 0) ||
|
|
(token[0] == L'/' && token[1] != L'/'))
|
|
{
|
|
UINT i;
|
|
|
|
// Named parameter
|
|
// Examine whether there is a colon character
|
|
|
|
if (UniStrCmpi(token, L"--help") == 0)
|
|
{
|
|
token++;
|
|
}
|
|
|
|
i = UniSearchStrEx(token, L":", 0, false);
|
|
if (i == INFINITE)
|
|
{
|
|
i = UniSearchStrEx(token, L"=", 0, false);
|
|
}
|
|
if (i != INFINITE)
|
|
{
|
|
wchar_t *tmp;
|
|
char *a;
|
|
|
|
// There is a colon character
|
|
tmp = CopyUniStr(token);
|
|
tmp[i] = 0;
|
|
|
|
a = CopyUniToStr(&tmp[1]);
|
|
if (InsertStr(o, a) == false)
|
|
{
|
|
Free(a);
|
|
}
|
|
|
|
if (UniStrCmpi(name, &tmp[1]) == 0)
|
|
{
|
|
if (ret == NULL)
|
|
{
|
|
// Content
|
|
ret = UniCopyStr(&token[i + 1]);
|
|
}
|
|
}
|
|
|
|
Free(tmp);
|
|
}
|
|
else
|
|
{
|
|
// There is no colon character
|
|
char *a;
|
|
|
|
a = CopyUniToStr(&token[1]);
|
|
if (InsertStr(o, a) == false)
|
|
{
|
|
Free(a);
|
|
}
|
|
|
|
if (UniStrCmpi(name, &token[1]) == 0)
|
|
{
|
|
if (ret == NULL)
|
|
{
|
|
// Empty character
|
|
ret = UniCopyStr(L"");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Nameless argument
|
|
if (name == NULL)
|
|
{
|
|
if (ret == NULL)
|
|
{
|
|
if (token[0] == L'-' && token[1] == L'-')
|
|
{
|
|
ret = UniCopyStr(&token[1]);
|
|
}
|
|
else if (token[0] == L'/' && token[1] == L'/')
|
|
{
|
|
ret = UniCopyStr(&token[1]);
|
|
}
|
|
else
|
|
{
|
|
ret = UniCopyStr(token);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
UniFreeToken(t);
|
|
}
|
|
}
|
|
|
|
Free(tmp);
|
|
|
|
if (o != NULL)
|
|
{
|
|
TOKEN_LIST *t = ZeroMalloc(sizeof(TOKEN_LIST));
|
|
UINT i;
|
|
|
|
t->NumTokens = LIST_NUM(o);
|
|
t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
|
|
|
|
for (i = 0;i < t->NumTokens;i++)
|
|
{
|
|
t->Token[i] = LIST_DATA(o, i);
|
|
}
|
|
|
|
ReleaseList(o);
|
|
|
|
*param_list = t;
|
|
}
|
|
|
|
if (UniStrCmpi(ret, L"none") == 0 || UniStrCmpi(ret, L"null") == 0)
|
|
{
|
|
// Null and none are reserved words
|
|
ret[0] = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
char *ParseCommandA(wchar_t *str, char *name)
|
|
{
|
|
wchar_t *tmp1, *tmp2;
|
|
char *ret;
|
|
// Validate arguments
|
|
if (str == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (name != NULL)
|
|
{
|
|
tmp1 = CopyStrToUni(name);
|
|
}
|
|
else
|
|
{
|
|
tmp1 = NULL;
|
|
}
|
|
|
|
tmp2 = ParseCommand(str, tmp1);
|
|
|
|
if (tmp2 == NULL)
|
|
{
|
|
ret = NULL;
|
|
}
|
|
else
|
|
{
|
|
ret = CopyUniToStr(tmp2);
|
|
Free(tmp2);
|
|
}
|
|
|
|
Free(tmp1);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Password prompt
|
|
bool PasswordPrompt(char *password, UINT size)
|
|
{
|
|
UINT wp;
|
|
bool escape = false;
|
|
void *console;
|
|
// Validate arguments
|
|
if (password == NULL || size <= 1)
|
|
{
|
|
if (size >= 1)
|
|
{
|
|
password[0] = 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
wp = 0;
|
|
|
|
Zero(password, size);
|
|
|
|
console = SetConsoleRaw();
|
|
|
|
while (true)
|
|
{
|
|
int c;
|
|
|
|
#ifdef OS_WIN32
|
|
c = _getch();
|
|
#else // OS_WIN32
|
|
c = getc(stdin);
|
|
PROCESS_CH:
|
|
#endif // OS_WIN32
|
|
|
|
if (c >= 0x20 && c <= 0x7E)
|
|
{
|
|
// Character
|
|
if ((wp + 1) < size)
|
|
{
|
|
password[wp++] = (char)c;
|
|
putc('*', stdout);
|
|
}
|
|
}
|
|
else if (c == 0x03)
|
|
{
|
|
// Break
|
|
RestoreConsole(console);
|
|
exit(0);
|
|
}
|
|
else if (c == 0x04 || c == 0x1a || c == 0x0D || c==0x0A)
|
|
{
|
|
// Exit
|
|
if (c == 0x04 || c == 0x1a)
|
|
{
|
|
escape = true;
|
|
}
|
|
break;
|
|
}
|
|
else if (c == 0xE0)
|
|
{
|
|
// Read one more character
|
|
#ifdef OS_WIN32
|
|
c = _getch();
|
|
#else // OS_WIN32
|
|
c = getc(stdin);
|
|
#endif // OS_WIN32
|
|
if (c == 0x4B || c == 0x53)
|
|
{
|
|
// Backspace
|
|
goto BACKSPACE;
|
|
}
|
|
}
|
|
#ifdef OS_UNIX // OS_UNIX
|
|
else if (c == 0x1B)
|
|
{
|
|
c = getc(stdin);
|
|
if (c != 0x5B && c != 0x4F)
|
|
{
|
|
// ESC key
|
|
goto PROCESS_CH;
|
|
}
|
|
|
|
c = getc(stdin);
|
|
if (c == 0x44)
|
|
{
|
|
// Left arrow key
|
|
goto BACKSPACE;
|
|
}
|
|
else if (c == 0x33)
|
|
{
|
|
c = getc(stdin);
|
|
if (c == 0x7E)
|
|
{
|
|
// Delete key
|
|
goto BACKSPACE;
|
|
}
|
|
}
|
|
|
|
// Drain remaining sequence bytes (most are <= 6)
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
if (c >= 0x40 && c <= 0x7E)
|
|
{
|
|
// End of sequence
|
|
break;
|
|
}
|
|
c = getc(stdin);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
#endif // OS_UNIX
|
|
else if (c == 0x08 || c == 0x7F)
|
|
{
|
|
BACKSPACE:
|
|
// Backspace
|
|
if (wp >= 1)
|
|
{
|
|
password[--wp] = 0;
|
|
putc(0x08, stdout);
|
|
putc(' ', stdout);
|
|
putc(0x08, stdout);
|
|
}
|
|
}
|
|
}
|
|
Print("\n");
|
|
|
|
RestoreConsole(console);
|
|
|
|
return (escape ? false : true);
|
|
}
|
|
|
|
// Show the prompt
|
|
wchar_t *Prompt(wchar_t *prompt_str)
|
|
{
|
|
wchar_t *ret = NULL;
|
|
wchar_t *tmp = NULL;
|
|
// Validate arguments
|
|
if (prompt_str == NULL)
|
|
{
|
|
prompt_str = L"";
|
|
}
|
|
|
|
#ifdef OS_WIN32
|
|
UniPrint(L"%s", prompt_str);
|
|
tmp = Malloc(MAX_PROMPT_STRSIZE);
|
|
if (fgetws(tmp, MAX_PROMPT_STRSIZE - 1, stdin) != NULL)
|
|
{
|
|
bool escape = false;
|
|
UINT i, len;
|
|
|
|
len = UniStrLen(tmp);
|
|
for (i = 0;i < len;i++)
|
|
{
|
|
if (tmp[i] == 0x04 || tmp[i] == 0x1A)
|
|
{
|
|
escape = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (escape == false)
|
|
{
|
|
UniTrimCrlf(tmp);
|
|
|
|
ret = UniCopyStr(tmp);
|
|
}
|
|
}
|
|
Free(tmp);
|
|
#else // OS_WIN32
|
|
{
|
|
char *prompt = CopyUniToStr(prompt_str);
|
|
char *s = readline(prompt);
|
|
Free(prompt);
|
|
|
|
if (s != NULL)
|
|
{
|
|
TrimCrlf(s);
|
|
Trim(s);
|
|
|
|
if (IsEmptyStr(s) == false)
|
|
{
|
|
add_history(s);
|
|
}
|
|
|
|
ret = CopyStrToUni(s);
|
|
|
|
free(s);
|
|
}
|
|
}
|
|
#endif // OS_WIN32
|
|
|
|
if (ret == NULL)
|
|
{
|
|
Print("\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
char *PromptA(wchar_t *prompt_str)
|
|
{
|
|
wchar_t *str = Prompt(prompt_str);
|
|
|
|
if (str == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
char *ret = CopyUniToStr(str);
|
|
|
|
Free(str);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
// Set the console to raw mode
|
|
void *SetConsoleRaw()
|
|
{
|
|
#ifdef OS_UNIX
|
|
struct termios t, *ret;
|
|
|
|
Zero(&t, sizeof(t));
|
|
if (tcgetattr(0, &t) != 0)
|
|
{
|
|
// Failed
|
|
return NULL;
|
|
}
|
|
|
|
// Copy the current settings
|
|
ret = Clone(&t, sizeof(t));
|
|
|
|
// Change the settings
|
|
t.c_lflag &= (~ICANON);
|
|
t.c_lflag &= (~ECHO);
|
|
t.c_cc[VTIME] = 0;
|
|
t.c_cc[VMIN] = 1;
|
|
tcsetattr(0, TCSANOW, &t);
|
|
|
|
return ret;
|
|
#else // OS_UNIX
|
|
return Malloc(0);
|
|
#endif // OS_UNIX
|
|
}
|
|
|
|
// Restore the mode of the console
|
|
void RestoreConsole(void *p)
|
|
{
|
|
#ifdef OS_UNIX
|
|
struct termios *t;
|
|
// Validate arguments
|
|
if (p == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
t = (struct termios *)p;
|
|
|
|
// Restore the settings
|
|
tcsetattr(0, TCSANOW, t);
|
|
|
|
Free(t);
|
|
#else // OS_UNIX
|
|
if (p != NULL)
|
|
{
|
|
Free(p);
|
|
}
|
|
#endif // OS_UNIX
|
|
}
|
|
|
|
////////////////////////////
|
|
// Local console function
|
|
|
|
// Creating a new local console
|
|
CONSOLE *NewLocalConsole(wchar_t *infile, wchar_t *outfile)
|
|
{
|
|
IO *in_io = NULL, *out_io = NULL;
|
|
CONSOLE *c = ZeroMalloc(sizeof(CONSOLE));
|
|
LOCAL_CONSOLE_PARAM *p;
|
|
UINT old_size = 0;
|
|
|
|
#ifdef OS_WIN32
|
|
if (MsGetConsoleWidth() == 80)
|
|
{
|
|
//old_size = MsSetConsoleWidth(WIN32_DEFAULT_CONSOLE_WIDTH);
|
|
}
|
|
#endif // OS_WIN32
|
|
|
|
c->ConsoleType = CONSOLE_LOCAL;
|
|
c->Free = ConsoleLocalFree;
|
|
c->ReadLine = ConsoleLocalReadLine;
|
|
c->ReadPassword = ConsoleLocalReadPassword;
|
|
c->Write = ConsoleLocalWrite;
|
|
c->GetWidth = ConsoleLocalGetWidth;
|
|
c->OutputLock = NewLock();
|
|
|
|
if (UniIsEmptyStr(infile) == false)
|
|
{
|
|
// Input file is specified
|
|
in_io = FileOpenW(infile, false);
|
|
if (in_io == NULL)
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
|
|
UniFormat(tmp, sizeof(tmp), _UU("CON_INFILE_ERROR"), infile);
|
|
c->Write(c, tmp);
|
|
Free(c);
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
|
|
UniFormat(tmp, sizeof(tmp), _UU("CON_INFILE_START"), infile);
|
|
c->Write(c, tmp);
|
|
}
|
|
}
|
|
|
|
if (UniIsEmptyStr(outfile) == false)
|
|
{
|
|
// Output file is specified
|
|
out_io = FileCreateW(outfile);
|
|
if (out_io == NULL)
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
|
|
UniFormat(tmp, sizeof(tmp), _UU("CON_OUTFILE_ERROR"), outfile);
|
|
c->Write(c, tmp);
|
|
Free(c);
|
|
|
|
if (in_io != NULL)
|
|
{
|
|
FileClose(in_io);
|
|
}
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
wchar_t tmp[MAX_SIZE];
|
|
|
|
UniFormat(tmp, sizeof(tmp), _UU("CON_OUTFILE_START"), outfile);
|
|
c->Write(c, tmp);
|
|
}
|
|
}
|
|
|
|
p = ZeroMalloc(sizeof(LOCAL_CONSOLE_PARAM));
|
|
c->Param = p;
|
|
|
|
p->InFile = in_io;
|
|
p->OutFile = out_io;
|
|
p->Win32_OldConsoleWidth = old_size;
|
|
|
|
if (in_io != NULL)
|
|
{
|
|
UINT size;
|
|
void *buf;
|
|
|
|
size = FileSize(in_io);
|
|
buf = ZeroMalloc(size + 1);
|
|
FileRead(in_io, buf, size);
|
|
|
|
p->InBuf = NewBuf();
|
|
WriteBuf(p->InBuf, buf, size);
|
|
Free(buf);
|
|
|
|
p->InBuf->Current = 0;
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
// Release Console
|
|
void ConsoleLocalFree(CONSOLE *c)
|
|
{
|
|
LOCAL_CONSOLE_PARAM *p;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
p = (LOCAL_CONSOLE_PARAM *)c->Param;
|
|
|
|
#ifdef OS_WIN32
|
|
if (p->Win32_OldConsoleWidth != 0)
|
|
{
|
|
MsSetConsoleWidth(p->Win32_OldConsoleWidth);
|
|
}
|
|
#endif // OS_WIN32
|
|
|
|
if (p != NULL)
|
|
{
|
|
if (p->InFile != NULL)
|
|
{
|
|
FileClose(p->InFile);
|
|
FreeBuf(p->InBuf);
|
|
}
|
|
|
|
if (p->OutFile != NULL)
|
|
{
|
|
FileClose(p->OutFile);
|
|
}
|
|
|
|
Free(p);
|
|
}
|
|
|
|
DeleteLock(c->OutputLock);
|
|
|
|
// Memory release
|
|
Free(c);
|
|
}
|
|
|
|
// Get the width of the screen
|
|
UINT ConsoleLocalGetWidth(CONSOLE *c)
|
|
{
|
|
UINT ret = 0;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#ifdef OS_WIN32
|
|
ret = MsGetConsoleWidth();
|
|
#else // OS_WIN32
|
|
{
|
|
struct winsize t;
|
|
|
|
Zero(&t, sizeof(t));
|
|
|
|
if (ioctl(1, TIOCGWINSZ, &t) == 0)
|
|
{
|
|
ret = t.ws_col;
|
|
}
|
|
}
|
|
#endif // OS_WIN32
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Read one line from the console
|
|
wchar_t *ConsoleLocalReadLine(CONSOLE *c, wchar_t *prompt, bool nofile)
|
|
{
|
|
wchar_t *ret;
|
|
LOCAL_CONSOLE_PARAM *p;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
p = (LOCAL_CONSOLE_PARAM *)c->Param;
|
|
if (prompt == NULL)
|
|
{
|
|
prompt = L">";
|
|
}
|
|
|
|
ConsoleWriteOutFile(c, prompt, false);
|
|
|
|
if (nofile == false && p->InBuf != NULL)
|
|
{
|
|
// Read the next line from the file
|
|
ret = ConsoleReadNextFromInFile(c);
|
|
|
|
if (ret != NULL)
|
|
{
|
|
// Display the pseudo prompt
|
|
UniPrint(L"%s", prompt);
|
|
|
|
// Display on the screen
|
|
UniPrint(L"%s\n", ret);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Read the following line from the console
|
|
ret = Prompt(prompt);
|
|
}
|
|
|
|
if (ret != NULL)
|
|
{
|
|
ConsoleWriteOutFile(c, ret, true);
|
|
}
|
|
else
|
|
{
|
|
ConsoleWriteOutFile(c, _UU("CON_USER_CANCEL"), true);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Read the password from the console
|
|
char *ConsoleLocalReadPassword(CONSOLE *c, wchar_t *prompt)
|
|
{
|
|
char tmp[64];
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
if (prompt == NULL)
|
|
{
|
|
prompt = L"Password>";
|
|
}
|
|
|
|
UniPrint(L"%s", prompt);
|
|
ConsoleWriteOutFile(c, prompt, false);
|
|
|
|
if (PasswordPrompt(tmp, sizeof(tmp)))
|
|
{
|
|
ConsoleWriteOutFile(c, L"********", true);
|
|
return CopyStr(tmp);
|
|
}
|
|
else
|
|
{
|
|
ConsoleWriteOutFile(c, _UU("CON_USER_CANCEL"), true);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Display a string to the console
|
|
bool ConsoleLocalWrite(CONSOLE *c, wchar_t *str)
|
|
{
|
|
// Validate arguments
|
|
if (c == NULL || str == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
UniPrint(L"%s%s", str, (UniEndWith(str, L"\n") ? L"" : L"\n"));
|
|
|
|
ConsoleWriteOutFile(c, str, true);
|
|
|
|
return true;
|
|
}
|
|
|
|
// Read the next line from the input file
|
|
wchar_t *ConsoleReadNextFromInFile(CONSOLE *c)
|
|
{
|
|
LOCAL_CONSOLE_PARAM *p;
|
|
char *str;
|
|
// Validate arguments
|
|
if (c == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
p = (LOCAL_CONSOLE_PARAM *)c->Param;
|
|
|
|
if (p->InBuf == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
str = CfgReadNextLine(p->InBuf);
|
|
|
|
if (str == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
Trim(str);
|
|
|
|
if (IsEmptyStr(str) == false)
|
|
{
|
|
UINT size;
|
|
wchar_t *ret;
|
|
|
|
size = CalcUtf8ToUni((BYTE *)str, StrLen(str));
|
|
ret = ZeroMalloc(size + 32);
|
|
Utf8ToUni(ret, size, (BYTE *)str, StrLen(str));
|
|
|
|
Free(str);
|
|
|
|
return ret;
|
|
}
|
|
|
|
Free(str);
|
|
}
|
|
}
|
|
|
|
// Write when the output file is specified
|
|
void ConsoleWriteOutFile(CONSOLE *c, wchar_t *str, bool add_last_crlf)
|
|
{
|
|
LOCAL_CONSOLE_PARAM *p;
|
|
// Validate arguments
|
|
if (c == NULL || str == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
p = (LOCAL_CONSOLE_PARAM *)c->Param;
|
|
|
|
if (p != NULL && p->OutFile != NULL)
|
|
{
|
|
wchar_t *tmp = UniNormalizeCrlf(str);
|
|
UINT utf8_size;
|
|
UCHAR *utf8;
|
|
|
|
utf8_size = CalcUniToUtf8(tmp);
|
|
utf8 = ZeroMalloc(utf8_size + 1);
|
|
UniToUtf8(utf8, utf8_size + 1, tmp);
|
|
|
|
FileWrite(p->OutFile, utf8, utf8_size);
|
|
|
|
if (UniEndWith(str, L"\n") == false && add_last_crlf)
|
|
{
|
|
char *crlf = "\r\n";
|
|
FileWrite(p->OutFile, "\r\n", StrLen(crlf));
|
|
}
|
|
|
|
Free(utf8);
|
|
Free(tmp);
|
|
}
|
|
|
|
}
|
|
|