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