ReactOS 0.4.17-dev-573-g8315b8c
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 if (((pCommand->dwFlags & CMD_FLAG_LOCAL) && (g_pszMachine != NULL)) ||
205 ((pCommand->dwFlags & CMD_FLAG_ONLINE) && (g_bOnline == FALSE)))
206 {
207 dwError = ERROR_CMD_NOT_FOUND;
209 break;
210 }
211
212 /* Check for help keywords */
213 if (((dwArgIndex + 1) == (dwArgCount - 1)) &&
214 ((_wcsicmp(argv[dwArgIndex + 1], L"?") == 0) || (_wcsicmp(argv[dwArgIndex + 1], L"help") == 0)))
215 {
216 PrintCommandHelp(pTempContext, pGroup, pCommand);
218 break;
219 }
220
221 if (pCommand->pfnCmdHandler != NULL)
222 {
223 dwArgIndex++;
224 dwError = pCommand->pfnCmdHandler(g_pszMachine, argv, dwArgIndex, dwArgCount, 0, NULL, bDone);
225 if (dwError != ERROR_SUCCESS)
226 {
227 if (dwError == ERROR_SHOW_USAGE)
228 {
229 PrintCommandHelp(pTempContext, pGroup, pCommand);
230 dwError = ERROR_SUPPRESS_OUTPUT;
231 }
232 }
233 else
234 {
235 /* Execute the commands following a pushd command */
236 if ((_wcsicmp(pCommand->pwszCmdToken, L"pushd") == 0) &&
237 (dwArgIndex < dwArgCount))
238 {
240 break;
241 }
242 }
243 }
244
246 break;
247
248 case STATE_GROUP:
249 DPRINT("STATE_GROUP\n");
250
251 if (!CheckOsVersion(pGroup->pfnOsVersionCheck))
252 {
253 DPRINT("Group: Version check failed!\n");
254 dwError = ERROR_CMD_NOT_FOUND;
256 break;
257 }
258
259 if (((pGroup->dwFlags & CMD_FLAG_LOCAL) && (g_pszMachine != NULL)) ||
260 ((pGroup->dwFlags & CMD_FLAG_ONLINE) && (g_bOnline == FALSE)))
261 {
262 dwError = ERROR_CMD_NOT_FOUND;
264 break;
265 }
266
267 /* Check for group without command */
268 if (dwArgIndex == (dwArgCount - 1))
269 {
270 PrintGroupHelp(pTempContext, pGroup->pwszCmdGroupToken, TRUE);
272 break;
273 }
274
275 /* Check for help keywords */
276 if (((dwArgIndex + 1) <= (dwArgCount - 1)) &&
277 ((_wcsicmp(argv[dwArgIndex + 1], L"?") == 0) || (_wcsicmp(argv[dwArgIndex + 1], L"help") == 0)))
278 {
279 PrintGroupHelp(pTempContext, pGroup->pwszCmdGroupToken, TRUE);
281 break;
282 }
283
284 dwArgIndex++;
285 pCommand = GetGroupCommand(argv[dwArgIndex], pGroup);
286 if (pCommand != NULL)
287 {
289 break;
290 }
291
292 dwError = ERROR_CMD_NOT_FOUND;
294 break;
295
296 case STATE_CONTEXT:
297 DPRINT("STATE_CONTEXT\n");
298
299 if (!CheckOsVersion(pTempSubContext->pfnOsVersionCheck))
300 {
301 DPRINT("Context: Version check failed!\n");
302 dwError = ERROR_CMD_NOT_FOUND;
304 break;
305 }
306
307 if (((pTempSubContext->dwFlags & CMD_FLAG_LOCAL) && (g_pszMachine != NULL)) ||
308 ((pTempSubContext->dwFlags & CMD_FLAG_ONLINE) && (g_bOnline == FALSE)))
309 {
310 dwError = ERROR_CMD_NOT_FOUND;
312 break;
313 }
314
315 if (pTempSubContext == pCurrentContext)
316 {
317 if (dwArgIndex != (dwArgCount - 1))
318 dwError = ERROR_CMD_NOT_FOUND;
319
321 break;
322 }
323
324 if (dwArgIndex == (dwArgCount - 1))
325 {
326 DPRINT("Set current context\n");
327 pCurrentContext = pTempSubContext;
331 break;
332 }
333
334 /* Check for help keywords */
335 if (((dwArgIndex + 1) <= (dwArgCount - 1)) &&
336 ((_wcsicmp(argv[dwArgIndex + 1], L"?") == 0) || (_wcsicmp(argv[dwArgIndex + 1], L"help") == 0)))
337 {
338 PrintContextHelp(pTempSubContext);
340 break;
341 }
342
343 DPRINT("Change temorary context\n");
344 pTempContext = pTempSubContext;
346 dwArgIndex++;
347 break;
348
350 DPRINT("STATE_PARENT_CONTEXT\n");
351
352 if (pTempContext->pParentContext == NULL)
353 {
354 dwError = ERROR_CMD_NOT_FOUND;
356 break;
357 }
358
359 DPRINT("Change temorary context\n");
360 pTempContext = pTempContext->pParentContext;
362 dwArgIndex = 0;
363 break;
364
365 case STATE_DONE:
366 DPRINT("STATE_DONE dwError %ld\n", dwError);
367 return dwError;
368 }
369 }
370
371 /* Done */
372 return ERROR_SUCCESS;
373}
374
375
376/*
377 * InterpretScript(char *line):
378 * The main function used for when reading commands from scripts.
379 */
380DWORD
382 _In_ LPWSTR pszInputLine)
383{
384 LPWSTR args_vector[MAX_ARGS_COUNT];
385 DWORD dwArgCount = 0, i, len;
386 BOOL bWhiteSpace = TRUE;
387 BOOL bDone = FALSE;
388 BOOL bInQuotes = FALSE;
389 LPWSTR ptr, pStartQuote, pEndQuote;
390
391 memset(args_vector, 0, sizeof(args_vector));
392
393 ptr = pszInputLine;
394 while (*ptr != 0)
395 {
396 if (*ptr == L'\"')
397 bInQuotes = (bInQuotes) ? FALSE : TRUE;
398
399 if ((iswspace(*ptr) && (bInQuotes == FALSE)) || *ptr == L'\n')
400 {
401 *ptr = 0;
402 bWhiteSpace = TRUE;
403 }
404 else
405 {
406 if ((bWhiteSpace != FALSE) && (dwArgCount < MAX_ARGS_COUNT))
407 {
408 args_vector[dwArgCount] = ptr;
409 dwArgCount++;
410 }
411
412 bWhiteSpace = FALSE;
413 }
414
415 ptr++;
416 }
417
418 /* Remove quotation marks */
419 for (i = 0; i < dwArgCount; i++)
420 {
421 pStartQuote = wcschr(args_vector[i], L'\"');
422 if (pStartQuote)
423 {
424 pEndQuote = wcschr(pStartQuote + 1, L'\"');
425 if (pEndQuote)
426 {
427 len = pEndQuote - pStartQuote;
428 memmove(pStartQuote, pStartQuote + 1, (len - 1) * sizeof(WCHAR));
429 *(pEndQuote - 1) = UNICODE_NULL;
430 }
431 }
432 }
433
434 return InterpretCommand(args_vector, dwArgCount, &bDone);
435}
436
437
438VOID
440 _In_ PCONTEXT_ENTRY pContext)
441{
442 if (pContext != pRootContext)
443 {
444 PrintPrompt(pContext->pParentContext);
445 ConPuts(StdOut, L" ");
446 }
447
448 ConPuts(StdOut, pContext->pszContextName);
449}
450
451
452VOID
454{
455 WCHAR input_line[MAX_STRING_SIZE];
456 LPWSTR args_vector[MAX_ARGS_COUNT];
457 DWORD dwArgCount = 0, i, len;
458 BOOL bWhiteSpace = TRUE;
459 BOOL bDone = FALSE;
460 BOOL bInQuotes = FALSE;
461 LPWSTR ptr, pStartQuote, pEndQuote;
462 DWORD dwError = ERROR_SUCCESS;
463
464 for (;;)
465 {
466 dwArgCount = 0;
467 memset(args_vector, 0, sizeof(args_vector));
468
469 /* Shown just before the input where the user places commands */
470 if (g_pszMachine)
471 ConPrintf(StdOut, L"[%s] ", g_pszMachine);
473 ConPuts(StdOut, L">");
474
475 /* Get input from the user. */
476 fgetws(input_line, MAX_STRING_SIZE, stdin);
477
478 ptr = input_line;
479 while (*ptr != 0)
480 {
481 if (*ptr == L'\"')
482 bInQuotes = (bInQuotes) ? FALSE : TRUE;
483
484 if ((iswspace(*ptr) && (bInQuotes == FALSE)) || *ptr == L'\n')
485 {
486 *ptr = UNICODE_NULL;
487 bWhiteSpace = TRUE;
488 }
489 else
490 {
491 if ((bWhiteSpace != FALSE) && (dwArgCount < MAX_ARGS_COUNT))
492 {
493 args_vector[dwArgCount] = ptr;
494 dwArgCount++;
495 }
496 bWhiteSpace = FALSE;
497 }
498 ptr++;
499 }
500
501 /* Remove quotation marks */
502 for (i = 0; i < dwArgCount; i++)
503 {
504 pStartQuote = wcschr(args_vector[i], L'\"');
505 if (pStartQuote)
506 {
507 pEndQuote = wcschr(pStartQuote + 1, L'\"');
508 if (pEndQuote)
509 {
510 len = pEndQuote - pStartQuote;
511 memmove(pStartQuote, pStartQuote + 1, (len - 1) * sizeof(WCHAR));
512 *(pEndQuote - 1) = UNICODE_NULL;
513 }
514 }
515 }
516
517 dwError = InterpretCommand(args_vector, dwArgCount, &bDone);
518 if ((dwError != ERROR_SUCCESS) && (dwError != ERROR_SUPPRESS_OUTPUT))
519 {
520 PWSTR pszCommandString = MergeStrings(args_vector, dwArgCount);
521 PrintError(NULL, dwError, pszCommandString);
522 HeapFree(GetProcessHeap(), 0, pszCommandString);
523 }
524 if (dwError != ERROR_SUPPRESS_OUTPUT)
525 ConPuts(StdOut, L"\n");
526
527 if (bDone)
528 break;
529 }
530}
BOOL g_bOnline
Definition: context.c:33
PCONTEXT_ENTRY pRootContext
Definition: context.c:26
PCONTEXT_ENTRY pCurrentContext
Definition: context.c:27
PWSTR g_pszMachine
Definition: context.c:32
VOID PrintCommandHelp(_In_ PCONTEXT_ENTRY pContext, _In_ PCOMMAND_GROUP pGroup, _In_ PCOMMAND_ENTRY pCommand)
Definition: help.c:337
VOID PrintGroupHelp(_In_ PCONTEXT_ENTRY pContext, _In_ LPWSTR pszGroupName, _In_ BOOL bRecurse)
Definition: help.c:385
VOID PrintContextHelp(_In_ PCONTEXT_ENTRY pContext)
Definition: help.c:412
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:381
VOID InterpretInteractive(VOID)
Definition: interpreter.c:453
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:439
#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
@ CMD_FLAG_ONLINE
Definition: netsh.h:45
@ CMD_FLAG_LOCAL
Definition: netsh.h:44
_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
DWORD dwFlags
Definition: precomp.h:82
struct _COMMAND_ENTRY * pNext
Definition: precomp.h:76
PCOMMAND_ENTRY pCommandListHead
Definition: precomp.h:96
PNS_OSVERSIONCHECK pfnOsVersionCheck
Definition: precomp.h:94
DWORD dwFlags
Definition: precomp.h:93
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:115
PWSTR pszContextName
Definition: precomp.h:108
struct _CONTEXT_ENTRY * pSubContextHead
Definition: precomp.h:124
struct _CONTEXT_ENTRY * pParentContext
Definition: precomp.h:105
struct _CONTEXT_ENTRY * pNext
Definition: precomp.h:103
PCOMMAND_GROUP pGroupListHead
Definition: precomp.h:121
PNS_OSVERSIONCHECK pfnOsVersionCheck
Definition: precomp.h:116
DWORD dwFlags
Definition: precomp.h:112
PCOMMAND_ENTRY pCommandListHead
Definition: precomp.h:118
uint16_t * PWSTR
Definition: typedefs.h:56
uint16_t * LPWSTR
Definition: typedefs.h:56