ReactOS 0.4.17-dev-243-g1369312
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 /* Check for help keywords */
197 if (((dwArgIndex + 1) == (dwArgCount - 1)) &&
198 ((_wcsicmp(argv[dwArgIndex + 1], L"?") == 0) || (_wcsicmp(argv[dwArgIndex + 1], L"help") == 0)))
199 {
200 PrintCommandHelp(pTempContext, pGroup, pCommand);
202 break;
203 }
204
205 if (pCommand->pfnCmdHandler != NULL)
206 {
207 dwArgIndex++;
208 dwError = pCommand->pfnCmdHandler(pszMachine, argv, dwArgIndex, dwArgCount, 0, NULL, bDone);
209 if (dwError != ERROR_SUCCESS)
210 {
211 if (dwError == ERROR_SHOW_USAGE)
212 {
213 PrintCommandHelp(pTempContext, pGroup, pCommand);
214 dwError = ERROR_SUPPRESS_OUTPUT;
215 }
216 }
217 else
218 {
219 /* Execute the commands following a pushd command */
220 if ((_wcsicmp(pCommand->pwszCmdToken, L"pushd") == 0) &&
221 (dwArgIndex < dwArgCount))
222 {
224 break;
225 }
226 }
227 }
228
230 break;
231
232 case STATE_GROUP:
233 DPRINT("STATE_GROUP\n");
234
235 /* Check for group without command */
236 if (dwArgIndex == (dwArgCount - 1))
237 {
238 PrintGroupHelp(pTempContext, pGroup->pwszCmdGroupToken, TRUE);
240 break;
241 }
242
243 /* Check for help keywords */
244 if (((dwArgIndex + 1) <= (dwArgCount - 1)) &&
245 ((_wcsicmp(argv[dwArgIndex + 1], L"?") == 0) || (_wcsicmp(argv[dwArgIndex + 1], L"help") == 0)))
246 {
247 PrintGroupHelp(pTempContext, pGroup->pwszCmdGroupToken, TRUE);
249 break;
250 }
251
252 dwArgIndex++;
253 pCommand = GetGroupCommand(argv[dwArgIndex], pGroup);
254 if (pCommand != NULL)
255 {
257 break;
258 }
259
260 dwError = ERROR_CMD_NOT_FOUND;
262 break;
263
264 case STATE_CONTEXT:
265 DPRINT("STATE_CONTEXT\n");
266
267 if (pTempSubContext == pCurrentContext)
268 {
269 if (dwArgIndex != (dwArgCount - 1))
270 dwError = ERROR_CMD_NOT_FOUND;
271
273 break;
274 }
275
276 if (dwArgIndex == (dwArgCount - 1))
277 {
278 DPRINT("Set current context\n");
279 pCurrentContext = pTempSubContext;
283 break;
284 }
285
286 /* Check for help keywords */
287 if (((dwArgIndex + 1) <= (dwArgCount - 1)) &&
288 ((_wcsicmp(argv[dwArgIndex + 1], L"?") == 0) || (_wcsicmp(argv[dwArgIndex + 1], L"help") == 0)))
289 {
290 PrintContextHelp(pTempSubContext);
292 break;
293 }
294
295 DPRINT("Change temorary context\n");
296 pTempContext = pTempSubContext;
298 dwArgIndex++;
299 break;
300
302 DPRINT("STATE_PARENT_CONTEXT\n");
303
304 if (pTempContext->pParentContext == NULL)
305 {
306 dwError = ERROR_CMD_NOT_FOUND;
308 break;
309 }
310
311 DPRINT("Change temorary context\n");
312 pTempContext = pTempContext->pParentContext;
314 dwArgIndex = 0;
315 break;
316
317 case STATE_DONE:
318 DPRINT("STATE_DONE dwError %ld\n", dwError);
319 return dwError;
320 }
321 }
322
323 /* Done */
324 return ERROR_SUCCESS;
325}
326
327
328/*
329 * InterpretScript(char *line):
330 * The main function used for when reading commands from scripts.
331 */
332DWORD
334 _In_ LPWSTR pszInputLine)
335{
336 LPWSTR args_vector[MAX_ARGS_COUNT];
337 DWORD dwArgCount = 0, i, len;
338 BOOL bWhiteSpace = TRUE;
339 BOOL bDone = FALSE;
340 BOOL bInQuotes = FALSE;
341 LPWSTR ptr, pStartQuote, pEndQuote;
342
343 memset(args_vector, 0, sizeof(args_vector));
344
345 ptr = pszInputLine;
346 while (*ptr != 0)
347 {
348 if (*ptr == L'\"')
349 bInQuotes = (bInQuotes) ? FALSE : TRUE;
350
351 if ((iswspace(*ptr) && (bInQuotes == FALSE)) || *ptr == L'\n')
352 {
353 *ptr = 0;
354 bWhiteSpace = TRUE;
355 }
356 else
357 {
358 if ((bWhiteSpace != FALSE) && (dwArgCount < MAX_ARGS_COUNT))
359 {
360 args_vector[dwArgCount] = ptr;
361 dwArgCount++;
362 }
363
364 bWhiteSpace = FALSE;
365 }
366
367 ptr++;
368 }
369
370 /* Remove quotation marks */
371 for (i = 0; i < dwArgCount; i++)
372 {
373 pStartQuote = wcschr(args_vector[i], L'\"');
374 if (pStartQuote)
375 {
376 pEndQuote = wcschr(pStartQuote + 1, L'\"');
377 if (pEndQuote)
378 {
379 len = pEndQuote - pStartQuote;
380 memmove(pStartQuote, pStartQuote + 1, (len - 1) * sizeof(WCHAR));
381 *(pEndQuote - 1) = UNICODE_NULL;
382 }
383 }
384 }
385
386 return InterpretCommand(args_vector, dwArgCount, &bDone);
387}
388
389
390VOID
392 _In_ PCONTEXT_ENTRY pContext)
393{
394 if (pContext != pRootContext)
395 {
396 PrintPrompt(pContext->pParentContext);
397 ConPuts(StdOut, L" ");
398 }
399
400 ConPuts(StdOut, pContext->pszContextName);
401}
402
403
404VOID
406{
407 WCHAR input_line[MAX_STRING_SIZE];
408 LPWSTR args_vector[MAX_ARGS_COUNT];
409 DWORD dwArgCount = 0, i, len;
410 BOOL bWhiteSpace = TRUE;
411 BOOL bDone = FALSE;
412 BOOL bInQuotes = FALSE;
413 LPWSTR ptr, pStartQuote, pEndQuote;
414 DWORD dwError = ERROR_SUCCESS;
415
416 for (;;)
417 {
418 dwArgCount = 0;
419 memset(args_vector, 0, sizeof(args_vector));
420
421 /* Shown just before the input where the user places commands */
422 if (pszMachine)
423 ConPrintf(StdOut, L"[%s] ", pszMachine);
425 ConPuts(StdOut, L">");
426
427 /* Get input from the user. */
428 fgetws(input_line, MAX_STRING_SIZE, stdin);
429
430 ptr = input_line;
431 while (*ptr != 0)
432 {
433 if (*ptr == L'\"')
434 bInQuotes = (bInQuotes) ? FALSE : TRUE;
435
436 if ((iswspace(*ptr) && (bInQuotes == FALSE)) || *ptr == L'\n')
437 {
438 *ptr = UNICODE_NULL;
439 bWhiteSpace = TRUE;
440 }
441 else
442 {
443 if ((bWhiteSpace != FALSE) && (dwArgCount < MAX_ARGS_COUNT))
444 {
445 args_vector[dwArgCount] = ptr;
446 dwArgCount++;
447 }
448 bWhiteSpace = FALSE;
449 }
450 ptr++;
451 }
452
453 /* Remove quotation marks */
454 for (i = 0; i < dwArgCount; i++)
455 {
456 pStartQuote = wcschr(args_vector[i], L'\"');
457 if (pStartQuote)
458 {
459 pEndQuote = wcschr(pStartQuote + 1, L'\"');
460 if (pEndQuote)
461 {
462 len = pEndQuote - pStartQuote;
463 memmove(pStartQuote, pStartQuote + 1, (len - 1) * sizeof(WCHAR));
464 *(pEndQuote - 1) = UNICODE_NULL;
465 }
466 }
467 }
468
469 dwError = InterpretCommand(args_vector, dwArgCount, &bDone);
470 if ((dwError != ERROR_SUCCESS) && (dwError != ERROR_SUPPRESS_OUTPUT))
471 {
472 PWSTR pszCommandString = MergeStrings(args_vector, dwArgCount);
473 PrintError(NULL, dwError, pszCommandString);
474 HeapFree(GetProcessHeap(), 0, pszCommandString);
475 }
476 if (dwError != ERROR_SUPPRESS_OUTPUT)
477 ConPuts(StdOut, L"\n");
478
479 if (bDone)
480 break;
481 }
482}
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:277
VOID PrintGroupHelp(_In_ PCONTEXT_ENTRY pContext, _In_ LPWSTR pszGroupName, _In_ BOOL bRecurse)
Definition: help.c:314
VOID PrintContextHelp(_In_ PCONTEXT_ENTRY pContext)
Definition: help.c:341
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:333
VOID InterpretInteractive(VOID)
Definition: interpreter.c:405
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:391
#define MAX_STRING_SIZE
Definition: precomp.h:36
#define MAX_ARGS_COUNT
Definition: precomp.h:37
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:159
#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:427
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
struct _COMMAND_ENTRY * pNext
Definition: precomp.h:76
PCOMMAND_ENTRY pCommandListHead
Definition: precomp.h:94
struct _COMMAND_GROUP * pNext
Definition: precomp.h:88
PWSTR pwszCmdGroupToken
Definition: precomp.h:90
Definition: precomp.h:99
PNS_CONTEXT_CONNECT_FN pfnConnectFn
Definition: precomp.h:112
PWSTR pszContextName
Definition: precomp.h:106
struct _CONTEXT_ENTRY * pSubContextHead
Definition: precomp.h:120
struct _CONTEXT_ENTRY * pParentContext
Definition: precomp.h:103
struct _CONTEXT_ENTRY * pNext
Definition: precomp.h:101
PCOMMAND_GROUP pGroupListHead
Definition: precomp.h:117
PCOMMAND_ENTRY pCommandListHead
Definition: precomp.h:114
uint16_t * PWSTR
Definition: typedefs.h:56
uint16_t * LPWSTR
Definition: typedefs.h:56