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