ReactOS 0.4.17-dev-470-gf9e3448
interpreter.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS NetSh
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Network Shell command interpreter
5 * COPYRIGHT: Copyright 2023 Eric Kohl <eric.kohl@reactos.org>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include "precomp.h"
11
12#define NDEBUG
13#include <debug.h>
14
16{
24
25
26/* FUNCTIONS *****************************************************************/
27
28static
31 PWSTR pszCommand,
32 PCOMMAND_GROUP pGroup)
33{
34 PCOMMAND_ENTRY pCommand;
35
36 DPRINT("GetGroupCommand(%S %p)\n", pszCommand, pGroup);
37
38 if (pszCommand == NULL)
39 return NULL;
40
41 pCommand = pGroup->pCommandListHead;
42 while (pCommand)
43 {
44 if (MatchToken(pszCommand, pCommand->pwszCmdToken))
45 return pCommand;
46
47 pCommand = pCommand->pNext;
48 }
49
50 return NULL;
51}
52
53
54static
57 PWSTR pszCommand,
58 PCONTEXT_ENTRY pContext)
59{
60 PCOMMAND_ENTRY pCommand;
61
62 DPRINT("GetContextCommand(%S %p)\n", pszCommand, pContext);
63
64 if (pszCommand == NULL)
65 return NULL;
66
67 pCommand = pContext->pCommandListHead;
68 while (pCommand)
69 {
70 if (MatchToken(pszCommand, pCommand->pwszCmdToken))
71 return pCommand;
72
73 pCommand = pCommand->pNext;
74 }
75
76 return NULL;
77}
78
79
80static
83 PWSTR pszGroup,
84 PCONTEXT_ENTRY pContext)
85{
86 PCOMMAND_GROUP pGroup;
87
88 DPRINT("GetContextGroup(%S %p)\n", pszGroup, pContext);
89
90 if (pszGroup == NULL)
91 return NULL;
92
93 pGroup = pContext->pGroupListHead;
94 while (pGroup)
95 {
96 if (MatchToken(pszGroup, pGroup->pwszCmdGroupToken))
97 return pGroup;
98
99 pGroup = pGroup->pNext;
100 }
101
102 return NULL;
103}
104
105
106static
109 PWSTR pszContext,
110 PCONTEXT_ENTRY pContext)
111{
112 PCONTEXT_ENTRY pSubContext;
113
114 DPRINT("GetContextSubContext(%S %p)\n", pszContext, pContext);
115
116 if (pszContext == NULL)
117 return NULL;
118
119 pSubContext = pContext->pSubContextHead;
120 while (pSubContext)
121 {
122 if (MatchToken(pszContext, pSubContext->pszContextName))
123 return pSubContext;
124
125 pSubContext = pSubContext->pNext;
126 }
127
128 return NULL;
129}
130
131
132static
133DWORD
137 _Inout_ PBOOL bDone)
138{
139 PCONTEXT_ENTRY pTempContext, pTempSubContext = NULL;
140 PCOMMAND_GROUP pGroup = NULL;
141 PCOMMAND_ENTRY pCommand = NULL;
143 DWORD dwArgIndex = 0;
144 DWORD dwError = ERROR_SUCCESS;
145
146 /* If no args provided */
147 if (dwArgCount == 0)
148 return ERROR_SUCCESS;
149
150 if (pCurrentContext == NULL)
152
153 /* Check for help keywords */
154 if ((dwArgCount == 1) &&
155 ((_wcsicmp(argv[0], L"?") == 0) || (_wcsicmp(argv[0], L"help") == 0)))
156 {
158 return ERROR_SUCCESS;
159 }
160
161 pTempContext = pCurrentContext;
162 while (dwArgIndex < dwArgCount)
163 {
164 switch (State)
165 {
166 case STATE_ANALYZE:
167 DPRINT("STATE_ANALYZE\n");
168
169 pCommand = GetContextCommand(argv[dwArgIndex], pTempContext);
170 if (pCommand != NULL)
171 {
173 break;
174 }
175
176 pGroup = GetContextGroup(argv[dwArgIndex], pTempContext);
177 if (pGroup != NULL)
178 {
180 break;
181 }
182
183 pTempSubContext = GetContextSubContext(argv[dwArgIndex], pTempContext);
184 if (pTempSubContext != NULL)
185 {
187 break;
188 }
189
191 break;
192
193 case STATE_COMMAND:
194 DPRINT("STATE_COMMAND\n");
195
196 if (!CheckOsVersion(pCommand->pfnOsVersionCheck))
197 {
198 DPRINT("Command: Version check failed!\n");
199 dwError = ERROR_CMD_NOT_FOUND;
201 break;
202 }
203
204 /* Check for help keywords */
205 if (((dwArgIndex + 1) == (dwArgCount - 1)) &&
206 ((_wcsicmp(argv[dwArgIndex + 1], L"?") == 0) || (_wcsicmp(argv[dwArgIndex + 1], L"help") == 0)))
207 {
208 PrintCommandHelp(pTempContext, pGroup, pCommand);
210 break;
211 }
212
213 if (pCommand->pfnCmdHandler != NULL)
214 {
215 dwArgIndex++;
216 dwError = pCommand->pfnCmdHandler(pszMachine, argv, dwArgIndex, dwArgCount, 0, NULL, bDone);
217 if (dwError != ERROR_SUCCESS)
218 {
219 if (dwError == ERROR_SHOW_USAGE)
220 {
221 PrintCommandHelp(pTempContext, pGroup, pCommand);
222 dwError = ERROR_SUPPRESS_OUTPUT;
223 }
224 }
225 else
226 {
227 /* Execute the commands following a pushd command */
228 if ((_wcsicmp(pCommand->pwszCmdToken, L"pushd") == 0) &&
229 (dwArgIndex < dwArgCount))
230 {
232 break;
233 }
234 }
235 }
236
238 break;
239
240 case STATE_GROUP:
241 DPRINT("STATE_GROUP\n");
242
243 if (!CheckOsVersion(pGroup->pfnOsVersionCheck))
244 {
245 DPRINT("Group: Version check failed!\n");
246 dwError = ERROR_CMD_NOT_FOUND;
248 break;
249 }
250
251 /* Check for group without command */
252 if (dwArgIndex == (dwArgCount - 1))
253 {
254 PrintGroupHelp(pTempContext, pGroup->pwszCmdGroupToken, TRUE);
256 break;
257 }
258
259 /* Check for help keywords */
260 if (((dwArgIndex + 1) <= (dwArgCount - 1)) &&
261 ((_wcsicmp(argv[dwArgIndex + 1], L"?") == 0) || (_wcsicmp(argv[dwArgIndex + 1], L"help") == 0)))
262 {
263 PrintGroupHelp(pTempContext, pGroup->pwszCmdGroupToken, TRUE);
265 break;
266 }
267
268 dwArgIndex++;
269 pCommand = GetGroupCommand(argv[dwArgIndex], pGroup);
270 if (pCommand != NULL)
271 {
273 break;
274 }
275
276 dwError = ERROR_CMD_NOT_FOUND;
278 break;
279
280 case STATE_CONTEXT:
281 DPRINT("STATE_CONTEXT\n");
282
283 if (!CheckOsVersion(pTempSubContext->pfnOsVersionCheck))
284 {
285 DPRINT("Context: Version check failed!\n");
286 dwError = ERROR_CMD_NOT_FOUND;
288 break;
289 }
290
291 if (pTempSubContext == pCurrentContext)
292 {
293 if (dwArgIndex != (dwArgCount - 1))
294 dwError = ERROR_CMD_NOT_FOUND;
295
297 break;
298 }
299
300 if (dwArgIndex == (dwArgCount - 1))
301 {
302 DPRINT("Set current context\n");
303 pCurrentContext = pTempSubContext;
307 break;
308 }
309
310 /* Check for help keywords */
311 if (((dwArgIndex + 1) <= (dwArgCount - 1)) &&
312 ((_wcsicmp(argv[dwArgIndex + 1], L"?") == 0) || (_wcsicmp(argv[dwArgIndex + 1], L"help") == 0)))
313 {
314 PrintContextHelp(pTempSubContext);
316 break;
317 }
318
319 DPRINT("Change temorary context\n");
320 pTempContext = pTempSubContext;
322 dwArgIndex++;
323 break;
324
326 DPRINT("STATE_PARENT_CONTEXT\n");
327
328 if (pTempContext->pParentContext == NULL)
329 {
330 dwError = ERROR_CMD_NOT_FOUND;
332 break;
333 }
334
335 DPRINT("Change temorary context\n");
336 pTempContext = pTempContext->pParentContext;
338 dwArgIndex = 0;
339 break;
340
341 case STATE_DONE:
342 DPRINT("STATE_DONE dwError %ld\n", dwError);
343 return dwError;
344 }
345 }
346
347 /* Done */
348 return ERROR_SUCCESS;
349}
350
351
352/*
353 * InterpretScript(char *line):
354 * The main function used for when reading commands from scripts.
355 */
356DWORD
358 _In_ LPWSTR pszInputLine)
359{
360 LPWSTR args_vector[MAX_ARGS_COUNT];
361 DWORD dwArgCount = 0, i, len;
362 BOOL bWhiteSpace = TRUE;
363 BOOL bDone = FALSE;
364 BOOL bInQuotes = FALSE;
365 LPWSTR ptr, pStartQuote, pEndQuote;
366
367 memset(args_vector, 0, sizeof(args_vector));
368
369 ptr = pszInputLine;
370 while (*ptr != 0)
371 {
372 if (*ptr == L'\"')
373 bInQuotes = (bInQuotes) ? FALSE : TRUE;
374
375 if ((iswspace(*ptr) && (bInQuotes == FALSE)) || *ptr == L'\n')
376 {
377 *ptr = 0;
378 bWhiteSpace = TRUE;
379 }
380 else
381 {
382 if ((bWhiteSpace != FALSE) && (dwArgCount < MAX_ARGS_COUNT))
383 {
384 args_vector[dwArgCount] = ptr;
385 dwArgCount++;
386 }
387
388 bWhiteSpace = FALSE;
389 }
390
391 ptr++;
392 }
393
394 /* Remove quotation marks */
395 for (i = 0; i < dwArgCount; i++)
396 {
397 pStartQuote = wcschr(args_vector[i], L'\"');
398 if (pStartQuote)
399 {
400 pEndQuote = wcschr(pStartQuote + 1, L'\"');
401 if (pEndQuote)
402 {
403 len = pEndQuote - pStartQuote;
404 memmove(pStartQuote, pStartQuote + 1, (len - 1) * sizeof(WCHAR));
405 *(pEndQuote - 1) = UNICODE_NULL;
406 }
407 }
408 }
409
410 return InterpretCommand(args_vector, dwArgCount, &bDone);
411}
412
413
414VOID
416 _In_ PCONTEXT_ENTRY pContext)
417{
418 if (pContext != pRootContext)
419 {
420 PrintPrompt(pContext->pParentContext);
421 ConPuts(StdOut, L" ");
422 }
423
424 ConPuts(StdOut, pContext->pszContextName);
425}
426
427
428VOID
430{
431 WCHAR input_line[MAX_STRING_SIZE];
432 LPWSTR args_vector[MAX_ARGS_COUNT];
433 DWORD dwArgCount = 0, i, len;
434 BOOL bWhiteSpace = TRUE;
435 BOOL bDone = FALSE;
436 BOOL bInQuotes = FALSE;
437 LPWSTR ptr, pStartQuote, pEndQuote;
438 DWORD dwError = ERROR_SUCCESS;
439
440 for (;;)
441 {
442 dwArgCount = 0;
443 memset(args_vector, 0, sizeof(args_vector));
444
445 /* Shown just before the input where the user places commands */
446 if (pszMachine)
447 ConPrintf(StdOut, L"[%s] ", pszMachine);
449 ConPuts(StdOut, L">");
450
451 /* Get input from the user. */
452 fgetws(input_line, MAX_STRING_SIZE, stdin);
453
454 ptr = input_line;
455 while (*ptr != 0)
456 {
457 if (*ptr == L'\"')
458 bInQuotes = (bInQuotes) ? FALSE : TRUE;
459
460 if ((iswspace(*ptr) && (bInQuotes == FALSE)) || *ptr == L'\n')
461 {
462 *ptr = UNICODE_NULL;
463 bWhiteSpace = TRUE;
464 }
465 else
466 {
467 if ((bWhiteSpace != FALSE) && (dwArgCount < MAX_ARGS_COUNT))
468 {
469 args_vector[dwArgCount] = ptr;
470 dwArgCount++;
471 }
472 bWhiteSpace = FALSE;
473 }
474 ptr++;
475 }
476
477 /* Remove quotation marks */
478 for (i = 0; i < dwArgCount; i++)
479 {
480 pStartQuote = wcschr(args_vector[i], L'\"');
481 if (pStartQuote)
482 {
483 pEndQuote = wcschr(pStartQuote + 1, L'\"');
484 if (pEndQuote)
485 {
486 len = pEndQuote - pStartQuote;
487 memmove(pStartQuote, pStartQuote + 1, (len - 1) * sizeof(WCHAR));
488 *(pEndQuote - 1) = UNICODE_NULL;
489 }
490 }
491 }
492
493 dwError = InterpretCommand(args_vector, dwArgCount, &bDone);
494 if ((dwError != ERROR_SUCCESS) && (dwError != ERROR_SUPPRESS_OUTPUT))
495 {
496 PWSTR pszCommandString = MergeStrings(args_vector, dwArgCount);
497 PrintError(NULL, dwError, pszCommandString);
498 HeapFree(GetProcessHeap(), 0, pszCommandString);
499 }
500 if (dwError != ERROR_SUPPRESS_OUTPUT)
501 ConPuts(StdOut, L"\n");
502
503 if (bDone)
504 break;
505 }
506}
PCONTEXT_ENTRY pRootContext
Definition: context.c:26
PCONTEXT_ENTRY pCurrentContext
Definition: context.c:27
PWSTR pszMachine
Definition: context.c:32
VOID PrintCommandHelp(_In_ PCONTEXT_ENTRY pContext, _In_ PCOMMAND_GROUP pGroup, _In_ PCOMMAND_ENTRY pCommand)
Definition: help.c:296
VOID PrintGroupHelp(_In_ PCONTEXT_ENTRY pContext, _In_ LPWSTR pszGroupName, _In_ BOOL bRecurse)
Definition: help.c:339
VOID PrintContextHelp(_In_ PCONTEXT_ENTRY pContext)
Definition: help.c:366
static DWORD InterpretCommand(_In_ LPWSTR *argv, _In_ DWORD dwArgCount, _Inout_ PBOOL bDone)
Definition: interpreter.c:134
enum _INTERPRETER_STATE INTERPRETER_STATE
DWORD InterpretLine(_In_ LPWSTR pszInputLine)
Definition: interpreter.c:357
VOID InterpretInteractive(VOID)
Definition: interpreter.c:429
static PCOMMAND_GROUP GetContextGroup(PWSTR pszGroup, PCONTEXT_ENTRY pContext)
Definition: interpreter.c:82
static PCOMMAND_ENTRY GetContextCommand(PWSTR pszCommand, PCONTEXT_ENTRY pContext)
Definition: interpreter.c:56
_INTERPRETER_STATE
Definition: interpreter.c:16
@ STATE_ANALYZE
Definition: interpreter.c:17
@ STATE_CONTEXT
Definition: interpreter.c:20
@ STATE_PARENT_CONTEXT
Definition: interpreter.c:21
@ STATE_DONE
Definition: interpreter.c:22
@ STATE_GROUP
Definition: interpreter.c:19
@ STATE_COMMAND
Definition: interpreter.c:18
static PCOMMAND_ENTRY GetGroupCommand(PWSTR pszCommand, PCOMMAND_GROUP pGroup)
Definition: interpreter.c:30
static PCONTEXT_ENTRY GetContextSubContext(PWSTR pszContext, PCONTEXT_ENTRY pContext)
Definition: interpreter.c:108
VOID PrintPrompt(_In_ PCONTEXT_ENTRY pContext)
Definition: interpreter.c:415
#define MAX_STRING_SIZE
Definition: precomp.h:36
#define MAX_ARGS_COUNT
Definition: precomp.h:37
BOOL CheckOsVersion(_In_ PNS_OSVERSIONCHECK pfnOsVersionCheck)
Definition: wmi.c:35
static VOID PrintError(DWORD dwError)
Definition: cacls.c:37
void ConPuts(FILE *fp, LPCWSTR psz)
Definition: conutils_noros.h:8
void ConPrintf(FILE *fp, LPCWSTR psz,...)
#define StdOut
Definition: conutils_noros.h:6
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define wcschr
Definition: compat.h:17
#define GetProcessHeap()
Definition: compat.h:736
#define HeapFree(x, y, z)
Definition: compat.h:735
wchar_t *CDECL fgetws(wchar_t *s, int size, FILE *file)
Definition: file.c:4043
#define stdin
_ACRTIMP int __cdecl _wcsicmp(const wchar_t *, const wchar_t *)
Definition: wcs.c:164
#define L(x)
Definition: resources.c:13
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
BOOL * PBOOL
Definition: minwindef.h:137
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
static PVOID ptr
Definition: dispmode.c:27
#define argv
Definition: mplay32.c:18
BOOL WINAPI MatchToken(_In_ LPCWSTR pwszUserToken, _In_ LPCWSTR pwszCmdToken)
Definition: netsh.c:450
LPWSTR MergeStrings(_In_ LPWSTR pszStringArray[], _In_ UINT nCount)
Definition: netsh.c:53
#define ERROR_SUPPRESS_OUTPUT
Definition: netsh.h:26
#define ERROR_CMD_NOT_FOUND
Definition: netsh.h:13
_In_ LPWSTR _In_ DWORD dwArgCount
Definition: netsh.h:115
#define ERROR_SHOW_USAGE
Definition: netsh.h:22
#define _Inout_
Definition: no_sal2.h:162
#define _In_
Definition: no_sal2.h:158
#define UNICODE_NULL
short WCHAR
Definition: pedump.c:58
#define iswspace(_c)
Definition: ctype.h:669
#define memset(x, y, z)
Definition: compat.h:39
#define DPRINT
Definition: sndvol32.h:73
Definition: precomp.h:74
PWSTR pwszCmdToken
Definition: precomp.h:78
PFN_HANDLE_CMD pfnCmdHandler
Definition: precomp.h:79
PNS_OSVERSIONCHECK pfnOsVersionCheck
Definition: precomp.h:83
struct _COMMAND_ENTRY * pNext
Definition: precomp.h:76
PCOMMAND_ENTRY pCommandListHead
Definition: precomp.h:96
PNS_OSVERSIONCHECK pfnOsVersionCheck
Definition: precomp.h:94
struct _COMMAND_GROUP * pNext
Definition: precomp.h:89
PWSTR pwszCmdGroupToken
Definition: precomp.h:91
Definition: precomp.h:101
PNS_CONTEXT_CONNECT_FN pfnConnectFn
Definition: precomp.h:114
PWSTR pszContextName
Definition: precomp.h:108
struct _CONTEXT_ENTRY * pSubContextHead
Definition: precomp.h:123
struct _CONTEXT_ENTRY * pParentContext
Definition: precomp.h:105
struct _CONTEXT_ENTRY * pNext
Definition: precomp.h:103
PCOMMAND_GROUP pGroupListHead
Definition: precomp.h:120
PNS_OSVERSIONCHECK pfnOsVersionCheck
Definition: precomp.h:115
PCOMMAND_ENTRY pCommandListHead
Definition: precomp.h:117
uint16_t * PWSTR
Definition: typedefs.h:56
uint16_t * LPWSTR
Definition: typedefs.h:56