]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel1CommandsLib/For.c
ShellPkg/Dp: Add null pointer check
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel1CommandsLib / For.c
1 /** @file
2 Main file for endfor and for shell level 1 functions.
3
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "UefiShellLevel1CommandsLib.h"
17 #include <Library/PrintLib.h>
18
19 /**
20 Determine if a valid string is a valid number for the 'for' command.
21
22 @param[in] Number The pointer to the string representation of the number to test.
23
24 @retval TRUE The number is valid.
25 @retval FALSE The number is not valid.
26 **/
27 BOOLEAN
28 ShellIsValidForNumber (
29 IN CONST CHAR16 *Number
30 )
31 {
32 if (Number == NULL || *Number == CHAR_NULL) {
33 return (FALSE);
34 }
35
36 if (*Number == L'-') {
37 Number++;
38 }
39
40 if (StrLen(Number) == 0) {
41 return (FALSE);
42 }
43
44 if (StrLen(Number) >= 7) {
45 if ((StrStr(Number, L" ") == NULL) || (((StrStr(Number, L" ") != NULL) && (StrStr(Number, L" ") - Number) >= 7))) {
46 return (FALSE);
47 }
48 }
49
50 if (!ShellIsDecimalDigitCharacter(*Number)) {
51 return (FALSE);
52 }
53
54 return (TRUE);
55 }
56
57 /**
58 Function for 'endfor' command.
59
60 @param[in] ImageHandle Handle to the Image (NULL if Internal).
61 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
62 **/
63 SHELL_STATUS
64 EFIAPI
65 ShellCommandRunEndFor (
66 IN EFI_HANDLE ImageHandle,
67 IN EFI_SYSTEM_TABLE *SystemTable
68 )
69 {
70 EFI_STATUS Status;
71 BOOLEAN Found;
72 SCRIPT_FILE *CurrentScriptFile;
73
74 Status = CommandInit();
75 ASSERT_EFI_ERROR(Status);
76
77 if (!gEfiShellProtocol->BatchIsActive()) {
78 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"endfor");
79 return (SHELL_UNSUPPORTED);
80 }
81
82 if (gEfiShellParametersProtocol->Argc > 1) {
83 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"endfor");
84 return (SHELL_INVALID_PARAMETER);
85 }
86
87 Found = MoveToTag(GetPreviousNode, L"for", L"endfor", NULL, ShellCommandGetCurrentScriptFile(), FALSE, FALSE, FALSE);
88
89 if (!Found) {
90 CurrentScriptFile = ShellCommandGetCurrentScriptFile();
91 ShellPrintHiiEx(
92 -1,
93 -1,
94 NULL,
95 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
96 gShellLevel1HiiHandle,
97 L"For",
98 L"EndFor",
99 CurrentScriptFile!=NULL
100 && CurrentScriptFile->CurrentCommand!=NULL
101 ? CurrentScriptFile->CurrentCommand->Line:0);
102 return (SHELL_NOT_FOUND);
103 }
104 return (SHELL_SUCCESS);
105 }
106
107 typedef struct {
108 UINT32 Signature;
109 INTN Current;
110 INTN End;
111 INTN Step;
112 CHAR16 *ReplacementName;
113 CHAR16 *CurrentValue;
114 BOOLEAN RemoveSubstAlias;
115 CHAR16 Set[1];
116 } SHELL_FOR_INFO;
117 #define SIZE_OF_SHELL_FOR_INFO OFFSET_OF (SHELL_FOR_INFO, Set)
118 #define SHELL_FOR_INFO_SIGNATURE SIGNATURE_32 ('S', 'F', 'I', 's')
119
120 /**
121 Update the value of a given alias on the list. If the alias is not there then add it.
122
123 @param[in] Alias The alias to test for.
124 @param[in] CommandString The updated command string.
125 @param[in, out] List The list to search.
126
127 @retval EFI_SUCCESS The operation was completed successfully.
128 @retval EFI_OUT_OF_RESOURCES There was not enough free memory.
129 **/
130 EFI_STATUS
131 InternalUpdateAliasOnList(
132 IN CONST CHAR16 *Alias,
133 IN CONST CHAR16 *CommandString,
134 IN OUT LIST_ENTRY *List
135 )
136 {
137 ALIAS_LIST *Node;
138 BOOLEAN Found;
139
140 //
141 // assert for NULL parameter
142 //
143 ASSERT(Alias != NULL);
144
145 //
146 // check for the Alias
147 //
148 for ( Node = (ALIAS_LIST *)GetFirstNode(List), Found = FALSE
149 ; !IsNull(List, &Node->Link)
150 ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link)
151 ){
152 ASSERT(Node->CommandString != NULL);
153 ASSERT(Node->Alias != NULL);
154 if (StrCmp(Node->Alias, Alias)==0) {
155 FreePool(Node->CommandString);
156 Node->CommandString = NULL;
157 Node->CommandString = StrnCatGrow(&Node->CommandString, NULL, CommandString, 0);
158 Found = TRUE;
159 break;
160 }
161 }
162 if (!Found) {
163 Node = AllocateZeroPool(sizeof(ALIAS_LIST));
164 if (Node == NULL) {
165 return (EFI_OUT_OF_RESOURCES);
166 }
167 ASSERT(Node->Alias == NULL);
168 Node->Alias = StrnCatGrow(&Node->Alias, NULL, Alias, 0);
169 ASSERT(Node->CommandString == NULL);
170 Node->CommandString = StrnCatGrow(&Node->CommandString, NULL, CommandString, 0);
171 InsertTailList(List, &Node->Link);
172 }
173 return (EFI_SUCCESS);
174 }
175
176 /**
177 Find out if an alias is on the given list.
178
179 @param[in] Alias The alias to test for.
180 @param[in] List The list to search.
181
182 @retval TRUE The alias is on the list.
183 @retval FALSE The alias is not on the list.
184 **/
185 BOOLEAN
186 InternalIsAliasOnList(
187 IN CONST CHAR16 *Alias,
188 IN CONST LIST_ENTRY *List
189 )
190 {
191 ALIAS_LIST *Node;
192
193 //
194 // assert for NULL parameter
195 //
196 ASSERT(Alias != NULL);
197
198 //
199 // check for the Alias
200 //
201 for ( Node = (ALIAS_LIST *)GetFirstNode(List)
202 ; !IsNull(List, &Node->Link)
203 ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link)
204 ){
205 ASSERT(Node->CommandString != NULL);
206 ASSERT(Node->Alias != NULL);
207 if (StrCmp(Node->Alias, Alias)==0) {
208 return (TRUE);
209 }
210 }
211 return (FALSE);
212 }
213
214 /**
215 Remove an alias from the given list.
216
217 @param[in] Alias The alias to remove.
218 @param[in, out] List The list to search.
219 **/
220 BOOLEAN
221 InternalRemoveAliasFromList(
222 IN CONST CHAR16 *Alias,
223 IN OUT LIST_ENTRY *List
224 )
225 {
226 ALIAS_LIST *Node;
227
228 //
229 // assert for NULL parameter
230 //
231 ASSERT(Alias != NULL);
232
233 //
234 // check for the Alias
235 //
236 for ( Node = (ALIAS_LIST *)GetFirstNode(List)
237 ; !IsNull(List, &Node->Link)
238 ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link)
239 ){
240 ASSERT(Node->CommandString != NULL);
241 ASSERT(Node->Alias != NULL);
242 if (StrCmp(Node->Alias, Alias)==0) {
243 RemoveEntryList(&Node->Link);
244 FreePool(Node->Alias);
245 FreePool(Node->CommandString);
246 FreePool(Node);
247 return (TRUE);
248 }
249 }
250 return (FALSE);
251 }
252
253 /**
254 Function to determine whether a string is decimal or hex representation of a number
255 and return the number converted from the string.
256
257 @param[in] String String representation of a number
258
259 @return the number
260 @retval (UINTN)(-1) An error ocurred.
261 **/
262 UINTN
263 ReturnUintn(
264 IN CONST CHAR16 *String
265 )
266 {
267 UINT64 RetVal;
268
269 if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, FALSE, TRUE))) {
270 return ((UINTN)RetVal);
271 }
272 return ((UINTN)(-1));
273 }
274
275 /**
276 Function for 'for' command.
277
278 @param[in] ImageHandle Handle to the Image (NULL if Internal).
279 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
280 **/
281 SHELL_STATUS
282 EFIAPI
283 ShellCommandRunFor (
284 IN EFI_HANDLE ImageHandle,
285 IN EFI_SYSTEM_TABLE *SystemTable
286 )
287 {
288 EFI_STATUS Status;
289 SHELL_STATUS ShellStatus;
290 SCRIPT_FILE *CurrentScriptFile;
291 CHAR16 *ArgSet;
292 CHAR16 *ArgSetWalker;
293 CHAR16 *Parameter;
294 UINTN ArgSize;
295 UINTN LoopVar;
296 SHELL_FOR_INFO *Info;
297 CHAR16 *TempString;
298 CHAR16 *TempSpot;
299 BOOLEAN FirstPass;
300 EFI_SHELL_FILE_INFO *Node;
301 EFI_SHELL_FILE_INFO *FileList;
302 UINTN NewSize;
303
304 ArgSet = NULL;
305 ArgSize = 0;
306 ShellStatus = SHELL_SUCCESS;
307 ArgSetWalker = NULL;
308 TempString = NULL;
309 Parameter = NULL;
310 FirstPass = FALSE;
311
312 //
313 // initialize the shell lib (we must be in non-auto-init...)
314 //
315 Status = ShellInitialize();
316 ASSERT_EFI_ERROR(Status);
317
318 Status = CommandInit();
319 ASSERT_EFI_ERROR(Status);
320
321 if (!gEfiShellProtocol->BatchIsActive()) {
322 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"for");
323 return (SHELL_UNSUPPORTED);
324 }
325
326 if (gEfiShellParametersProtocol->Argc < 4) {
327 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle, L"for");
328 return (SHELL_INVALID_PARAMETER);
329 }
330
331 CurrentScriptFile = ShellCommandGetCurrentScriptFile();
332 ASSERT(CurrentScriptFile != NULL);
333
334 if ((CurrentScriptFile->CurrentCommand != NULL) && (CurrentScriptFile->CurrentCommand->Data == NULL)) {
335 FirstPass = TRUE;
336
337 //
338 // Make sure that an End exists.
339 //
340 if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, TRUE, FALSE)) {
341 ShellPrintHiiEx(
342 -1,
343 -1,
344 NULL,
345 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
346 gShellLevel1HiiHandle,
347 L"EndFor",
348 L"For",
349 CurrentScriptFile->CurrentCommand->Line);
350 return (SHELL_DEVICE_ERROR);
351 }
352
353 //
354 // Process the line.
355 //
356 if (gEfiShellParametersProtocol->Argv[1][0] != L'%' || gEfiShellParametersProtocol->Argv[1][2] != CHAR_NULL
357 ||!((gEfiShellParametersProtocol->Argv[1][1] >= L'a' && gEfiShellParametersProtocol->Argv[1][1] <= L'z')
358 ||(gEfiShellParametersProtocol->Argv[1][1] >= L'A' && gEfiShellParametersProtocol->Argv[1][1] <= L'Z'))
359 ) {
360 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_VAR), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[1]);
361 return (SHELL_INVALID_PARAMETER);
362 }
363
364 if (gUnicodeCollation->StriColl(
365 gUnicodeCollation,
366 L"in",
367 gEfiShellParametersProtocol->Argv[2]) == 0) {
368 for (LoopVar = 0x3 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {
369 ASSERT((ArgSet == NULL && ArgSize == 0) || (ArgSet != NULL));
370 if (StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"*") != NULL
371 ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"?") != NULL
372 ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"[") != NULL
373 ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"]") != NULL) {
374 FileList = NULL;
375 Status = ShellOpenFileMetaArg ((CHAR16*)gEfiShellParametersProtocol->Argv[LoopVar], EFI_FILE_MODE_READ, &FileList);
376 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {
377 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0);
378 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, gEfiShellParametersProtocol->Argv[LoopVar], 0);
379 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0);
380 } else {
381 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
382 ; !IsNull(&FileList->Link, &Node->Link)
383 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
384 ){
385 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0);
386 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, Node->FullName, 0);
387 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0);
388 }
389 ShellCloseFileMetaArg(&FileList);
390 }
391 } else {
392 Parameter = gEfiShellParametersProtocol->Argv[LoopVar];
393 if (Parameter[0] == L'\"' && Parameter[StrLen(Parameter)-1] == L'\"') {
394 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" ", 0);
395 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, Parameter, 0);
396 } else {
397 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0);
398 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, Parameter, 0);
399 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0);
400 }
401 }
402 }
403 if (ArgSet == NULL) {
404 ShellStatus = SHELL_OUT_OF_RESOURCES;
405 } else {
406 //
407 // set up for an 'in' for loop
408 //
409 NewSize = StrSize(ArgSet);
410 NewSize += sizeof(SHELL_FOR_INFO)+StrSize(gEfiShellParametersProtocol->Argv[1]);
411 Info = AllocateZeroPool(NewSize);
412 if (Info == NULL) {
413 FreePool (ArgSet);
414 return SHELL_OUT_OF_RESOURCES;
415 }
416 Info->Signature = SHELL_FOR_INFO_SIGNATURE;
417 CopyMem(Info->Set, ArgSet, StrSize(ArgSet));
418 NewSize = StrSize(gEfiShellParametersProtocol->Argv[1]);
419 CopyMem(Info->Set+(StrSize(ArgSet)/sizeof(Info->Set[0])), gEfiShellParametersProtocol->Argv[1], NewSize);
420 Info->ReplacementName = Info->Set+StrSize(ArgSet)/sizeof(Info->Set[0]);
421 Info->CurrentValue = (CHAR16*)Info->Set;
422 Info->Step = 0;
423 Info->Current = 0;
424 Info->End = 0;
425
426 if (InternalIsAliasOnList(Info->ReplacementName, &CurrentScriptFile->SubstList)) {
427 Info->RemoveSubstAlias = FALSE;
428 } else {
429 Info->RemoveSubstAlias = TRUE;
430 }
431 CurrentScriptFile->CurrentCommand->Data = Info;
432 }
433 } else if (gUnicodeCollation->StriColl(
434 gUnicodeCollation,
435 L"run",
436 gEfiShellParametersProtocol->Argv[2]) == 0) {
437 for (LoopVar = 0x3 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {
438 ASSERT((ArgSet == NULL && ArgSize == 0) || (ArgSet != NULL));
439 if (StrStr (gEfiShellParametersProtocol->Argv[LoopVar], L")") != NULL &&
440 (LoopVar + 1) < gEfiShellParametersProtocol->Argc
441 ) {
442 return (SHELL_INVALID_PARAMETER);
443 }
444 if (ArgSet == NULL) {
445 // ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0);
446 } else {
447 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" ", 0);
448 }
449 ArgSet = StrnCatGrow(&ArgSet, &ArgSize, gEfiShellParametersProtocol->Argv[LoopVar], 0);
450 // ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" ", 0);
451 }
452 if (ArgSet == NULL) {
453 ShellStatus = SHELL_OUT_OF_RESOURCES;
454 } else {
455 //
456 // set up for a 'run' for loop
457 //
458 Info = AllocateZeroPool(sizeof(SHELL_FOR_INFO)+StrSize(gEfiShellParametersProtocol->Argv[1]));
459 if (Info == NULL) {
460 FreePool (ArgSet);
461 return SHELL_OUT_OF_RESOURCES;
462 }
463 Info->Signature = SHELL_FOR_INFO_SIGNATURE;
464 CopyMem(Info->Set, gEfiShellParametersProtocol->Argv[1], StrSize(gEfiShellParametersProtocol->Argv[1]));
465 Info->ReplacementName = Info->Set;
466 Info->CurrentValue = NULL;
467 ArgSetWalker = ArgSet;
468 if (ArgSetWalker[0] != L'(') {
469 ShellPrintHiiEx(
470 -1,
471 -1,
472 NULL,
473 STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT),
474 gShellLevel1HiiHandle,
475 ArgSet,
476 CurrentScriptFile->CurrentCommand->Line);
477 ShellStatus = SHELL_INVALID_PARAMETER;
478 } else {
479 TempSpot = StrStr(ArgSetWalker, L")");
480 if (TempSpot != NULL) {
481 TempString = TempSpot+1;
482 if (*(TempString) != CHAR_NULL) {
483 while(TempString != NULL && *TempString == L' ') {
484 TempString++;
485 }
486 if (StrLen(TempString) > 0) {
487 TempSpot = NULL;
488 }
489 }
490 }
491 if (TempSpot == NULL) {
492 ShellPrintHiiEx(
493 -1,
494 -1,
495 NULL,
496 STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT),
497 gShellLevel1HiiHandle,
498 CurrentScriptFile->CurrentCommand->Line);
499 ShellStatus = SHELL_INVALID_PARAMETER;
500 } else {
501 *TempSpot = CHAR_NULL;
502 ArgSetWalker++;
503 while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') {
504 ArgSetWalker++;
505 }
506 if (!ShellIsValidForNumber(ArgSetWalker)) {
507 ShellPrintHiiEx(
508 -1,
509 -1,
510 NULL,
511 STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT),
512 gShellLevel1HiiHandle,
513 ArgSet,
514 CurrentScriptFile->CurrentCommand->Line);
515 ShellStatus = SHELL_INVALID_PARAMETER;
516 } else {
517 if (ArgSetWalker[0] == L'-') {
518 Info->Current = 0 - (INTN)ReturnUintn(ArgSetWalker+1);
519 } else {
520 Info->Current = (INTN)ReturnUintn(ArgSetWalker);
521 }
522 ArgSetWalker = StrStr(ArgSetWalker, L" ");
523 while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') {
524 ArgSetWalker++;
525 }
526 if (ArgSetWalker == NULL || *ArgSetWalker == CHAR_NULL || !ShellIsValidForNumber(ArgSetWalker)){
527 ShellPrintHiiEx(
528 -1,
529 -1,
530 NULL,
531 STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT),
532 gShellLevel1HiiHandle,
533 ArgSet,
534 CurrentScriptFile->CurrentCommand->Line);
535 ShellStatus = SHELL_INVALID_PARAMETER;
536 } else {
537 if (ArgSetWalker[0] == L'-') {
538 Info->End = 0 - (INTN)ReturnUintn(ArgSetWalker+1);
539 } else {
540 Info->End = (INTN)ReturnUintn(ArgSetWalker);
541 }
542 if (Info->Current < Info->End) {
543 Info->Step = 1;
544 } else {
545 Info->Step = -1;
546 }
547
548 ArgSetWalker = StrStr(ArgSetWalker, L" ");
549 while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') {
550 ArgSetWalker++;
551 }
552 if (ArgSetWalker != NULL && *ArgSetWalker != CHAR_NULL) {
553 if (ArgSetWalker == NULL || *ArgSetWalker == CHAR_NULL || !ShellIsValidForNumber(ArgSetWalker)){
554 ShellPrintHiiEx(
555 -1,
556 -1,
557 NULL,
558 STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT),
559 gShellLevel1HiiHandle,
560 ArgSet,
561 CurrentScriptFile->CurrentCommand->Line);
562 ShellStatus = SHELL_INVALID_PARAMETER;
563 } else {
564 if (*ArgSetWalker == L')') {
565 ASSERT(Info->Step == 1 || Info->Step == -1);
566 } else {
567 if (ArgSetWalker[0] == L'-') {
568 Info->Step = 0 - (INTN)ReturnUintn(ArgSetWalker+1);
569 } else {
570 Info->Step = (INTN)ReturnUintn(ArgSetWalker);
571 }
572
573 if (StrStr(ArgSetWalker, L" ") != NULL) {
574 ShellPrintHiiEx(
575 -1,
576 -1,
577 NULL,
578 STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT),
579 gShellLevel1HiiHandle,
580 ArgSet,
581 CurrentScriptFile->CurrentCommand->Line);
582 ShellStatus = SHELL_INVALID_PARAMETER;
583 }
584 }
585 }
586
587 }
588 }
589 }
590 }
591 }
592 if (ShellStatus == SHELL_SUCCESS) {
593 if (InternalIsAliasOnList(Info->ReplacementName, &CurrentScriptFile->SubstList)) {
594 Info->RemoveSubstAlias = FALSE;
595 } else {
596 Info->RemoveSubstAlias = TRUE;
597 }
598 }
599 if (CurrentScriptFile->CurrentCommand != NULL) {
600 CurrentScriptFile->CurrentCommand->Data = Info;
601 }
602 }
603 } else {
604 ShellPrintHiiEx(
605 -1,
606 -1,
607 NULL,
608 STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT),
609 gShellLevel1HiiHandle,
610 ArgSet,
611 CurrentScriptFile!=NULL
612 && CurrentScriptFile->CurrentCommand!=NULL
613 ? CurrentScriptFile->CurrentCommand->Line:0);
614 ShellStatus = SHELL_INVALID_PARAMETER;
615 }
616 } else {
617 //
618 // These need to be NULL since they are used to determine if this is the first pass later on...
619 //
620 ASSERT(ArgSetWalker == NULL);
621 ASSERT(ArgSet == NULL);
622 }
623
624 if (CurrentScriptFile != NULL && CurrentScriptFile->CurrentCommand != NULL) {
625 Info = (SHELL_FOR_INFO*)CurrentScriptFile->CurrentCommand->Data;
626 if (CurrentScriptFile->CurrentCommand->Reset) {
627 if (Info != NULL) {
628 Info->CurrentValue = (CHAR16*)Info->Set;
629 }
630 FirstPass = TRUE;
631 CurrentScriptFile->CurrentCommand->Reset = FALSE;
632 }
633 } else {
634 ShellStatus = SHELL_UNSUPPORTED;
635 Info = NULL;
636 }
637 if (ShellStatus == SHELL_SUCCESS) {
638 ASSERT(Info != NULL);
639 if (Info->Step != 0) {
640 //
641 // only advance if not the first pass
642 //
643 if (!FirstPass) {
644 //
645 // sequence version of for loop...
646 //
647 Info->Current += Info->Step;
648 }
649
650 TempString = AllocateZeroPool(50*sizeof(CHAR16));
651 UnicodeSPrint(TempString, 50*sizeof(CHAR16), L"%d", Info->Current);
652 InternalUpdateAliasOnList(Info->ReplacementName, TempString, &CurrentScriptFile->SubstList);
653 FreePool(TempString);
654
655 if ((Info->Step > 0 && Info->Current > Info->End) || (Info->Step < 0 && Info->Current < Info->End)) {
656 CurrentScriptFile->CurrentCommand->Data = NULL;
657 //
658 // find the matching endfor (we're done with the loop)
659 //
660 if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, FALSE, FALSE)) {
661 ShellPrintHiiEx(
662 -1,
663 -1,
664 NULL,
665 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
666 gShellLevel1HiiHandle,
667 L"EndFor",
668 L"For",
669 CurrentScriptFile!=NULL
670 && CurrentScriptFile->CurrentCommand!=NULL
671 ? CurrentScriptFile->CurrentCommand->Line:0);
672 ShellStatus = SHELL_DEVICE_ERROR;
673 }
674 if (Info->RemoveSubstAlias) {
675 //
676 // remove item from list
677 //
678 InternalRemoveAliasFromList(Info->ReplacementName, &CurrentScriptFile->SubstList);
679 }
680 FreePool(Info);
681 }
682 } else {
683 //
684 // Must be in 'in' version of for loop...
685 //
686 ASSERT(Info->Set != NULL);
687 if (Info->CurrentValue != NULL && *Info->CurrentValue != CHAR_NULL) {
688 if (Info->CurrentValue[0] == L' ') {
689 Info->CurrentValue++;
690 }
691 if (Info->CurrentValue[0] == L'\"') {
692 Info->CurrentValue++;
693 }
694 //
695 // do the next one of the set
696 //
697 ASSERT(TempString == NULL);
698 TempString = StrnCatGrow(&TempString, NULL, Info->CurrentValue, 0);
699 if (TempString == NULL) {
700 ShellStatus = SHELL_OUT_OF_RESOURCES;
701 } else {
702 TempSpot = StrStr(TempString, L"\" \"");
703 if (TempSpot != NULL) {
704 *TempSpot = CHAR_NULL;
705 }
706 while (TempString[StrLen(TempString)-1] == L'\"') {
707 TempString[StrLen(TempString)-1] = CHAR_NULL;
708 }
709 InternalUpdateAliasOnList(Info->ReplacementName, TempString, &CurrentScriptFile->SubstList);
710 Info->CurrentValue += StrLen(TempString);
711
712 if (Info->CurrentValue[0] == L'\"') {
713 Info->CurrentValue++;
714 }
715 FreePool(TempString);
716 }
717 } else {
718 CurrentScriptFile->CurrentCommand->Data = NULL;
719 //
720 // find the matching endfor (we're done with the loop)
721 //
722 if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, FALSE, FALSE)) {
723 ShellPrintHiiEx(
724 -1,
725 -1,
726 NULL,
727 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
728 gShellLevel1HiiHandle,
729 L"EndFor",
730 L"For",
731 CurrentScriptFile!=NULL
732 && CurrentScriptFile->CurrentCommand!=NULL
733 ? CurrentScriptFile->CurrentCommand->Line:0);
734 ShellStatus = SHELL_DEVICE_ERROR;
735 }
736 if (Info->RemoveSubstAlias) {
737 //
738 // remove item from list
739 //
740 InternalRemoveAliasFromList(Info->ReplacementName, &CurrentScriptFile->SubstList);
741 }
742 FreePool(Info);
743 }
744 }
745 }
746 if (ArgSet != NULL) {
747 FreePool(ArgSet);
748 }
749 return (ShellStatus);
750 }
751