From 3f6639031c5cdc401550973a3d62beec00fd8b89 Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Sat, 23 Aug 2025 11:06:19 +0200 Subject: [PATCH] [NETSH] Context stack and helper improvements - Add the context stack including the PUSHD and POPD commands. - Add the required changes to the HELP command and command execution to support the context stack. - Add support for sub helpers. --- base/applications/network/netsh/context.c | 214 ++++++++++++-- base/applications/network/netsh/help.c | 262 +++++++++++++++--- base/applications/network/netsh/helper.c | 43 ++- base/applications/network/netsh/interpreter.c | 133 ++++++--- base/applications/network/netsh/lang/en-US.rc | 8 +- base/applications/network/netsh/netsh.c | 8 +- base/applications/network/netsh/precomp.h | 39 ++- base/applications/network/netsh/resource.h | 7 +- 8 files changed, 585 insertions(+), 129 deletions(-) diff --git a/base/applications/network/netsh/context.c b/base/applications/network/netsh/context.c index dded888c879..995ac98570c 100644 --- a/base/applications/network/netsh/context.c +++ b/base/applications/network/netsh/context.c @@ -14,9 +14,21 @@ /* GLOBALS ********************************************************************/ +typedef struct _CONTEXT_STACK_ENTRY +{ + struct _CONTEXT_STACK_ENTRY *pPrev; + struct _CONTEXT_STACK_ENTRY *pNext; + + PCONTEXT_ENTRY pContext; +} CONTEXT_STACK_ENTRY, *PCONTEXT_STACK_ENTRY; + + PCONTEXT_ENTRY pRootContext = NULL; PCONTEXT_ENTRY pCurrentContext = NULL; +PCONTEXT_STACK_ENTRY pContextStackHead = NULL; +PCONTEXT_STACK_ENTRY pContextStackTail = NULL; + /* FUNCTIONS ******************************************************************/ PCONTEXT_ENTRY @@ -135,6 +147,8 @@ AddCommandGroup( { PCOMMAND_GROUP pEntry; + DPRINT("AddCommandGroup(%S %lu)\n", pwszCmdGroupToken, dwShortCmdHelpToken); + /* Allocate the entry */ pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_GROUP)); if (pEntry == NULL) @@ -220,10 +234,68 @@ AddGroupCommand( } +VOID +RemoveContextFromStack( + _In_ PCONTEXT_ENTRY pContextEntry) +{ + PCONTEXT_STACK_ENTRY pStackEntry, pNextEntry; + + if (pContextStackHead == NULL) + return; + + pStackEntry = pContextStackHead; + while (1) + { + if (pStackEntry->pContext == pContextEntry) + { + if (pStackEntry == pContextStackHead && pStackEntry == pContextStackHead) + { + pContextStackHead = NULL; + pContextStackTail = NULL; + HeapFree(GetProcessHeap(), 0, pStackEntry); + return; + } + else if (pStackEntry == pContextStackHead) + { + pStackEntry->pNext->pPrev = NULL; + pContextStackHead = pStackEntry->pNext; + HeapFree(GetProcessHeap(), 0, pStackEntry); + pStackEntry = pContextStackHead; + } + else if (pStackEntry == pContextStackTail) + { + pStackEntry->pPrev->pNext = NULL; + pContextStackTail = pStackEntry->pPrev; + HeapFree(GetProcessHeap(), 0, pStackEntry); + return; + } + else + { + pNextEntry = pStackEntry->pNext; + pStackEntry->pPrev->pNext = pStackEntry->pNext; + pStackEntry->pNext->pPrev = pStackEntry->pPrev; + HeapFree(GetProcessHeap(), 0, pStackEntry); + pStackEntry = pNextEntry; + } + } + else + { + if (pStackEntry == pContextStackTail) + return; + + pStackEntry = pStackEntry->pNext; + } + } +} + + VOID DeleteContext( PWSTR pszName) { + /* Remove the context from the stack */ + /* RemoveContextFromStack(); */ + /* Delete all commands */ /* Delete the context */ } @@ -278,6 +350,81 @@ RemCommand( } +DWORD +WINAPI +PopdCommand( + LPCWSTR pwszMachine, + LPWSTR *argv, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + BOOL *pbDone) +{ + PCONTEXT_STACK_ENTRY pEntry; + + DPRINT("PopdCommand()\n"); + + if (pContextStackHead == NULL) + return 0; + + pEntry = pContextStackHead; + + pCurrentContext = pEntry->pContext; + + if (pContextStackTail == pEntry) + { + pContextStackHead = NULL; + pContextStackTail = NULL; + } + else + { + pContextStackHead = pEntry->pNext; + pContextStackHead->pPrev = NULL; + } + + HeapFree(GetProcessHeap(), 0, pEntry); + + return 0; +} + + +DWORD +WINAPI +PushdCommand( + LPCWSTR pwszMachine, + LPWSTR *argv, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + _Out_ BOOL *pbDone) +{ + PCONTEXT_STACK_ENTRY pEntry; + + DPRINT("PushdCommand()\n"); + + pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CONTEXT_STACK_ENTRY)); + if (pEntry == NULL) + return 1; + + pEntry->pContext = pCurrentContext; + if (pContextStackHead == NULL) + { + pContextStackHead = pEntry; + pContextStackTail = pEntry; + } + else + { + pEntry->pNext = pContextStackHead; + pContextStackHead->pPrev = pEntry; + pContextStackHead = pEntry; + } + + return 0; +} + + BOOL CreateRootContext(VOID) { @@ -290,12 +437,14 @@ CreateRootContext(VOID) pRootContext->hModule = GetModuleHandle(NULL); - AddContextCommand(pRootContext, L"..", UpCommand, IDS_HLP_UP, IDS_HLP_UP_EX, 0); - AddContextCommand(pRootContext, L"?", HelpCommand, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0); - AddContextCommand(pRootContext, L"bye", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); - AddContextCommand(pRootContext, L"exit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); - AddContextCommand(pRootContext, L"help", HelpCommand, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0); - AddContextCommand(pRootContext, L"quit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); + AddContextCommand(pRootContext, L"..", UpCommand, IDS_HLP_UP, IDS_HLP_UP_EX, 0); + AddContextCommand(pRootContext, L"?", NULL, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0); + AddContextCommand(pRootContext, L"bye", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); + AddContextCommand(pRootContext, L"exit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); + AddContextCommand(pRootContext, L"help", NULL, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0); + AddContextCommand(pRootContext, L"popd", PopdCommand, IDS_HLP_POPD, IDS_HLP_POPD_EX, 0); + AddContextCommand(pRootContext, L"pushd", PushdCommand, IDS_HLP_PUSHD, IDS_HLP_PUSHD_EX, 0); + AddContextCommand(pRootContext, L"quit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); pGroup = AddCommandGroup(pRootContext, L"add", IDS_HLP_GROUP_ADD, 0); if (pGroup) @@ -326,8 +475,10 @@ WINAPI RegisterContext( _In_ const NS_CONTEXT_ATTRIBUTES *pChildContext) { + PHELPER_ENTRY pHelper; PCONTEXT_ENTRY pContext; - DWORD i; + PCOMMAND_GROUP pGroup; + DWORD i, j; DPRINT1("RegisterContext(%p)\n", pChildContext); if (pChildContext == NULL) @@ -345,30 +496,59 @@ RegisterContext( return ERROR_INVALID_PARAMETER; } - DPRINT1("Name: %S\n", pChildContext->pwszContext); + DPRINT("Name: %S\n", pChildContext->pwszContext); + DPRINT("Groups: %lu\n", pChildContext->ulNumGroups); + DPRINT("Top commands: %lu\n", pChildContext->ulNumTopCmds); + + pHelper = FindHelper(&pChildContext->guidHelper, pHelperListHead); pContext = AddContext(pRootContext, pChildContext->pwszContext, (GUID*)&pChildContext->guidHelper); if (pContext != NULL) { + if ((pHelper != NULL) && (pHelper->pDllEntry != NULL)) + { + pContext->hModule = pHelper->pDllEntry->hModule; + } + for (i = 0; i < pChildContext->ulNumTopCmds; i++) { AddContextCommand(pContext, - pChildContext->pTopCmds[i].pwszCmdToken, - pChildContext->pTopCmds[i].pfnCmdHandler, - pChildContext->pTopCmds[i].dwShortCmdHelpToken, - pChildContext->pTopCmds[i].dwCmdHlpToken, - pChildContext->pTopCmds[i].dwFlags); + pChildContext->pTopCmds[i].pwszCmdToken, + pChildContext->pTopCmds[i].pfnCmdHandler, + pChildContext->pTopCmds[i].dwShortCmdHelpToken, + pChildContext->pTopCmds[i].dwCmdHlpToken, + pChildContext->pTopCmds[i].dwFlags); } /* Add command groups */ for (i = 0; i < pChildContext->ulNumGroups; i++) { - AddCommandGroup(pContext, - pChildContext->pCmdGroups[i].pwszCmdGroupToken, - pChildContext->pCmdGroups[i].dwShortCmdHelpToken, - pChildContext->pCmdGroups[i].dwFlags); + pGroup = AddCommandGroup(pContext, + pChildContext->pCmdGroups[i].pwszCmdGroupToken, + pChildContext->pCmdGroups[i].dwShortCmdHelpToken, + pChildContext->pCmdGroups[i].dwFlags); + if (pGroup != NULL) + { + for (j = 0; j < pChildContext->pCmdGroups[i].ulCmdGroupSize; j++) + { + AddGroupCommand(pGroup, + pChildContext->pCmdGroups[i].pCmdGroup[j].pwszCmdToken, + pChildContext->pCmdGroups[i].pCmdGroup[j].pfnCmdHandler, + pChildContext->pCmdGroups[i].pCmdGroup[j].dwShortCmdHelpToken, + pChildContext->pCmdGroups[i].pCmdGroup[j].dwCmdHlpToken, + pChildContext->pCmdGroups[i].pCmdGroup[j].dwFlags); + } + } } } return ERROR_SUCCESS; } + + +VOID +CleanupContext(VOID) +{ + /* Delete the context stack */ + +} diff --git a/base/applications/network/netsh/help.c b/base/applications/network/netsh/help.c index a446e1ec10c..6f099cbaa7d 100644 --- a/base/applications/network/netsh/help.c +++ b/base/applications/network/netsh/help.c @@ -36,17 +36,11 @@ GetContextFullName( static VOID -HelpContext( - PCONTEXT_ENTRY pContext) +PrintCurrentContextHeader( + _In_ PCONTEXT_ENTRY pContext) { - PCONTEXT_ENTRY pSubContext; - PCOMMAND_ENTRY pCommand; - PCOMMAND_GROUP pGroup; WCHAR szBuffer[80]; - if (pContext != pRootContext) - HelpContext(pContext->pParentContext); - if (pContext == pCurrentContext) { ConPrintf(StdOut, L"\nCommands in this context:\n"); @@ -60,6 +54,16 @@ HelpContext( GetContextFullName(pContext, szBuffer, 80); ConPrintf(StdOut, L"\nCommands in the %s-context:\n", szBuffer); } +} + + +static +VOID +PrintShortCommands( + _In_ PCONTEXT_ENTRY pContext) +{ + PCOMMAND_ENTRY pCommand; + WCHAR szBuffer[80]; pCommand = pContext->pCommandListHead; while (pCommand != NULL) @@ -69,6 +73,16 @@ HelpContext( ConPrintf(StdOut, L"%-15s - %s\n", pCommand->pwszCmdToken, szBuffer); pCommand = pCommand->pNext; } +} + + +static +VOID +PrintShortGroups( + _In_ PCONTEXT_ENTRY pContext) +{ + PCOMMAND_GROUP pGroup; + WCHAR szBuffer[80]; pGroup = pContext->pGroupListHead; while (pGroup != NULL) @@ -78,6 +92,16 @@ HelpContext( ConPrintf(StdOut, L"%-15s - %s\n", pGroup->pwszCmdGroupToken, szBuffer); pGroup = pGroup->pNext; } +} + + +static +VOID +PrintShortSubContexts( + _In_ PCONTEXT_ENTRY pContext) +{ + PCONTEXT_ENTRY pSubContext; + WCHAR szBuffer[80]; pSubContext = pContext->pSubContextHead; while (pSubContext != NULL) @@ -88,29 +112,203 @@ HelpContext( } } - +static VOID -HelpGroup( - PCOMMAND_GROUP pGroup) +PrintShortGroupCommands( + _In_ PCONTEXT_ENTRY pContext, + _In_ PCOMMAND_GROUP pGroup) { PCOMMAND_ENTRY pCommand; - WCHAR szBuffer[64]; - - ConResPrintf(StdOut, IDS_HELP_HEADER); - - ConPrintf(StdOut, L"\nCommands in this context:\n"); + WCHAR szBuffer1[64]; + WCHAR szBuffer2[80]; pCommand = pGroup->pCommandListHead; while (pCommand != NULL) { - swprintf(szBuffer, L"%s %s", pGroup->pwszCmdGroupToken, pCommand->pwszCmdToken); - ConPrintf(StdOut, L"%-15s - ", szBuffer); - ConResPuts(StdOut, pCommand->dwShortCmdHelpToken); + swprintf(szBuffer1, L"%s %s", pGroup->pwszCmdGroupToken, pCommand->pwszCmdToken); + LoadStringW(pContext->hModule, pCommand->dwShortCmdHelpToken, szBuffer2, 80); + + ConPrintf(StdOut, L"%-15s - %s\n", szBuffer1, szBuffer2); pCommand = pCommand->pNext; } } +static +VOID +PrintLongCommand( + _In_ PCONTEXT_ENTRY pContext, + _In_ PCOMMAND_ENTRY pCommand) +{ + WCHAR szBuffer[80]; + + LoadStringW(pContext->hModule, pCommand->dwCmdHlpToken, szBuffer, 80); + ConPrintf(StdOut, szBuffer); +} + + +static +VOID +PrintContext( + _In_ PCONTEXT_ENTRY pContext) +{ + DPRINT1("PrintContext()\n"); + + if (pContext != pRootContext) + PrintContext(pContext->pParentContext); + + PrintCurrentContextHeader(pContext); + + PrintShortCommands(pContext); + + PrintShortGroups(pContext); + + PrintShortSubContexts(pContext); +} + + +static +VOID +PrintGroup( + _In_ PCONTEXT_ENTRY pContext, + _In_ LPWSTR pszGroupName, + _In_ BOOL bRecurse) +{ + PCOMMAND_GROUP pGroup; + + if (bRecurse) + { + if (pContext != pRootContext) + PrintGroup(pContext->pParentContext, pszGroupName, bRecurse); + } + + pGroup = pContext->pGroupListHead; + while (pGroup != NULL) + { + if (_wcsicmp(pszGroupName, pGroup->pwszCmdGroupToken) == 0) + { + PrintCurrentContextHeader(pContext); + PrintShortGroupCommands(pContext, pGroup); + } + pGroup = pGroup->pNext; + } +} + + +static +VOID +PrintSubcontexts( + _In_ PCONTEXT_ENTRY pContext) +{ + if (pCurrentContext->pSubContextHead != NULL) + { + ConResPrintf(StdOut, IDS_SUBCONTEXT_HEADER); + pContext = pCurrentContext->pSubContextHead; + while (pContext != NULL) + { + ConPrintf(StdOut, L" %s", pContext->pszContextName); + pContext = pContext->pNext; + } + ConPuts(StdOut, L"\n"); + } +} + + +BOOL +ProcessHelp( + _In_ PCONTEXT_ENTRY pContext, + _In_ DWORD dwArgCount, + _In_ LPWSTR *argv, + _In_ DWORD dwCurrentIndex, + _In_ DWORD dwHelpLevel) +{ + PCONTEXT_ENTRY pSubContext; + PCOMMAND_ENTRY pCommand; + PCOMMAND_GROUP pGroup; + + DPRINT("ProcessHelp(dwCurrentIndex %lu dwArgCount %lu dwHelpLevel %lu)\n", dwCurrentIndex, dwArgCount, dwHelpLevel); + + if (dwHelpLevel == dwCurrentIndex) + { + ConResPrintf(StdOut, IDS_HELP_HEADER); + PrintContext(pContext); + PrintSubcontexts(pContext); + ConResPrintf(StdOut, IDS_HELP_FOOTER); + return TRUE; + } + + pCommand = pContext->pCommandListHead; + while (pCommand != NULL) + { + if (_wcsicmp(argv[dwCurrentIndex], pCommand->pwszCmdToken) == 0) + { + if (dwHelpLevel == dwCurrentIndex + 1) + { + PrintLongCommand(pContext, pCommand); + return TRUE; + } + } + + pCommand = pCommand->pNext; + } + + pGroup = pContext->pGroupListHead; + while (pGroup != NULL) + { + if (_wcsicmp(argv[dwCurrentIndex], pGroup->pwszCmdGroupToken) == 0) + { + if (dwHelpLevel == dwCurrentIndex + 1) + { + ConResPrintf(StdOut, IDS_HELP_HEADER); + PrintGroup(pContext, argv[dwCurrentIndex], (dwHelpLevel == 1)); + return TRUE; + } + + pCommand = pGroup->pCommandListHead; + while (pCommand != NULL) + { + if ((dwArgCount > dwCurrentIndex + 1) && (_wcsicmp(argv[dwCurrentIndex + 1], pCommand->pwszCmdToken) == 0)) + { + if (dwHelpLevel == dwCurrentIndex + 2) + { + PrintLongCommand(pContext, pCommand); + return TRUE; + } + } + + pCommand = pCommand->pNext; + } + +// ConResPrintf(StdOut, IDS_HELP_HEADER); +// PrintGroup(pContext, pGroup); + return FALSE; + } + + pGroup = pGroup->pNext; + } + + if (pContext == pCurrentContext) + { + pSubContext = pContext->pSubContextHead; + while (pSubContext != NULL) + { + if (_wcsicmp(argv[dwCurrentIndex], pSubContext->pszContextName) == 0) + { + return ProcessHelp(pSubContext, + dwArgCount, + argv, + dwCurrentIndex + 1, + dwHelpLevel); + } + + pSubContext = pSubContext->pNext; + } + } + + return FALSE; +} + + DWORD WINAPI HelpCommand( @@ -122,31 +320,5 @@ HelpCommand( LPCVOID pvData, BOOL *pbDone) { - PCONTEXT_ENTRY pContext; - - ConResPrintf(StdOut, IDS_HELP_HEADER); - - pContext = pCurrentContext; - if (pContext == NULL) - { - DPRINT1("HelpCommand: invalid context %p\n", pContext); - return 1; - } - - HelpContext(pContext); - - if (pCurrentContext->pSubContextHead != NULL) - { - ConResPrintf(StdOut, IDS_SUBCONTEXT_HEADER); - pContext = pCurrentContext->pSubContextHead; - while (pContext != NULL) - { - ConPrintf(StdOut, L" %s", pContext->pszContextName); - pContext = pContext->pNext; - } - ConPuts(StdOut, L"\n"); - } - ConPuts(StdOut, L"\n"); - return ERROR_SUCCESS; } diff --git a/base/applications/network/netsh/helper.c b/base/applications/network/netsh/helper.c index 2054a647019..d452b2e807e 100644 --- a/base/applications/network/netsh/helper.c +++ b/base/applications/network/netsh/helper.c @@ -26,12 +26,12 @@ PDLL_LIST_ENTRY pCurrentDll = NULL; static VOID -StartHelpers(VOID) +StartHelpers( + PHELPER_ENTRY pHelper) { - PHELPER_ENTRY pHelper; + PHELPER_ENTRY pSubHelper; DWORD dwError; - pHelper = pHelperListHead; while (pHelper != NULL) { if (pHelper->bStarted == FALSE) @@ -44,6 +44,13 @@ StartHelpers(VOID) } } + pSubHelper = pHelper->pSubHelperHead; + while (pSubHelper != NULL) + { + StartHelpers(pSubHelper); + pSubHelper = pSubHelper->pNext; + } + pHelper = pHelper->pNext; } } @@ -310,7 +317,7 @@ done: RegCloseKey(hKey); - StartHelpers(); + StartHelpers(pHelperListHead); } @@ -336,16 +343,21 @@ UnloadHelpers(VOID) PHELPER_ENTRY FindHelper( - _In_ const GUID *pguidHelper) + _In_ const GUID *pguidHelper, + _In_ PHELPER_ENTRY pHelper) { - PHELPER_ENTRY pHelper; + PHELPER_ENTRY pFoundHelper; - pHelper = pHelperListHead; +// pHelper = pHelperListHead; while (pHelper != NULL) { if (IsEqualGUID(pguidHelper, &pHelper->Attributes.guidHelper)) return pHelper; + pFoundHelper = FindHelper(pguidHelper, pHelper->pSubHelperHead); + if (pFoundHelper) + return pFoundHelper; + pHelper = pHelper->pNext; } @@ -364,7 +376,7 @@ RegisterHelper( DPRINT("RegisterHelper(%p %p)\n", pguidParentHelper, pHelperAttributes); - if (FindHelper(&pHelperAttributes->guidHelper) != NULL) + if (FindHelper(&pHelperAttributes->guidHelper, pHelperListHead) != NULL) { DPRINT1("The Helper has already been registered!\n"); return 1; @@ -397,9 +409,12 @@ RegisterHelper( } else { - pParentHelper = FindHelper(&pHelperAttributes->guidHelper); + pParentHelper = FindHelper(pguidParentHelper, pHelperListHead); if (pParentHelper == NULL) + { + DPRINT("Parent helper not found!\n"); return ERROR_INVALID_PARAMETER; + } if (pParentHelper->pSubHelperHead == NULL && pParentHelper->pSubHelperTail == NULL) { @@ -446,7 +461,7 @@ AddHelperCommand( if (dwError != ERROR_SUCCESS) return dwError; - StartHelpers(); + StartHelpers(pHelperListHead); return ERROR_SUCCESS; } @@ -528,13 +543,15 @@ PrintSubContext( WCHAR szPrefix[22]; DWORD i; + DPRINT("PrintSubContext(%p %lu)\n", pParentContext, dwLevel); + if (pParentContext == NULL) return; pContext = pParentContext->pSubContextHead; while (pContext != NULL) { - pHelper = FindHelper(&pContext->Guid); + pHelper = FindHelper(&pContext->Guid, pHelperListHead); if (pHelper != NULL) { if (dwLevel > 10) @@ -542,7 +559,9 @@ PrintSubContext( for (i = 0; i < dwLevel * 2; i++) szPrefix[i] = L' '; - szPrefix[i] = UNICODE_NULL; + szPrefix[dwLevel * 2] = UNICODE_NULL; + + DPRINT("Level %lu \"%S\" %S\n", dwLevel, szPrefix, pContext->pszContextName); ConPrintf(StdOut, L"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X} %-16s %s%s\n", pHelper->Attributes.guidHelper.Data1, diff --git a/base/applications/network/netsh/interpreter.c b/base/applications/network/netsh/interpreter.c index 79c166432a3..4561c29e2d3 100644 --- a/base/applications/network/netsh/interpreter.c +++ b/base/applications/network/netsh/interpreter.c @@ -15,15 +15,17 @@ /* FUNCTIONS *****************************************************************/ BOOL -InterpretCommand( +ProcessCommand( + _In_ PCONTEXT_ENTRY pContext, + _In_ DWORD dwArgCount, _In_ LPWSTR *argv, - _In_ DWORD dwArgCount) + _In_ DWORD dwCurrentIndex, + _In_ DWORD dwHelpLevel, + _Inout_ PBOOL bDone) { - PCONTEXT_ENTRY pContext, pSubContext; + PCONTEXT_ENTRY pSubContext; PCOMMAND_ENTRY pCommand; PCOMMAND_GROUP pGroup; - BOOL bDone = FALSE; - DWORD dwHelpLevel = 0; DWORD dwError = ERROR_SUCCESS; /* If no args provided */ @@ -51,21 +53,13 @@ InterpretCommand( { if (_wcsicmp(argv[0], pCommand->pwszCmdToken) == 0) { - if (dwHelpLevel == 1) + dwError = pCommand->pfnCmdHandler(NULL, argv, dwCurrentIndex, dwArgCount, 0, NULL, bDone); + if (dwError != ERROR_SUCCESS) { + ConPrintf(StdOut, L"Error: %lu\n\n", dwError); ConResPrintf(StdOut, pCommand->dwCmdHlpToken); - return TRUE; - } - else - { - dwError = pCommand->pfnCmdHandler(NULL, argv, 0, dwArgCount, 0, NULL, &bDone); - if (dwError != ERROR_SUCCESS) - { - ConPrintf(StdOut, L"Error: %lu\n\n"); - ConResPrintf(StdOut, pCommand->dwCmdHlpToken); - } - return !bDone; } + return TRUE; } pCommand = pCommand->pNext; @@ -76,40 +70,33 @@ InterpretCommand( { if (_wcsicmp(argv[0], pGroup->pwszCmdGroupToken) == 0) { - if (dwHelpLevel == 1) + if (dwArgCount == 1) { - HelpGroup(pGroup); + ProcessHelp(pContext, dwArgCount, argv, dwCurrentIndex, dwHelpLevel + 1); return TRUE; } - - pCommand = pGroup->pCommandListHead; - while (pCommand != NULL) + else { - if ((dwArgCount > 1) && (_wcsicmp(argv[1], pCommand->pwszCmdToken) == 0)) + pCommand = pGroup->pCommandListHead; + while (pCommand != NULL) { - if (dwHelpLevel == 2) + if ((dwArgCount > 1) && (_wcsicmp(argv[1], pCommand->pwszCmdToken) == 0)) +// if ((dwArgCount > dwCurrentIndex + 1) && (wcsicmp(argv[dwCurrentIndex + 1], pCommand->pwszCmdToken) == 0)) { - ConResPrintf(StdOut, pCommand->dwCmdHlpToken); - return TRUE; - } - else - { - dwError = pCommand->pfnCmdHandler(NULL, argv, 1, dwArgCount, 0, NULL, &bDone); + dwError = pCommand->pfnCmdHandler(NULL, argv, dwCurrentIndex + 1, dwArgCount, 0, NULL, bDone); if (dwError != ERROR_SUCCESS) { - ConPrintf(StdOut, L"Error: %lu\n\n"); + ConPrintf(StdOut, L"Error: %lu\n\n", dwError); ConResPrintf(StdOut, pCommand->dwCmdHlpToken); - return TRUE; } - return !bDone; + return TRUE; } + + pCommand = pCommand->pNext; } - pCommand = pCommand->pNext; + return FALSE; } - - HelpGroup(pGroup); - return TRUE; } pGroup = pGroup->pNext; @@ -122,8 +109,21 @@ InterpretCommand( { if (_wcsicmp(argv[0], pSubContext->pszContextName) == 0) { - pCurrentContext = pSubContext; - return TRUE; + DPRINT("%S ==> dwCurrentIndex: %lu dwArgCount: %lu\n", argv[dwCurrentIndex], dwCurrentIndex, dwArgCount); + if (dwArgCount == dwCurrentIndex + 1) + { + pCurrentContext = pSubContext; + return TRUE; + } + else + { + return ProcessCommand(pSubContext, + dwArgCount, + argv, + dwCurrentIndex + 1, + dwHelpLevel, + bDone); + } } pSubContext = pSubContext->pNext; @@ -136,9 +136,44 @@ InterpretCommand( pContext = pContext->pParentContext; } - ConResPrintf(StdErr, IDS_INVALID_COMMAND, argv[0]); + return FALSE; +} - return TRUE; + +BOOL +InterpretCommand( + _In_ LPWSTR *argv, + _In_ DWORD dwArgCount, + _Inout_ PBOOL bDone) +{ + /* If no args provided */ + if (dwArgCount == 0) + return TRUE; + + if (pCurrentContext == NULL) + { + DPRINT("InterpretCmd: invalid context %p\n", pCurrentContext); + return FALSE; + } + + if ((_wcsicmp(argv[dwArgCount - 1], L"?") == 0) || + (_wcsicmp(argv[dwArgCount - 1], L"help") == 0)) + { + return ProcessHelp(pCurrentContext, + dwArgCount, + argv, + 0, + dwArgCount - 1); + } + else + { + return ProcessCommand(pCurrentContext, + dwArgCount, + argv, + 0, + 0, + bDone); + } } @@ -153,6 +188,7 @@ InterpretScript( LPWSTR args_vector[MAX_ARGS_COUNT]; DWORD dwArgCount = 0; BOOL bWhiteSpace = TRUE; + BOOL bDone = FALSE; LPWSTR ptr; memset(args_vector, 0, sizeof(args_vector)); @@ -180,7 +216,7 @@ InterpretScript( } /* sends the string to find the command */ - return InterpretCommand(args_vector, dwArgCount); + return InterpretCommand(args_vector, dwArgCount, &bDone) == ERROR_SUCCESS; } @@ -191,16 +227,15 @@ InterpretInteractive(VOID) LPWSTR args_vector[MAX_ARGS_COUNT]; DWORD dwArgCount = 0; BOOL bWhiteSpace = TRUE; - BOOL bRun = TRUE; + BOOL bDone = FALSE; LPWSTR ptr; - while (bRun != FALSE) + for (;;) { dwArgCount = 0; memset(args_vector, 0, sizeof(args_vector)); /* Shown just before the input where the user places commands */ -// ConResPuts(StdOut, IDS_APP_PROMPT); ConPuts(StdOut, L"netsh"); if (pCurrentContext != pRootContext) { @@ -233,6 +268,12 @@ InterpretInteractive(VOID) } /* Send the string to find the command */ - bRun = InterpretCommand(args_vector, dwArgCount); + if (InterpretCommand(args_vector, dwArgCount, &bDone) == FALSE) + { + ConResPrintf(StdErr, IDS_INVALID_COMMAND, input_line); + } + + if (bDone) + break; } } diff --git a/base/applications/network/netsh/lang/en-US.rc b/base/applications/network/netsh/lang/en-US.rc index cb05841e99d..cd767618065 100644 --- a/base/applications/network/netsh/lang/en-US.rc +++ b/base/applications/network/netsh/lang/en-US.rc @@ -19,14 +19,20 @@ END STRINGTABLE BEGIN - IDS_HELP_HEADER "\nThe following commands are available:\n" + IDS_HELP_HEADER "\nThe following commands are available:\n" + IDS_HELP_FOOTER "\nHelp Footer\n\n" IDS_SUBCONTEXT_HEADER "\nThe following sub-contexts are available:\n" + IDS_HLP_UP "Goes up one context level." IDS_HLP_UP_EX "Syntax: ..\n\n Goes up one context level.\n\n" IDS_HLP_EXIT "Exits the program." IDS_HLP_EXIT_EX "Syntax: exit\n\n Exits the program.\n\n" IDS_HLP_HELP "Displays a list of commands." IDS_HLP_HELP_EX "Syntax: help\n\n Displays a list of commands.\n\n" + IDS_HLP_POPD "Changes to the context on the stack." + IDS_HLP_POPD_EX "Syntax: popd\n\n Changes to the context on the stack.\n\n" + IDS_HLP_PUSHD "Stores the current context on the stack." + IDS_HLP_PUSHD_EX "Syntax: pushd\n\n Stores the current context on the stack.\n\n" IDS_HLP_ADD_HELPER "Installs a helper DLL." IDS_HLP_ADD_HELPER_EX "Syntax: add helper \n\n Installs the specified helper DLL in netsh.\n\n" diff --git a/base/applications/network/netsh/netsh.c b/base/applications/network/netsh/netsh.c index 0728009d440..16656bde6ad 100644 --- a/base/applications/network/netsh/netsh.c +++ b/base/applications/network/netsh/netsh.c @@ -58,8 +58,9 @@ wmain( LPCWSTR pszFileName = NULL; int index; int result = EXIT_SUCCESS; + BOOL bDone = FALSE; - DPRINT("main()\n"); + DPRINT("wmain(%S)\n", GetCommandLineW()); /* Initialize the Console Standard Streams */ ConInitStdStreams(); @@ -93,7 +94,7 @@ wmain( } /* Run a command from the command line */ - if (InterpretCommand((LPWSTR*)&argv[index], argc - index) == FALSE) + if (InterpretCommand((LPWSTR*)&argv[index], argc - index, &bDone) != ERROR_SUCCESS) result = EXIT_FAILURE; goto done; } @@ -186,6 +187,7 @@ wmain( done: /* FIXME: Cleanup code goes here */ + CleanupContext(); UnloadHelpers(); return result; @@ -247,7 +249,7 @@ PrintMessage( va_list ap; va_start(ap, pwszFormat); - Length = ConPrintf(StdOut, pwszFormat); + Length = ConPrintfV(StdOut, pwszFormat, ap); va_end(ap); return Length; diff --git a/base/applications/network/netsh/precomp.h b/base/applications/network/netsh/precomp.h index 031b03cc767..19438251367 100644 --- a/base/applications/network/netsh/precomp.h +++ b/base/applications/network/netsh/precomp.h @@ -100,6 +100,7 @@ typedef struct _CONTEXT_ENTRY struct _CONTEXT_ENTRY *pNext; struct _CONTEXT_ENTRY *pParentContext; +// PHELPER_ENTRY pHelper; PWSTR pszContextName; GUID Guid; @@ -121,6 +122,7 @@ typedef struct _CONTEXT_ENTRY extern PCONTEXT_ENTRY pRootContext; extern PCONTEXT_ENTRY pCurrentContext; +extern PHELPER_ENTRY pHelperListHead; /* PROTOTYPES *****************************************************************/ @@ -129,8 +131,21 @@ extern PCONTEXT_ENTRY pCurrentContext; BOOL CreateRootContext(VOID); +VOID +CleanupContext(VOID); + /* help.c */ + +BOOL +ProcessHelp( + _In_ PCONTEXT_ENTRY pContext, + _In_ DWORD dwCurrentIndex, + _In_ LPWSTR *argv, + _In_ DWORD dwArgCount, + _In_ DWORD dwHelpLevel); + + DWORD WINAPI HelpCommand( @@ -142,10 +157,21 @@ HelpCommand( LPCVOID pvData, BOOL *pbDone); +#if 0 VOID HelpGroup( - PCOMMAND_GROUP pGroup); + PCONTEXT_ENTRY pContext, + LPWSTR pszGroupName, + BOOL bRecurse); +VOID +HelpContext( + PCONTEXT_ENTRY pContext); + +VOID +HelpSubcontexts( + PCONTEXT_ENTRY pContext); +#endif /* helper.c */ VOID @@ -154,6 +180,10 @@ LoadHelpers(VOID); VOID UnloadHelpers(VOID); +PHELPER_ENTRY +FindHelper( + _In_ const GUID *pguidHelper, + _In_ PHELPER_ENTRY pHelper); DWORD WINAPI @@ -192,12 +222,13 @@ ShowHelperCommand( /* interpreter.c */ BOOL InterpretScript( - LPWSTR pszFileName); + _In_ LPWSTR pszFileName); BOOL InterpretCommand( - LPWSTR *argv, - DWORD dwArgCount); + _In_ LPWSTR *argv, + _In_ DWORD dwArgCount, + _Inout_ PBOOL bDone); VOID InterpretInteractive(VOID); diff --git a/base/applications/network/netsh/resource.h b/base/applications/network/netsh/resource.h index 651a9cd60b4..64c640acfaa 100644 --- a/base/applications/network/netsh/resource.h +++ b/base/applications/network/netsh/resource.h @@ -16,7 +16,8 @@ #define IDS_INVALID_SYNTAX 104 #define IDS_HELP_HEADER 200 -#define IDS_SUBCONTEXT_HEADER 201 +#define IDS_HELP_FOOTER 201 +#define IDS_SUBCONTEXT_HEADER 202 #define IDS_HLP_EXIT 300 #define IDS_HLP_EXIT_EX 301 @@ -24,6 +25,10 @@ #define IDS_HLP_HELP_EX 303 #define IDS_HLP_UP 304 #define IDS_HLP_UP_EX 305 +#define IDS_HLP_POPD 306 +#define IDS_HLP_POPD_EX 307 +#define IDS_HLP_PUSHD 308 +#define IDS_HLP_PUSHD_EX 309 #define IDS_HLP_ADD_HELPER 310 #define IDS_HLP_ADD_HELPER_EX 311