]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel1CommandsLib/If.c
ShellPkg: acpiview: Add GT Frame Number validation to GTDT parser
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel1CommandsLib / If.c
1 /** @file
2 Main file for If and else shell level 1 function.
3
4 (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "UefiShellLevel1CommandsLib.h"
11 #include <Library/PrintLib.h>
12
13 typedef enum {
14 EndTagOr,
15 EndTagAnd,
16 EndTagThen,
17 EndTagMax
18 } END_TAG_TYPE;
19
20 typedef enum {
21 OperatorGreaterThan,
22 OperatorLessThan,
23 OperatorEqual,
24 OperatorNotEqual,
25 OperatorGreatorOrEqual,
26 OperatorLessOrEqual,
27 OperatorUnisgnedGreaterThan,
28 OperatorUnsignedLessThan,
29 OperatorUnsignedGreaterOrEqual,
30 OperatorUnsignedLessOrEqual,
31 OperatorMax
32 } BIN_OPERATOR_TYPE;
33
34 /**
35 Extract the next fragment, if there is one.
36
37 @param[in, out] Statement The current remaining statement.
38 @param[in] Fragment The current fragment.
39 @param[out] Match TRUE when there is another Fragment in Statement,
40 FALSE otherwise.
41
42 @retval EFI_SUCCESS The match operation is performed successfully.
43 @retval EFI_OUT_OF_RESOURCES Out of resources.
44 **/
45 EFI_STATUS
46 IsNextFragment (
47 IN OUT CONST CHAR16 **Statement,
48 IN CONST CHAR16 *Fragment,
49 OUT BOOLEAN *Match
50 )
51 {
52 CHAR16 *Tester;
53
54 Tester = NULL;
55
56 Tester = StrnCatGrow(&Tester, NULL, *Statement, StrLen(Fragment));
57 if (Tester == NULL) {
58 return EFI_OUT_OF_RESOURCES;
59 }
60 Tester[StrLen(Fragment)] = CHAR_NULL;
61 if (gUnicodeCollation->StriColl(
62 gUnicodeCollation,
63 (CHAR16*)Fragment,
64 Tester) == 0) {
65 //
66 // increment the string pointer to the end of what we found and then chop off spaces...
67 //
68 *Statement+=StrLen(Fragment);
69 while (*Statement[0] == L' ') {
70 (*Statement)++;
71 }
72 *Match = TRUE;
73 } else {
74 *Match = FALSE;
75 }
76 FreePool(Tester);
77 return EFI_SUCCESS;
78 }
79
80 /**
81 Determine if String represents a valid profile.
82
83 @param[in] String The pointer to the string to test.
84
85 @retval TRUE String is a valid profile.
86 @retval FALSE String is not a valid profile.
87 **/
88 BOOLEAN
89 IsValidProfile (
90 IN CONST CHAR16 *String
91 )
92 {
93 CONST CHAR16 *ProfilesString;
94 CONST CHAR16 *TempLocation;
95
96 ProfilesString = ShellGetEnvironmentVariable(L"profiles");
97 ASSERT(ProfilesString != NULL);
98 TempLocation = StrStr(ProfilesString, String);
99 if ((TempLocation != NULL) && (*(TempLocation-1) == L';') && (*(TempLocation+StrLen(String)) == L';')) {
100 return (TRUE);
101 }
102 return (FALSE);
103 }
104
105 /**
106 Do a comparison between 2 things.
107
108 @param[in] Compare1 The first item to compare.
109 @param[in] Compare2 The second item to compare.
110 @param[in] BinOp The type of comparison to perform.
111 @param[in] CaseInsensitive TRUE to do non-case comparison, FALSE otherwise.
112 @param[in] ForceStringCompare TRUE to force string comparison, FALSE otherwise.
113
114 @return The result of the comparison.
115 **/
116 BOOLEAN
117 TestOperation (
118 IN CONST CHAR16 *Compare1,
119 IN CONST CHAR16 *Compare2,
120 IN CONST BIN_OPERATOR_TYPE BinOp,
121 IN CONST BOOLEAN CaseInsensitive,
122 IN CONST BOOLEAN ForceStringCompare
123 )
124 {
125 INTN Cmp1;
126 INTN Cmp2;
127
128 //
129 // "Compare1 BinOp Compare2"
130 //
131 switch (BinOp) {
132 case OperatorUnisgnedGreaterThan:
133 case OperatorGreaterThan:
134 if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) {
135 //
136 // string compare
137 //
138 if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) > 0) || (StringCompare(&Compare1, &Compare2) > 0)) {
139 return (TRUE);
140 }
141 } else {
142 //
143 // numeric compare
144 //
145 if (Compare1[0] == L'-') {
146 Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1);
147 } else {
148 Cmp1 = (INTN)ShellStrToUintn(Compare1);
149 }
150 if (Compare2[0] == L'-') {
151 Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1);
152 } else {
153 Cmp2 = (INTN)ShellStrToUintn(Compare2);
154 }
155 if (BinOp == OperatorGreaterThan) {
156 if (Cmp1 > Cmp2) {
157 return (TRUE);
158 }
159 } else {
160 if ((UINTN)Cmp1 > (UINTN)Cmp2) {
161 return (TRUE);
162 }
163 }
164 }
165 return (FALSE);
166 case OperatorUnsignedLessThan:
167 case OperatorLessThan:
168 if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) {
169 //
170 // string compare
171 //
172 if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) < 0) || (StringCompare(&Compare1, &Compare2) < 0)) {
173 return (TRUE);
174 }
175 } else {
176 //
177 // numeric compare
178 //
179 if (Compare1[0] == L'-') {
180 Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1);
181 } else {
182 Cmp1 = (INTN)ShellStrToUintn(Compare1);
183 }
184 if (Compare2[0] == L'-') {
185 Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1);
186 } else {
187 Cmp2 = (INTN)ShellStrToUintn(Compare2);
188 }
189 if (BinOp == OperatorLessThan) {
190 if (Cmp1 < Cmp2) {
191 return (TRUE);
192 }
193 } else {
194 if ((UINTN)Cmp1 < (UINTN)Cmp2) {
195 return (TRUE);
196 }
197 }
198
199 }
200 return (FALSE);
201 case OperatorEqual:
202 if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) {
203 //
204 // string compare
205 //
206 if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) == 0) || (StringCompare(&Compare1, &Compare2) == 0)) {
207 return (TRUE);
208 }
209 } else {
210 //
211 // numeric compare
212 //
213 if (Compare1[0] == L'-') {
214 Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1);
215 } else {
216 Cmp1 = (INTN)ShellStrToUintn(Compare1);
217 }
218 if (Compare2[0] == L'-') {
219 Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1);
220 } else {
221 Cmp2 = (INTN)ShellStrToUintn(Compare2);
222 }
223 if (Cmp1 == Cmp2) {
224 return (TRUE);
225 }
226 }
227 return (FALSE);
228 case OperatorNotEqual:
229 if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) {
230 //
231 // string compare
232 //
233 if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) != 0) || (StringCompare(&Compare1, &Compare2) != 0)) {
234 return (TRUE);
235 }
236 } else {
237 //
238 // numeric compare
239 //
240 if (Compare1[0] == L'-') {
241 Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1);
242 } else {
243 Cmp1 = (INTN)ShellStrToUintn(Compare1);
244 }
245 if (Compare2[0] == L'-') {
246 Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1);
247 } else {
248 Cmp2 = (INTN)ShellStrToUintn(Compare2);
249 }
250 if (Cmp1 != Cmp2) {
251 return (TRUE);
252 }
253 }
254 return (FALSE);
255 case OperatorUnsignedGreaterOrEqual:
256 case OperatorGreatorOrEqual:
257 if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) {
258 //
259 // string compare
260 //
261 if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) >= 0) || (StringCompare(&Compare1, &Compare2) >= 0)) {
262 return (TRUE);
263 }
264 } else {
265 //
266 // numeric compare
267 //
268 if (Compare1[0] == L'-') {
269 Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1);
270 } else {
271 Cmp1 = (INTN)ShellStrToUintn(Compare1);
272 }
273 if (Compare2[0] == L'-') {
274 Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1);
275 } else {
276 Cmp2 = (INTN)ShellStrToUintn(Compare2);
277 }
278 if (BinOp == OperatorGreatorOrEqual) {
279 if (Cmp1 >= Cmp2) {
280 return (TRUE);
281 }
282 } else {
283 if ((UINTN)Cmp1 >= (UINTN)Cmp2) {
284 return (TRUE);
285 }
286 }
287 }
288 return (FALSE);
289 case OperatorLessOrEqual:
290 case OperatorUnsignedLessOrEqual:
291 if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) {
292 //
293 // string compare
294 //
295 if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) <= 0) || (StringCompare(&Compare1, &Compare2) <= 0)) {
296 return (TRUE);
297 }
298 } else {
299 //
300 // numeric compare
301 //
302 if (Compare1[0] == L'-') {
303 Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1);
304 } else {
305 Cmp1 = (INTN)ShellStrToUintn(Compare1);
306 }
307 if (Compare2[0] == L'-') {
308 Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1);
309 } else {
310 Cmp2 = (INTN)ShellStrToUintn(Compare2);
311 }
312 if (BinOp == OperatorLessOrEqual) {
313 if (Cmp1 <= Cmp2) {
314 return (TRUE);
315 }
316 } else {
317 if ((UINTN)Cmp1 <= (UINTN)Cmp2) {
318 return (TRUE);
319 }
320 }
321 }
322 return (FALSE);
323 default:
324 ASSERT(FALSE);
325 return (FALSE);
326 }
327 }
328
329 /**
330 Process an if statement and determine if its is valid or not.
331
332 @param[in, out] PassingState Opon entry, the current state. Upon exit,
333 the new state.
334 @param[in] StartParameterNumber The number of the first parameter of
335 this statement.
336 @param[in] EndParameterNumber The number of the final parameter of
337 this statement.
338 @param[in] OperatorToUse The type of termination operator.
339 @param[in] CaseInsensitive TRUE for case insensitive, FALSE otherwise.
340 @param[in] ForceStringCompare TRUE for all string based, FALSE otherwise.
341
342 @retval EFI_INVALID_PARAMETER A parameter was invalid.
343 @retval EFI_SUCCESS The operation was successful.
344 **/
345 EFI_STATUS
346 ProcessStatement (
347 IN OUT BOOLEAN *PassingState,
348 IN UINTN StartParameterNumber,
349 IN UINTN EndParameterNumber,
350 IN CONST END_TAG_TYPE OperatorToUse,
351 IN CONST BOOLEAN CaseInsensitive,
352 IN CONST BOOLEAN ForceStringCompare
353 )
354 {
355 EFI_STATUS Status;
356 BOOLEAN OperationResult;
357 BOOLEAN NotPresent;
358 CHAR16 *StatementWalker;
359 BIN_OPERATOR_TYPE BinOp;
360 CHAR16 *Compare1;
361 CHAR16 *Compare2;
362 CHAR16 HexString[20];
363 CHAR16 *TempSpot;
364 BOOLEAN Match;
365
366 ASSERT((END_TAG_TYPE)OperatorToUse != EndTagThen);
367
368 Status = EFI_SUCCESS;
369 BinOp = OperatorMax;
370 OperationResult = FALSE;
371 Match = FALSE;
372 StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber];
373 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"not", &Match)) && Match) {
374 NotPresent = TRUE;
375 StatementWalker = gEfiShellParametersProtocol->Argv[++StartParameterNumber];
376 } else {
377 NotPresent = FALSE;
378 }
379
380 //
381 // now check for 'boolfunc' operators
382 //
383 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"isint", &Match)) && Match) {
384 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match
385 && StatementWalker[StrLen(StatementWalker)-1] == L')') {
386 StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL;
387 OperationResult = ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE);
388 } else {
389 Status = EFI_INVALID_PARAMETER;
390 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"isint");
391 }
392 } else if ((!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"exists", &Match)) && Match) ||
393 (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"exist", &Match)) && Match)) {
394 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match &&
395 StatementWalker[StrLen(StatementWalker)-1] == L')') {
396 StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL;
397 //
398 // is what remains a file in CWD???
399 //
400 OperationResult = (BOOLEAN)(ShellFileExists(StatementWalker)==EFI_SUCCESS);
401 } else if (StatementWalker[0] == CHAR_NULL && StartParameterNumber+1 == EndParameterNumber) {
402 OperationResult = (BOOLEAN)(ShellFileExists(gEfiShellParametersProtocol->Argv[++StartParameterNumber])==EFI_SUCCESS);
403 } else {
404 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"exist(s)");
405 Status = EFI_INVALID_PARAMETER;
406 }
407 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"available", &Match)) && Match) {
408 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match &&
409 StatementWalker[StrLen(StatementWalker)-1] == L')') {
410 StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL;
411 //
412 // is what remains a file in the CWD or path???
413 //
414 OperationResult = (BOOLEAN)(ShellIsFileInPath(StatementWalker)==EFI_SUCCESS);
415 } else {
416 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"available");
417 Status = EFI_INVALID_PARAMETER;
418 }
419 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"profile", &Match)) && Match) {
420 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match &&
421 StatementWalker[StrLen(StatementWalker)-1] == L')') {
422 //
423 // Chop off that ')'
424 //
425 StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL;
426 OperationResult = IsValidProfile(StatementWalker);
427 } else {
428 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"profile");
429 Status = EFI_INVALID_PARAMETER;
430 }
431 } else if (StartParameterNumber+1 >= EndParameterNumber) {
432 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[StartParameterNumber]);
433 Status = EFI_INVALID_PARAMETER;
434 } else {
435 //
436 // must be 'item binop item' style
437 //
438 Compare1 = NULL;
439 Compare2 = NULL;
440 BinOp = OperatorMax;
441
442 //
443 // get the first item
444 //
445 StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber];
446 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"efierror", &Match)) && Match) {
447 TempSpot = StrStr(StatementWalker, L")");
448 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) {
449 *TempSpot = CHAR_NULL;
450 if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) {
451 UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT);
452 ASSERT(Compare1 == NULL);
453 Compare1 = StrnCatGrow(&Compare1, NULL, HexString, 0);
454 StatementWalker += StrLen(StatementWalker) + 1;
455 } else {
456 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror");
457 Status = EFI_INVALID_PARAMETER;
458 }
459 } else {
460 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror");
461 Status = EFI_INVALID_PARAMETER;
462 }
463 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"pierror", &Match)) && Match) {
464 TempSpot = StrStr(StatementWalker, L")");
465 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) {
466 *TempSpot = CHAR_NULL;
467 if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) {
468 UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>2));
469 ASSERT(Compare1 == NULL);
470 Compare1 = StrnCatGrow(&Compare1, NULL, HexString, 0);
471 StatementWalker += StrLen(StatementWalker) + 1;
472 } else {
473 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror");
474 Status = EFI_INVALID_PARAMETER;
475 }
476 } else {
477 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror");
478 Status = EFI_INVALID_PARAMETER;
479 }
480 } else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16**)(&StatementWalker), L"oemerror", &Match)) && Match) {
481 TempSpot = StrStr(StatementWalker, L")");
482 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) {
483 TempSpot = CHAR_NULL;
484 if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) {
485 UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>1));
486 ASSERT(Compare1 == NULL);
487 Compare1 = StrnCatGrow(&Compare1, NULL, HexString, 0);
488 StatementWalker += StrLen(StatementWalker) + 1;
489 } else {
490 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror");
491 Status = EFI_INVALID_PARAMETER;
492 }
493 } else {
494 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror");
495 Status = EFI_INVALID_PARAMETER;
496 }
497 } else {
498 ASSERT(Compare1 == NULL);
499 if (EndParameterNumber - StartParameterNumber > 2) {
500 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_STARTING), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[StartParameterNumber+2]);
501 Status = EFI_INVALID_PARAMETER;
502 } else {
503 //
504 // must be a raw string
505 //
506 Compare1 = StrnCatGrow(&Compare1, NULL, StatementWalker, 0);
507 }
508 }
509
510 //
511 // get the operator
512 //
513 ASSERT(StartParameterNumber+1<EndParameterNumber);
514 StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber+1];
515 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"gt", &Match)) && Match) {
516 BinOp = OperatorGreaterThan;
517 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"lt", &Match)) && Match) {
518 BinOp = OperatorLessThan;
519 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"eq", &Match)) && Match) {
520 BinOp = OperatorEqual;
521 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ne", &Match)) && Match) {
522 BinOp = OperatorNotEqual;
523 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ge", &Match)) && Match) {
524 BinOp = OperatorGreatorOrEqual;
525 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"le", &Match)) && Match) {
526 BinOp = OperatorLessOrEqual;
527 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"==", &Match)) && Match) {
528 BinOp = OperatorEqual;
529 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ugt", &Match)) && Match) {
530 BinOp = OperatorUnisgnedGreaterThan;
531 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ult", &Match)) && Match) {
532 BinOp = OperatorUnsignedLessThan;
533 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"uge", &Match)) && Match) {
534 BinOp = OperatorUnsignedGreaterOrEqual;
535 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ule", &Match)) && Match) {
536 BinOp = OperatorUnsignedLessOrEqual;
537 } else {
538 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_INVALID_BINOP), gShellLevel1HiiHandle, StatementWalker);
539 Status = EFI_INVALID_PARAMETER;
540 }
541
542 //
543 // get the second item
544 //
545 ASSERT(StartParameterNumber+2<=EndParameterNumber);
546 StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber+2];
547 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"efierror", &Match)) && Match) {
548 TempSpot = StrStr(StatementWalker, L")");
549 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) {
550 TempSpot = CHAR_NULL;
551 if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) {
552 UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT);
553 ASSERT(Compare2 == NULL);
554 Compare2 = StrnCatGrow(&Compare2, NULL, HexString, 0);
555 StatementWalker += StrLen(StatementWalker) + 1;
556 } else {
557 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror");
558 Status = EFI_INVALID_PARAMETER;
559 }
560 } else {
561 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror");
562 Status = EFI_INVALID_PARAMETER;
563 }
564 //
565 // can this be collapsed into the above?
566 //
567 } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"pierror", &Match)) && Match) {
568 TempSpot = StrStr(StatementWalker, L")");
569 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) {
570 TempSpot = CHAR_NULL;
571 if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) {
572 UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>2));
573 ASSERT(Compare2 == NULL);
574 Compare2 = StrnCatGrow(&Compare2, NULL, HexString, 0);
575 StatementWalker += StrLen(StatementWalker) + 1;
576 } else {
577 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror");
578 Status = EFI_INVALID_PARAMETER;
579 }
580 } else {
581 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror");
582 Status = EFI_INVALID_PARAMETER;
583 }
584 } else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16**)(&StatementWalker), L"oemerror", &Match)) && Match) {
585 TempSpot = StrStr(StatementWalker, L")");
586 if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) {
587 TempSpot = CHAR_NULL;
588 if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) {
589 UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>1));
590 ASSERT(Compare2 == NULL);
591 Compare2 = StrnCatGrow(&Compare2, NULL, HexString, 0);
592 StatementWalker += StrLen(StatementWalker) + 1;
593 } else {
594 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror");
595 Status = EFI_INVALID_PARAMETER;
596 }
597 } else {
598 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror");
599 Status = EFI_INVALID_PARAMETER;
600 }
601 } else {
602 //
603 // must be a raw string
604 //
605 ASSERT(Compare2 == NULL);
606 Compare2 = StrnCatGrow(&Compare2, NULL, StatementWalker, 0);
607 }
608
609 if (Compare1 != NULL && Compare2 != NULL && BinOp != OperatorMax) {
610 OperationResult = TestOperation(Compare1, Compare2, BinOp, CaseInsensitive, ForceStringCompare);
611 }
612
613 SHELL_FREE_NON_NULL(Compare1);
614 SHELL_FREE_NON_NULL(Compare2);
615 }
616
617 //
618 // done processing do result...
619 //
620
621 if (!EFI_ERROR(Status)) {
622 if (NotPresent) {
623 OperationResult = (BOOLEAN)(!OperationResult);
624 }
625 switch(OperatorToUse) {
626 case EndTagOr:
627 *PassingState = (BOOLEAN)(*PassingState || OperationResult);
628 break;
629 case EndTagAnd:
630 *PassingState = (BOOLEAN)(*PassingState && OperationResult);
631 break;
632 case EndTagMax:
633 *PassingState = (BOOLEAN)(OperationResult);
634 break;
635 default:
636 ASSERT(FALSE);
637 }
638 }
639 return (Status);
640 }
641
642 /**
643 Break up the next part of the if statement (until the next 'and', 'or', or 'then').
644
645 @param[in] ParameterNumber The current parameter number.
646 @param[out] EndParameter Upon successful return, will point to the
647 parameter to start the next iteration with.
648 @param[out] EndTag Upon successful return, will point to the
649 type that was found at the end of this statement.
650
651 @retval TRUE A valid statement was found.
652 @retval FALSE A valid statement was not found.
653 **/
654 BOOLEAN
655 BuildNextStatement (
656 IN UINTN ParameterNumber,
657 OUT UINTN *EndParameter,
658 OUT END_TAG_TYPE *EndTag
659 )
660 {
661 *EndTag = EndTagMax;
662
663 for(
664 ; ParameterNumber < gEfiShellParametersProtocol->Argc
665 ; ParameterNumber++
666 ) {
667 if (gUnicodeCollation->StriColl(
668 gUnicodeCollation,
669 gEfiShellParametersProtocol->Argv[ParameterNumber],
670 L"or") == 0) {
671 *EndParameter = ParameterNumber - 1;
672 *EndTag = EndTagOr;
673 break;
674 } else if (gUnicodeCollation->StriColl(
675 gUnicodeCollation,
676 gEfiShellParametersProtocol->Argv[ParameterNumber],
677 L"and") == 0) {
678 *EndParameter = ParameterNumber - 1;
679 *EndTag = EndTagAnd;
680 break;
681 } else if (gUnicodeCollation->StriColl(
682 gUnicodeCollation,
683 gEfiShellParametersProtocol->Argv[ParameterNumber],
684 L"then") == 0) {
685 *EndParameter = ParameterNumber - 1;
686 *EndTag = EndTagThen;
687 break;
688 }
689 }
690 if (*EndTag == EndTagMax) {
691 return (FALSE);
692 }
693 return (TRUE);
694 }
695
696 /**
697 Move the script file pointer to a different place in the script file.
698 This one is special since it handles the if/else/endif syntax.
699
700 @param[in] ScriptFile The script file from GetCurrnetScriptFile().
701
702 @retval TRUE The move target was found and the move was successful.
703 @retval FALSE Something went wrong.
704 **/
705 BOOLEAN
706 MoveToTagSpecial (
707 IN SCRIPT_FILE *ScriptFile
708 )
709 {
710 SCRIPT_COMMAND_LIST *CommandNode;
711 BOOLEAN Found;
712 UINTN TargetCount;
713 CHAR16 *CommandName;
714 CHAR16 *CommandWalker;
715 CHAR16 *TempLocation;
716
717 TargetCount = 1;
718 Found = FALSE;
719
720 if (ScriptFile == NULL) {
721 return FALSE;
722 }
723
724 for (CommandNode = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &ScriptFile->CurrentCommand->Link), Found = FALSE
725 ; !IsNull(&ScriptFile->CommandList, &CommandNode->Link) && !Found
726 ; CommandNode = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &CommandNode->Link)
727 ){
728
729 //
730 // get just the first part of the command line...
731 //
732 CommandName = NULL;
733 CommandName = StrnCatGrow(&CommandName, NULL, CommandNode->Cl, 0);
734 if (CommandName == NULL) {
735 continue;
736 }
737 CommandWalker = CommandName;
738
739 //
740 // Skip leading spaces and tabs.
741 //
742 while ((CommandWalker[0] == L' ') || (CommandWalker[0] == L'\t')) {
743 CommandWalker++;
744 }
745 TempLocation = StrStr(CommandWalker, L" ");
746
747 if (TempLocation != NULL) {
748 *TempLocation = CHAR_NULL;
749 }
750
751 //
752 // did we find a nested item ?
753 //
754 if (gUnicodeCollation->StriColl(
755 gUnicodeCollation,
756 (CHAR16*)CommandWalker,
757 L"If") == 0) {
758 TargetCount++;
759 } else if (TargetCount == 1 && gUnicodeCollation->StriColl(
760 gUnicodeCollation,
761 (CHAR16*)CommandWalker,
762 (CHAR16*)L"else") == 0) {
763 //
764 // else can only decrement the last part... not an nested if
765 // hence the TargetCount compare added
766 //
767 TargetCount--;
768 } else if (gUnicodeCollation->StriColl(
769 gUnicodeCollation,
770 (CHAR16*)CommandWalker,
771 (CHAR16*)L"endif") == 0) {
772 TargetCount--;
773 }
774 if (TargetCount == 0) {
775 ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &CommandNode->Link);
776 Found = TRUE;
777 }
778
779 //
780 // Free the memory for this loop...
781 //
782 SHELL_FREE_NON_NULL(CommandName);
783 }
784 return (Found);
785 }
786
787 /**
788 Deal with the result of the if operation.
789
790 @param[in] Result The result of the if.
791
792 @retval EFI_SUCCESS The operation was successful.
793 @retval EFI_NOT_FOUND The ending tag could not be found.
794 **/
795 EFI_STATUS
796 PerformResultOperation (
797 IN CONST BOOLEAN Result
798 )
799 {
800 if (Result || MoveToTagSpecial(ShellCommandGetCurrentScriptFile())) {
801 return (EFI_SUCCESS);
802 }
803 return (EFI_NOT_FOUND);
804 }
805
806 /**
807 Function for 'if' command.
808
809 @param[in] ImageHandle Handle to the Image (NULL if Internal).
810 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
811 **/
812 SHELL_STATUS
813 EFIAPI
814 ShellCommandRunIf (
815 IN EFI_HANDLE ImageHandle,
816 IN EFI_SYSTEM_TABLE *SystemTable
817 )
818 {
819 EFI_STATUS Status;
820 SHELL_STATUS ShellStatus;
821 BOOLEAN CaseInsensitive;
822 BOOLEAN ForceString;
823 UINTN CurrentParameter;
824 UINTN EndParameter;
825 BOOLEAN CurrentValue;
826 END_TAG_TYPE Ending;
827 END_TAG_TYPE PreviousEnding;
828 SCRIPT_FILE *CurrentScriptFile;
829
830 Status = CommandInit();
831 ASSERT_EFI_ERROR(Status);
832
833 if (!gEfiShellProtocol->BatchIsActive()) {
834 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"if");
835 return (SHELL_UNSUPPORTED);
836 }
837
838 if (gEfiShellParametersProtocol->Argc < 3) {
839 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle, L"if");
840 return (SHELL_INVALID_PARAMETER);
841 }
842
843 //
844 // Make sure that an End exists.
845 //
846 CurrentScriptFile = ShellCommandGetCurrentScriptFile();
847 if (!MoveToTag(GetNextNode, L"endif", L"if", NULL, CurrentScriptFile, TRUE, TRUE, FALSE)) {
848 ShellPrintHiiEx(
849 -1,
850 -1,
851 NULL,
852 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
853 gShellLevel1HiiHandle,
854 L"EndIf",
855 L"If",
856 CurrentScriptFile!=NULL
857 && CurrentScriptFile->CurrentCommand!=NULL
858 ? CurrentScriptFile->CurrentCommand->Line:0);
859 return (SHELL_DEVICE_ERROR);
860 }
861
862 //
863 // initialize the shell lib (we must be in non-auto-init...)
864 //
865 Status = ShellInitialize();
866 ASSERT_EFI_ERROR(Status);
867
868 CurrentParameter = 1;
869 EndParameter = 0;
870
871 if (gUnicodeCollation->StriColl(
872 gUnicodeCollation,
873 gEfiShellParametersProtocol->Argv[1],
874 L"/i") == 0 ||
875 gUnicodeCollation->StriColl(
876 gUnicodeCollation,
877 gEfiShellParametersProtocol->Argv[2],
878 L"/i") == 0 ||
879 (gEfiShellParametersProtocol->Argc > 3 && gUnicodeCollation->StriColl(
880 gUnicodeCollation,
881 gEfiShellParametersProtocol->Argv[3],
882 L"/i") == 0)) {
883 CaseInsensitive = TRUE;
884 CurrentParameter++;
885 } else {
886 CaseInsensitive = FALSE;
887 }
888 if (gUnicodeCollation->StriColl(
889 gUnicodeCollation,
890 gEfiShellParametersProtocol->Argv[1],
891 L"/s") == 0 ||
892 gUnicodeCollation->StriColl(
893 gUnicodeCollation,
894 gEfiShellParametersProtocol->Argv[2],
895 L"/s") == 0 ||
896 (gEfiShellParametersProtocol->Argc > 3 && gUnicodeCollation->StriColl(
897 gUnicodeCollation,
898 gEfiShellParametersProtocol->Argv[3],
899 L"/s") == 0)) {
900 ForceString = TRUE;
901 CurrentParameter++;
902 } else {
903 ForceString = FALSE;
904 }
905
906 for ( ShellStatus = SHELL_SUCCESS, CurrentValue = FALSE, Ending = EndTagMax
907 ; CurrentParameter < gEfiShellParametersProtocol->Argc && ShellStatus == SHELL_SUCCESS
908 ; CurrentParameter++) {
909 if (gUnicodeCollation->StriColl(
910 gUnicodeCollation,
911 gEfiShellParametersProtocol->Argv[CurrentParameter],
912 L"then") == 0) {
913 //
914 // we are at the then
915 //
916 if (CurrentParameter+1 != gEfiShellParametersProtocol->Argc) {
917 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TEXT_AFTER_THEN), gShellLevel1HiiHandle, L"if");
918 ShellStatus = SHELL_INVALID_PARAMETER;
919 } else {
920 Status = PerformResultOperation(CurrentValue);
921 if (EFI_ERROR(Status)) {
922 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_AFTER_BAD), gShellLevel1HiiHandle, L"if", gEfiShellParametersProtocol->Argv[CurrentParameter]);
923 ShellStatus = SHELL_INVALID_PARAMETER;
924 }
925 }
926 } else {
927 PreviousEnding = Ending;
928 //
929 // build up the next statement for analysis
930 //
931 if (!BuildNextStatement(CurrentParameter, &EndParameter, &Ending)) {
932 CurrentScriptFile = ShellCommandGetCurrentScriptFile();
933 ShellPrintHiiEx(
934 -1,
935 -1,
936 NULL,
937 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
938 gShellLevel1HiiHandle,
939 L"Then",
940 L"If",
941 CurrentScriptFile!=NULL
942 && CurrentScriptFile->CurrentCommand!=NULL
943 ? CurrentScriptFile->CurrentCommand->Line:0);
944 ShellStatus = SHELL_INVALID_PARAMETER;
945 } else {
946 //
947 // Analyze the statement
948 //
949 Status = ProcessStatement(&CurrentValue, CurrentParameter, EndParameter, PreviousEnding, CaseInsensitive, ForceString);
950 if (EFI_ERROR(Status)) {
951 // ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_STARTING), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[CurrentParameter]);
952 ShellStatus = SHELL_INVALID_PARAMETER;
953 } else {
954 //
955 // Optomize to get out of the loop early...
956 //
957 if ((Ending == EndTagOr && CurrentValue) || (Ending == EndTagAnd && !CurrentValue)) {
958 Status = PerformResultOperation(CurrentValue);
959 if (EFI_ERROR(Status)) {
960 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_AFTER_BAD), gShellLevel1HiiHandle, L"if", gEfiShellParametersProtocol->Argv[CurrentParameter]);
961 ShellStatus = SHELL_INVALID_PARAMETER;
962 }
963 break;
964 }
965 }
966 }
967 if (ShellStatus == SHELL_SUCCESS){
968 CurrentParameter = EndParameter;
969 //
970 // Skip over the or or and parameter.
971 //
972 if (Ending == EndTagOr || Ending == EndTagAnd) {
973 CurrentParameter++;
974 }
975 }
976 }
977 }
978 return (ShellStatus);
979 }
980
981 /**
982 Function for 'else' command.
983
984 @param[in] ImageHandle Handle to the Image (NULL if Internal).
985 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
986 **/
987 SHELL_STATUS
988 EFIAPI
989 ShellCommandRunElse (
990 IN EFI_HANDLE ImageHandle,
991 IN EFI_SYSTEM_TABLE *SystemTable
992 )
993 {
994 EFI_STATUS Status;
995 SCRIPT_FILE *CurrentScriptFile;
996
997 Status = CommandInit ();
998 ASSERT_EFI_ERROR (Status);
999
1000 if (gEfiShellParametersProtocol->Argc > 1) {
1001 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"if");
1002 return (SHELL_INVALID_PARAMETER);
1003 }
1004
1005 if (!gEfiShellProtocol->BatchIsActive()) {
1006 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Else");
1007 return (SHELL_UNSUPPORTED);
1008 }
1009
1010 CurrentScriptFile = ShellCommandGetCurrentScriptFile();
1011
1012 if (!MoveToTag(GetPreviousNode, L"if", L"endif", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) {
1013 ShellPrintHiiEx(
1014 -1,
1015 -1,
1016 NULL,
1017 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
1018 gShellLevel1HiiHandle,
1019 L"If",
1020 L"Else",
1021 CurrentScriptFile!=NULL
1022 && CurrentScriptFile->CurrentCommand!=NULL
1023 ? CurrentScriptFile->CurrentCommand->Line:0);
1024 return (SHELL_DEVICE_ERROR);
1025 }
1026 if (!MoveToTag(GetPreviousNode, L"if", L"else", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) {
1027 ShellPrintHiiEx(
1028 -1,
1029 -1,
1030 NULL,
1031 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
1032 gShellLevel1HiiHandle,
1033 L"If",
1034 L"Else",
1035 CurrentScriptFile!=NULL
1036 && CurrentScriptFile->CurrentCommand!=NULL
1037 ? CurrentScriptFile->CurrentCommand->Line:0);
1038 return (SHELL_DEVICE_ERROR);
1039 }
1040
1041 if (!MoveToTag(GetNextNode, L"endif", L"if", NULL, CurrentScriptFile, FALSE, FALSE, FALSE)) {
1042 ShellPrintHiiEx(
1043 -1,
1044 -1,
1045 NULL,
1046 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
1047 gShellLevel1HiiHandle,
1048 L"EndIf",
1049 "Else",
1050 CurrentScriptFile!=NULL
1051 && CurrentScriptFile->CurrentCommand!=NULL
1052 ? CurrentScriptFile->CurrentCommand->Line:0);
1053 return (SHELL_DEVICE_ERROR);
1054 }
1055
1056 return (SHELL_SUCCESS);
1057 }
1058
1059 /**
1060 Function for 'endif' command.
1061
1062 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1063 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1064 **/
1065 SHELL_STATUS
1066 EFIAPI
1067 ShellCommandRunEndIf (
1068 IN EFI_HANDLE ImageHandle,
1069 IN EFI_SYSTEM_TABLE *SystemTable
1070 )
1071 {
1072 EFI_STATUS Status;
1073 SCRIPT_FILE *CurrentScriptFile;
1074
1075 Status = CommandInit ();
1076 ASSERT_EFI_ERROR (Status);
1077
1078 if (gEfiShellParametersProtocol->Argc > 1) {
1079 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"if");
1080 return (SHELL_INVALID_PARAMETER);
1081 }
1082
1083 if (!gEfiShellProtocol->BatchIsActive()) {
1084 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Endif");
1085 return (SHELL_UNSUPPORTED);
1086 }
1087
1088 CurrentScriptFile = ShellCommandGetCurrentScriptFile();
1089 if (!MoveToTag(GetPreviousNode, L"if", L"endif", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) {
1090 ShellPrintHiiEx(
1091 -1,
1092 -1,
1093 NULL,
1094 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
1095 gShellLevel1HiiHandle,
1096 L"If",
1097 L"EndIf",
1098 CurrentScriptFile!=NULL
1099 && CurrentScriptFile->CurrentCommand!=NULL
1100 ? CurrentScriptFile->CurrentCommand->Line:0);
1101 return (SHELL_DEVICE_ERROR);
1102 }
1103
1104 return (SHELL_SUCCESS);
1105 }