mirror of
https://github.com/reactos/reactos.git
synced 2026-06-01 00:40:26 +08:00
349 lines
8.5 KiB
C
349 lines
8.5 KiB
C
/*
|
|
* PROJECT: ReactOS NetSh
|
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
|
* PURPOSE: Network Shell builtin help command and support functions
|
|
* COPYRIGHT: Copyright 2023 Eric Kohl <eric.kohl@reactos.org>
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#define HUGE_HELP_BUFFER_SIZE 2048
|
|
#define SMALL_HELP_BUFFER_SIZE 160
|
|
#define TINY_HELP_BUFFER_SIZE 80
|
|
|
|
typedef enum
|
|
{
|
|
Command,
|
|
Group,
|
|
SubContext
|
|
} HELP_TYPE, *PHELP_TYPE;
|
|
|
|
typedef struct
|
|
{
|
|
HELP_TYPE Type;
|
|
PWSTR pszCommand;
|
|
DWORD dwHelpId;
|
|
union
|
|
{
|
|
PCOMMAND_ENTRY pCommand;
|
|
PCOMMAND_GROUP pGroup;
|
|
PCONTEXT_ENTRY pSubContext;
|
|
} Pointer;
|
|
} HELP_ENTRY, *PHELP_ENTRY;
|
|
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
static
|
|
VOID
|
|
GetContextFullName(
|
|
_In_ PCONTEXT_ENTRY pContext,
|
|
_Inout_ LPWSTR pszBuffer,
|
|
_In_ DWORD cchLength)
|
|
{
|
|
if (pContext != pRootContext)
|
|
{
|
|
GetContextFullName(pContext->pParentContext, pszBuffer, cchLength);
|
|
wcscat(pszBuffer, L" ");
|
|
wcscat(pszBuffer, pContext->pszContextName);
|
|
}
|
|
else
|
|
{
|
|
wcscpy(pszBuffer, pContext->pszContextName);
|
|
}
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
PrintCurrentContextHeader(
|
|
_In_ PCONTEXT_ENTRY pContext)
|
|
{
|
|
if (pContext == pCurrentContext)
|
|
{
|
|
ConResPrintf(StdOut, IDS_THIS_COMMANDS);
|
|
}
|
|
else
|
|
{
|
|
WCHAR szBuffer[SMALL_HELP_BUFFER_SIZE];
|
|
GetContextFullName(pContext, szBuffer, _countof(szBuffer));
|
|
ConResPrintf(StdOut, IDS_CONTEXT_COMMANDS, szBuffer);
|
|
}
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
PrintShortGroupCommands(
|
|
_In_ PCONTEXT_ENTRY pContext,
|
|
_In_ PCOMMAND_GROUP pGroup)
|
|
{
|
|
PCOMMAND_ENTRY pCommand;
|
|
WCHAR szBuffer1[TINY_HELP_BUFFER_SIZE];
|
|
WCHAR szBuffer2[SMALL_HELP_BUFFER_SIZE];
|
|
|
|
pCommand = pGroup->pCommandListHead;
|
|
while (pCommand != NULL)
|
|
{
|
|
_swprintf(szBuffer1, L"%s %s", pGroup->pwszCmdGroupToken, pCommand->pwszCmdToken);
|
|
LoadStringW(pContext->hModule, pCommand->dwShortCmdHelpToken, szBuffer2, _countof(szBuffer2));
|
|
|
|
ConPrintf(StdOut, L"%-15s - %s", szBuffer1, szBuffer2);
|
|
pCommand = pCommand->pNext;
|
|
}
|
|
}
|
|
|
|
|
|
static
|
|
int
|
|
HelpCompare(
|
|
_In_ const void *p1,
|
|
_In_ const void *p2)
|
|
{
|
|
return _wcsicmp(((PHELP_ENTRY)p1)->pszCommand, ((PHELP_ENTRY)p2)->pszCommand);
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
PrintContext(
|
|
_In_ PCONTEXT_ENTRY pContext)
|
|
{
|
|
PCOMMAND_ENTRY pCommand;
|
|
PCOMMAND_GROUP pGroup;
|
|
PCONTEXT_ENTRY pSubContext;
|
|
PHELP_ENTRY pHelpArray = NULL;
|
|
DWORD dwCount = 0, dwIndex;
|
|
WCHAR szBuffer[SMALL_HELP_BUFFER_SIZE];
|
|
|
|
DPRINT("PrintContext()\n");
|
|
|
|
if (pContext != pRootContext)
|
|
PrintContext(pContext->pParentContext);
|
|
|
|
PrintCurrentContextHeader(pContext);
|
|
|
|
/* Count short commands */
|
|
pCommand = pContext->pCommandListHead;
|
|
while (pCommand != NULL)
|
|
{
|
|
dwCount++;
|
|
pCommand = pCommand->pNext;
|
|
}
|
|
|
|
/* Count short groups */
|
|
pGroup = pContext->pGroupListHead;
|
|
while (pGroup != NULL)
|
|
{
|
|
dwCount++;
|
|
pGroup = pGroup->pNext;
|
|
}
|
|
|
|
/* Count short subcontexts */
|
|
pSubContext = pContext->pSubContextHead;
|
|
while (pSubContext != NULL)
|
|
{
|
|
dwCount++;
|
|
pSubContext = pSubContext->pNext;
|
|
}
|
|
|
|
pHelpArray = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * sizeof(HELP_ENTRY));
|
|
if (pHelpArray == NULL)
|
|
return;
|
|
|
|
dwIndex = 0;
|
|
|
|
/* Add short commands */
|
|
pCommand = pContext->pCommandListHead;
|
|
while (pCommand != NULL)
|
|
{
|
|
pHelpArray[dwIndex].Type = Command;
|
|
pHelpArray[dwIndex].pszCommand = pCommand->pwszCmdToken;
|
|
pHelpArray[dwIndex].dwHelpId = pCommand->dwShortCmdHelpToken;
|
|
// pHelpArray[dwIndex].Pointer.pCommand = pCommand;
|
|
dwIndex++;
|
|
pCommand = pCommand->pNext;
|
|
}
|
|
|
|
/* Add short groups */
|
|
pGroup = pContext->pGroupListHead;
|
|
while (pGroup != NULL)
|
|
{
|
|
pHelpArray[dwIndex].Type = Group;
|
|
pHelpArray[dwIndex].pszCommand = pGroup->pwszCmdGroupToken;
|
|
pHelpArray[dwIndex].dwHelpId = pGroup->dwShortCmdHelpToken;
|
|
// pHelpArray[dwIndex].Pointer.pGroup = pGroup;
|
|
dwIndex++;
|
|
pGroup = pGroup->pNext;
|
|
}
|
|
|
|
/* Count short subcontexts */
|
|
pSubContext = pContext->pSubContextHead;
|
|
while (pSubContext != NULL)
|
|
{
|
|
pHelpArray[dwIndex].Type = SubContext;
|
|
pHelpArray[dwIndex].pszCommand = pSubContext->pszContextName;
|
|
pHelpArray[dwIndex].Pointer.pSubContext = pSubContext;
|
|
dwIndex++;
|
|
pSubContext = pSubContext->pNext;
|
|
}
|
|
|
|
qsort(pHelpArray, dwCount, sizeof(HELP_ENTRY), HelpCompare);
|
|
|
|
for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
|
|
{
|
|
switch (pHelpArray[dwIndex].Type)
|
|
{
|
|
case Command:
|
|
case Group:
|
|
if (LoadStringW(pContext->hModule, pHelpArray[dwIndex].dwHelpId, szBuffer, _countof(szBuffer)) == 0)
|
|
szBuffer[0] = UNICODE_NULL;
|
|
ConPrintf(StdOut, L"%-15s - %s", pHelpArray[dwIndex].pszCommand, szBuffer);
|
|
break;
|
|
|
|
case SubContext:
|
|
GetContextFullName(pHelpArray[dwIndex].Pointer.pSubContext, szBuffer, _countof(szBuffer));
|
|
ConPrintf(StdOut, L"%-15s - Changes to the \"%s\" context.\n", pHelpArray[dwIndex].pszCommand, szBuffer);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pHelpArray)
|
|
HeapFree(GetProcessHeap(), 0, pHelpArray);
|
|
}
|
|
|
|
|
|
static
|
|
int
|
|
SubContextCompare(
|
|
_In_ const void *p1,
|
|
_In_ const void *p2)
|
|
{
|
|
return _wcsicmp((*((PCONTEXT_ENTRY*)p1))->pszContextName, (*((PCONTEXT_ENTRY*)p2))->pszContextName);
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
PrintSubcontexts(
|
|
_In_ PCONTEXT_ENTRY pContext)
|
|
{
|
|
PCONTEXT_ENTRY pSubContext, *pSubContextArray = NULL;
|
|
DWORD dwCount, dwIndex;
|
|
|
|
if (pContext->pSubContextHead == NULL)
|
|
return;
|
|
|
|
dwCount = 0;
|
|
pSubContext = pContext->pSubContextHead;
|
|
while (pSubContext != NULL)
|
|
{
|
|
dwCount++;
|
|
pSubContext = pSubContext->pNext;
|
|
}
|
|
|
|
pSubContextArray = HeapAlloc(GetProcessHeap(), 0, dwCount * sizeof(PCONTEXT_ENTRY));
|
|
if (pSubContextArray == NULL)
|
|
return;
|
|
|
|
dwIndex = 0;
|
|
pSubContext = pContext->pSubContextHead;
|
|
while (pSubContext != NULL)
|
|
{
|
|
pSubContextArray[dwIndex] = pSubContext;
|
|
dwIndex++;
|
|
pSubContext = pSubContext->pNext;
|
|
}
|
|
|
|
qsort(pSubContextArray, dwCount, sizeof(PCONTEXT_ENTRY), SubContextCompare);
|
|
|
|
ConResPrintf(StdOut, IDS_SUBCONTEXT_HEADER);
|
|
for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
|
|
{
|
|
ConPrintf(StdOut, L" %s", pSubContextArray[dwIndex]->pszContextName);
|
|
}
|
|
ConPuts(StdOut, L"\n");
|
|
|
|
HeapFree(GetProcessHeap(), 0, pSubContextArray);
|
|
}
|
|
|
|
|
|
VOID
|
|
PrintCommandHelp(
|
|
_In_ PCONTEXT_ENTRY pContext,
|
|
_In_ PCOMMAND_GROUP pGroup,
|
|
_In_ PCOMMAND_ENTRY pCommand)
|
|
{
|
|
LPWSTR pszCommandBuffer;
|
|
DWORD_PTR Args[2];
|
|
|
|
DPRINT("PrintCommandHelp(%p %p %p)\n", pContext, pGroup, pCommand);
|
|
|
|
pszCommandBuffer = HeapAlloc(GetProcessHeap(), 0, TINY_HELP_BUFFER_SIZE * sizeof(WCHAR));
|
|
if (pszCommandBuffer == NULL)
|
|
return;
|
|
|
|
wcscpy(pszCommandBuffer, pCommand->pwszCmdToken);
|
|
if (pGroup)
|
|
{
|
|
wcscat(pszCommandBuffer, L" ");
|
|
wcscat(pszCommandBuffer, pGroup->pwszCmdGroupToken);
|
|
}
|
|
|
|
Args[0] = (DWORD_PTR)pszCommandBuffer;
|
|
Args[1] = (DWORD_PTR)NULL;
|
|
|
|
ConResMsgPrintfExV(StdOut,
|
|
pContext->hModule,
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
pCommand->dwCmdHlpToken,
|
|
LANG_USER_DEFAULT,
|
|
(va_list *)&Args);
|
|
ConPuts(StdOut, L"\n");
|
|
|
|
HeapFree(GetProcessHeap(), 0, pszCommandBuffer);
|
|
}
|
|
|
|
|
|
VOID
|
|
PrintGroupHelp(
|
|
_In_ PCONTEXT_ENTRY pContext,
|
|
_In_ LPWSTR pszGroupName,
|
|
_In_ BOOL bRecurse)
|
|
{
|
|
PCOMMAND_GROUP pGroup;
|
|
|
|
if (bRecurse)
|
|
{
|
|
if (pContext != pRootContext)
|
|
PrintGroupHelp(pContext->pParentContext, pszGroupName, bRecurse);
|
|
}
|
|
|
|
pGroup = pContext->pGroupListHead;
|
|
while (pGroup != NULL)
|
|
{
|
|
if (_wcsicmp(pszGroupName, pGroup->pwszCmdGroupToken) == 0)
|
|
{
|
|
PrintCurrentContextHeader(pContext);
|
|
PrintShortGroupCommands(pContext, pGroup);
|
|
}
|
|
pGroup = pGroup->pNext;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
PrintContextHelp(
|
|
_In_ PCONTEXT_ENTRY pContext)
|
|
{
|
|
ConResPrintf(StdOut, IDS_HELP_HEADER);
|
|
PrintContext(pContext);
|
|
PrintSubcontexts(pContext);
|
|
ConResPrintf(StdOut, IDS_HELP_FOOTER);
|
|
}
|