1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2026-01-26 13:20:12 +03:00
Files
SoftEtherVPN/src/Cedar/Console.c
synqa eaef60a582 Fix password input handling on Linux
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.
2026-01-24 12:37:43 +09:00

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