]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Application/Shell/ShellEnvVar.c
ShellPkg: Move FindFirstCharacter/GetNextParameter to ShellCommandLib
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellEnvVar.c
CommitLineData
a405b86d 1/** @file\r
2 function declarations for shell environment functions.\r
3\r
b62bb885 4 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
a405b86d 5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
0406a571 15#include "Shell.h"\r
a405b86d 16\r
654a012b
QS
17#define INIT_NAME_BUFFER_SIZE 128\r
18#define INIT_DATA_BUFFER_SIZE 1024\r
19\r
b62bb885
QS
20//\r
21// The list is used to cache the environment variables.\r
22//\r
23ENV_VAR_LIST gShellEnvVarList;\r
24\r
a405b86d 25/**\r
26 Reports whether an environment variable is Volatile or Non-Volatile.\r
27\r
28 @param EnvVarName The name of the environment variable in question\r
31e5b912 29 @param Volatile Return TRUE if the environment variable is volatile\r
a405b86d 30\r
31e5b912
RN
31 @retval EFI_SUCCESS The volatile attribute is returned successfully\r
32 @retval others Some errors happened.\r
a405b86d 33**/\r
31e5b912 34EFI_STATUS\r
a405b86d 35IsVolatileEnv (\r
31e5b912
RN
36 IN CONST CHAR16 *EnvVarName,\r
37 OUT BOOLEAN *Volatile\r
a405b86d 38 )\r
39{\r
40 EFI_STATUS Status;\r
41 UINTN Size;\r
42 VOID *Buffer;\r
43 UINT32 Attribs;\r
44\r
31e5b912
RN
45 ASSERT (Volatile != NULL);\r
46\r
a405b86d 47 Size = 0;\r
48 Buffer = NULL;\r
49\r
50 //\r
51 // get the variable\r
52 //\r
53 Status = gRT->GetVariable((CHAR16*)EnvVarName,\r
54 &gShellVariableGuid,\r
55 &Attribs,\r
56 &Size,\r
57 Buffer);\r
58 if (Status == EFI_BUFFER_TOO_SMALL) {\r
733f138d 59 Buffer = AllocateZeroPool(Size);\r
31e5b912
RN
60 if (Buffer == NULL) {\r
61 return EFI_OUT_OF_RESOURCES;\r
62 }\r
a405b86d 63 Status = gRT->GetVariable((CHAR16*)EnvVarName,\r
64 &gShellVariableGuid,\r
65 &Attribs,\r
66 &Size,\r
67 Buffer);\r
68 FreePool(Buffer);\r
69 }\r
70 //\r
71 // not found means volatile\r
72 //\r
73 if (Status == EFI_NOT_FOUND) {\r
31e5b912
RN
74 *Volatile = TRUE;\r
75 return EFI_SUCCESS;\r
a405b86d 76 }\r
31e5b912
RN
77 if (EFI_ERROR (Status)) {\r
78 return Status;\r
a405b86d 79 }\r
80\r
81 //\r
31e5b912 82 // check for the Non Volatile bit\r
a405b86d 83 //\r
31e5b912
RN
84 *Volatile = !(BOOLEAN) ((Attribs & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE);\r
85 return EFI_SUCCESS;\r
a405b86d 86}\r
87\r
88/**\r
89 free function for ENV_VAR_LIST objects.\r
90\r
91 @param[in] List The pointer to pointer to list.\r
92**/\r
93VOID\r
94EFIAPI\r
95FreeEnvironmentVariableList(\r
96 IN LIST_ENTRY *List\r
97 )\r
98{\r
99 ENV_VAR_LIST *Node;\r
100\r
101 ASSERT (List != NULL);\r
102 if (List == NULL) {\r
103 return;\r
104 }\r
105\r
106 for ( Node = (ENV_VAR_LIST*)GetFirstNode(List)\r
3f869579 107 ; !IsListEmpty(List)\r
a405b86d 108 ; Node = (ENV_VAR_LIST*)GetFirstNode(List)\r
109 ){\r
110 ASSERT(Node != NULL);\r
111 RemoveEntryList(&Node->Link);\r
112 if (Node->Key != NULL) {\r
113 FreePool(Node->Key);\r
114 }\r
115 if (Node->Val != NULL) {\r
116 FreePool(Node->Val);\r
117 }\r
118 FreePool(Node);\r
119 }\r
120}\r
121\r
122/**\r
123 Creates a list of all Shell-Guid-based environment variables.\r
124\r
4ff7e37b
ED
125 @param[in, out] ListHead The pointer to pointer to LIST ENTRY object for\r
126 storing this list.\r
a405b86d 127\r
128 @retval EFI_SUCCESS the list was created sucessfully.\r
129**/\r
130EFI_STATUS\r
131EFIAPI\r
132GetEnvironmentVariableList(\r
133 IN OUT LIST_ENTRY *ListHead\r
134 )\r
135{\r
136 CHAR16 *VariableName;\r
137 UINTN NameSize;\r
654a012b 138 UINTN NameBufferSize;\r
a405b86d 139 EFI_STATUS Status;\r
140 EFI_GUID Guid;\r
141 UINTN ValSize;\r
654a012b 142 UINTN ValBufferSize;\r
a405b86d 143 ENV_VAR_LIST *VarList;\r
144\r
3c865f20 145 if (ListHead == NULL) {\r
146 return (EFI_INVALID_PARAMETER);\r
147 }\r
654a012b
QS
148 \r
149 Status = EFI_SUCCESS;\r
150 \r
151 ValBufferSize = INIT_DATA_BUFFER_SIZE;\r
152 NameBufferSize = INIT_NAME_BUFFER_SIZE;\r
153 VariableName = AllocateZeroPool(NameBufferSize);\r
3c865f20 154 if (VariableName == NULL) {\r
155 return (EFI_OUT_OF_RESOURCES);\r
156 }\r
7f79b01e 157 *VariableName = CHAR_NULL;\r
a405b86d 158\r
3c865f20 159 while (!EFI_ERROR(Status)) {\r
654a012b 160 NameSize = NameBufferSize;\r
a405b86d 161 Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
162 if (Status == EFI_NOT_FOUND){\r
163 Status = EFI_SUCCESS;\r
164 break;\r
654a012b
QS
165 } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
166 NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2;\r
167 SHELL_FREE_NON_NULL(VariableName);\r
168 VariableName = AllocateZeroPool(NameBufferSize);\r
169 if (VariableName == NULL) {\r
170 Status = EFI_OUT_OF_RESOURCES;\r
171 break;\r
172 }\r
173 NameSize = NameBufferSize;\r
174 Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
a405b86d 175 }\r
654a012b 176 \r
3c865f20 177 if (!EFI_ERROR(Status) && CompareGuid(&Guid, &gShellVariableGuid)){\r
a405b86d 178 VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST));\r
8be0ba36 179 if (VarList == NULL) {\r
180 Status = EFI_OUT_OF_RESOURCES;\r
181 } else {\r
654a012b
QS
182 ValSize = ValBufferSize;\r
183 VarList->Val = AllocateZeroPool(ValSize);\r
184 if (VarList->Val == NULL) {\r
185 SHELL_FREE_NON_NULL(VarList);\r
186 Status = EFI_OUT_OF_RESOURCES;\r
187 break;\r
188 }\r
a405b86d 189 Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val);\r
8be0ba36 190 if (Status == EFI_BUFFER_TOO_SMALL){\r
654a012b
QS
191 ValBufferSize = ValSize > ValBufferSize * 2 ? ValSize : ValBufferSize * 2;\r
192 SHELL_FREE_NON_NULL (VarList->Val);\r
193 VarList->Val = AllocateZeroPool(ValBufferSize);\r
8be0ba36 194 if (VarList->Val == NULL) {\r
195 SHELL_FREE_NON_NULL(VarList);\r
196 Status = EFI_OUT_OF_RESOURCES;\r
654a012b 197 break;\r
8be0ba36 198 }\r
654a012b
QS
199 \r
200 ValSize = ValBufferSize;\r
201 Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val);\r
8be0ba36 202 }\r
654a012b 203 if (!EFI_ERROR(Status)) {\r
7f79b01e 204 VarList->Key = AllocateCopyPool(StrSize(VariableName), VariableName);\r
8be0ba36 205 if (VarList->Key == NULL) {\r
206 SHELL_FREE_NON_NULL(VarList->Val);\r
207 SHELL_FREE_NON_NULL(VarList);\r
208 Status = EFI_OUT_OF_RESOURCES;\r
209 } else {\r
8be0ba36 210 InsertTailList(ListHead, &VarList->Link);\r
211 }\r
654a012b
QS
212 } else {\r
213 SHELL_FREE_NON_NULL(VarList->Val);\r
214 SHELL_FREE_NON_NULL(VarList);\r
8be0ba36 215 }\r
654a012b 216 } // if (VarList == NULL) ... else ...\r
a405b86d 217 } // compare guid\r
218 } // while\r
654a012b 219 SHELL_FREE_NON_NULL (VariableName);\r
a405b86d 220\r
221 if (EFI_ERROR(Status)) {\r
222 FreeEnvironmentVariableList(ListHead);\r
223 }\r
224\r
225 return (Status);\r
226}\r
227\r
228/**\r
229 Sets a list of all Shell-Guid-based environment variables. this will\r
230 also eliminate all existing shell environment variables (even if they\r
231 are not on the list).\r
232\r
233 This function will also deallocate the memory from List.\r
234\r
235 @param[in] ListHead The pointer to LIST_ENTRY from\r
236 GetShellEnvVarList().\r
237\r
238 @retval EFI_SUCCESS the list was Set sucessfully.\r
239**/\r
240EFI_STATUS\r
241EFIAPI\r
242SetEnvironmentVariableList(\r
243 IN LIST_ENTRY *ListHead\r
244 )\r
245{\r
246 ENV_VAR_LIST VarList;\r
247 ENV_VAR_LIST *Node;\r
248 EFI_STATUS Status;\r
249 UINTN Size;\r
250\r
251 InitializeListHead(&VarList.Link);\r
252\r
253 //\r
254 // Delete all the current environment variables\r
255 //\r
256 Status = GetEnvironmentVariableList(&VarList.Link);\r
257 ASSERT_EFI_ERROR(Status);\r
258\r
259 for ( Node = (ENV_VAR_LIST*)GetFirstNode(&VarList.Link)\r
260 ; !IsNull(&VarList.Link, &Node->Link)\r
261 ; Node = (ENV_VAR_LIST*)GetNextNode(&VarList.Link, &Node->Link)\r
262 ){\r
263 if (Node->Key != NULL) {\r
264 Status = SHELL_DELETE_ENVIRONMENT_VARIABLE(Node->Key);\r
265 }\r
266 ASSERT_EFI_ERROR(Status);\r
267 }\r
268\r
269 FreeEnvironmentVariableList(&VarList.Link);\r
270\r
271 //\r
272 // set all the variables fron the list\r
273 //\r
274 for ( Node = (ENV_VAR_LIST*)GetFirstNode(ListHead)\r
275 ; !IsNull(ListHead, &Node->Link)\r
276 ; Node = (ENV_VAR_LIST*)GetNextNode(ListHead, &Node->Link)\r
277 ){\r
278 Size = StrSize(Node->Val);\r
279 if (Node->Atts & EFI_VARIABLE_NON_VOLATILE) {\r
280 Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(Node->Key, Size, Node->Val);\r
281 } else {\r
282 Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (Node->Key, Size, Node->Val);\r
283 }\r
284 ASSERT_EFI_ERROR(Status);\r
285 }\r
286 FreeEnvironmentVariableList(ListHead);\r
287\r
288 return (Status);\r
289}\r
290\r
291/**\r
292 sets a list of all Shell-Guid-based environment variables.\r
293\r
294 @param Environment Points to a NULL-terminated array of environment\r
295 variables with the format 'x=y', where x is the\r
296 environment variable name and y is the value.\r
297\r
298 @retval EFI_SUCCESS The command executed successfully.\r
299 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
300 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
301\r
302 @sa SetEnvironmentVariableList\r
303**/\r
304EFI_STATUS\r
305EFIAPI\r
306SetEnvironmentVariables(\r
307 IN CONST CHAR16 **Environment\r
308 )\r
309{\r
310 CONST CHAR16 *CurrentString;\r
311 UINTN CurrentCount;\r
312 ENV_VAR_LIST *VarList;\r
313 ENV_VAR_LIST *Node;\r
a405b86d 314\r
315 VarList = NULL;\r
316\r
317 if (Environment == NULL) {\r
318 return (EFI_INVALID_PARAMETER);\r
319 }\r
320\r
321 //\r
322 // Build a list identical to the ones used for get/set list functions above\r
323 //\r
324 for ( CurrentCount = 0\r
325 ;\r
326 ; CurrentCount++\r
327 ){\r
328 CurrentString = Environment[CurrentCount];\r
329 if (CurrentString == NULL) {\r
330 break;\r
331 }\r
332 ASSERT(StrStr(CurrentString, L"=") != NULL);\r
733f138d 333 Node = AllocateZeroPool(sizeof(ENV_VAR_LIST));\r
7f79b01e
JC
334 if (Node == NULL) {\r
335 SetEnvironmentVariableList(&VarList->Link);\r
336 return (EFI_OUT_OF_RESOURCES);\r
337 }\r
338\r
a405b86d 339 Node->Key = AllocateZeroPool((StrStr(CurrentString, L"=") - CurrentString + 1) * sizeof(CHAR16));\r
7f79b01e
JC
340 if (Node->Key == NULL) {\r
341 SHELL_FREE_NON_NULL(Node);\r
342 SetEnvironmentVariableList(&VarList->Link);\r
343 return (EFI_OUT_OF_RESOURCES);\r
344 }\r
345\r
346 //\r
347 // Copy the string into the Key, leaving the last character allocated as NULL to terminate\r
348 //\r
490ce43d 349 StrnCpyS( Node->Key, \r
e75390f0 350 StrStr(CurrentString, L"=") - CurrentString + 1, \r
490ce43d
QS
351 CurrentString,\r
352 StrStr(CurrentString, L"=") - CurrentString\r
e75390f0 353 );\r
7f79b01e
JC
354\r
355 //\r
356 // ValueSize = TotalSize - already removed size - size for '=' + size for terminator (the last 2 items cancel each other)\r
357 //\r
358 Node->Val = AllocateCopyPool(StrSize(CurrentString) - StrSize(Node->Key), CurrentString + StrLen(Node->Key) + 1);\r
359 if (Node->Val == NULL) {\r
360 SHELL_FREE_NON_NULL(Node->Key);\r
361 SHELL_FREE_NON_NULL(Node);\r
362 SetEnvironmentVariableList(&VarList->Link);\r
363 return (EFI_OUT_OF_RESOURCES);\r
364 }\r
365\r
a405b86d 366 Node->Atts = EFI_VARIABLE_BOOTSERVICE_ACCESS;\r
367\r
368 if (VarList == NULL) {\r
369 VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST));\r
7f79b01e
JC
370 if (VarList == NULL) {\r
371 SHELL_FREE_NON_NULL(Node->Key);\r
372 SHELL_FREE_NON_NULL(Node->Val);\r
373 SHELL_FREE_NON_NULL(Node);\r
374 return (EFI_OUT_OF_RESOURCES);\r
375 }\r
a405b86d 376 InitializeListHead(&VarList->Link);\r
377 }\r
378 InsertTailList(&VarList->Link, &Node->Link);\r
379\r
380 } // for loop\r
381\r
382 //\r
383 // set this new list as the set of all environment variables.\r
384 // this function also frees the memory and deletes all pre-existing\r
385 // shell-guid based environment variables.\r
386 //\r
387 return (SetEnvironmentVariableList(&VarList->Link));\r
388}\r
b62bb885
QS
389\r
390/**\r
391 Find an environment variable in the gShellEnvVarList.\r
392\r
393 @param Key The name of the environment variable.\r
394 @param Value The value of the environment variable, the buffer\r
395 shoule be freed by the caller.\r
396 @param ValueSize The size in bytes of the environment variable\r
397 including the tailing CHAR_NELL.\r
398 @param Atts The attributes of the variable.\r
399\r
400 @retval EFI_SUCCESS The command executed successfully.\r
401 @retval EFI_NOT_FOUND The environment variable is not found in\r
402 gShellEnvVarList.\r
403\r
404**/\r
405EFI_STATUS\r
406ShellFindEnvVarInList (\r
407 IN CONST CHAR16 *Key,\r
408 OUT CHAR16 **Value,\r
409 OUT UINTN *ValueSize,\r
410 OUT UINT32 *Atts OPTIONAL\r
411 )\r
412{\r
413 ENV_VAR_LIST *Node;\r
414 \r
415 if (Key == NULL || Value == NULL || ValueSize == NULL) {\r
416 return SHELL_INVALID_PARAMETER;\r
417 }\r
418\r
419 for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)\r
420 ; !IsNull(&gShellEnvVarList.Link, &Node->Link)\r
421 ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)\r
422 ){\r
423 if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) {\r
424 *Value = AllocateCopyPool(StrSize(Node->Val), Node->Val);\r
425 *ValueSize = StrSize(Node->Val);\r
426 if (Atts != NULL) {\r
427 *Atts = Node->Atts;\r
428 }\r
429 return EFI_SUCCESS;\r
430 }\r
431 }\r
432\r
433 return EFI_NOT_FOUND;\r
434}\r
435\r
436/**\r
437 Add an environment variable into gShellEnvVarList.\r
438\r
439 @param Key The name of the environment variable.\r
440 @param Value The value of environment variable.\r
441 @param ValueSize The size in bytes of the environment variable\r
442 including the tailing CHAR_NULL\r
443 @param Atts The attributes of the variable.\r
444\r
ffbc60a0
RN
445 @retval EFI_SUCCESS The environment variable was added to list successfully.\r
446 @retval others Some errors happened.\r
447\r
b62bb885 448**/\r
ffbc60a0 449EFI_STATUS\r
b62bb885
QS
450ShellAddEnvVarToList (\r
451 IN CONST CHAR16 *Key,\r
452 IN CONST CHAR16 *Value,\r
453 IN UINTN ValueSize,\r
454 IN UINT32 Atts\r
455 )\r
456{\r
457 ENV_VAR_LIST *Node;\r
ffbc60a0
RN
458 CHAR16 *LocalKey;\r
459 CHAR16 *LocalValue;\r
b62bb885
QS
460 \r
461 if (Key == NULL || Value == NULL || ValueSize == 0) {\r
ffbc60a0
RN
462 return EFI_INVALID_PARAMETER;\r
463 }\r
464\r
465 LocalValue = AllocateCopyPool (ValueSize, Value);\r
466 if (LocalValue == NULL) {\r
467 return EFI_OUT_OF_RESOURCES;\r
b62bb885
QS
468 }\r
469\r
470 //\r
471 // Update the variable value if it exists in gShellEnvVarList.\r
472 //\r
473 for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)\r
474 ; !IsNull(&gShellEnvVarList.Link, &Node->Link)\r
475 ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)\r
476 ){\r
477 if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) {\r
478 Node->Atts = Atts;\r
479 SHELL_FREE_NON_NULL(Node->Val);\r
ffbc60a0
RN
480 Node->Val = LocalValue;\r
481 return EFI_SUCCESS;\r
b62bb885
QS
482 }\r
483 }\r
484\r
485 //\r
486 // If the environment varialbe key doesn't exist in list just insert\r
487 // a new node.\r
488 //\r
ffbc60a0
RN
489 LocalKey = AllocateCopyPool (StrSize(Key), Key);\r
490 if (LocalKey == NULL) {\r
491 FreePool (LocalValue);\r
492 return EFI_OUT_OF_RESOURCES;\r
493 }\r
b62bb885 494 Node = (ENV_VAR_LIST*)AllocateZeroPool (sizeof(ENV_VAR_LIST));\r
ffbc60a0
RN
495 if (Node == NULL) {\r
496 FreePool (LocalKey);\r
497 FreePool (LocalValue);\r
498 return EFI_OUT_OF_RESOURCES;\r
499 }\r
500 Node->Key = LocalKey;\r
501 Node->Val = LocalValue;\r
b62bb885
QS
502 Node->Atts = Atts;\r
503 InsertTailList(&gShellEnvVarList.Link, &Node->Link);\r
504\r
ffbc60a0 505 return EFI_SUCCESS;\r
b62bb885
QS
506}\r
507\r
508/**\r
509 Remove a specified environment variable in gShellEnvVarList.\r
510\r
511 @param Key The name of the environment variable.\r
512 \r
513 @retval EFI_SUCCESS The command executed successfully.\r
514 @retval EFI_NOT_FOUND The environment variable is not found in\r
515 gShellEnvVarList.\r
516**/\r
517EFI_STATUS\r
518ShellRemvoeEnvVarFromList (\r
519 IN CONST CHAR16 *Key\r
520 )\r
521{\r
522 ENV_VAR_LIST *Node;\r
523\r
524 if (Key == NULL) {\r
525 return EFI_INVALID_PARAMETER;\r
526 }\r
527\r
528 for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)\r
529 ; !IsNull(&gShellEnvVarList.Link, &Node->Link)\r
530 ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)\r
531 ){\r
532 if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) {\r
533 SHELL_FREE_NON_NULL(Node->Key);\r
534 SHELL_FREE_NON_NULL(Node->Val);\r
535 RemoveEntryList(&Node->Link);\r
536 SHELL_FREE_NON_NULL(Node);\r
537 return EFI_SUCCESS;\r
538 }\r
539 }\r
540\r
541 return EFI_NOT_FOUND;\r
542}\r
543\r
544/**\r
545 Initialize the gShellEnvVarList and cache all Shell-Guid-based environment\r
546 variables.\r
547 \r
548**/\r
549EFI_STATUS\r
550ShellInitEnvVarList (\r
551 VOID\r
552 )\r
553{\r
554 EFI_STATUS Status;\r
555\r
556 InitializeListHead(&gShellEnvVarList.Link);\r
557 Status = GetEnvironmentVariableList (&gShellEnvVarList.Link);\r
558\r
559 return Status;\r
560}\r
561\r
562/**\r
563 Destructe the gShellEnvVarList.\r
564\r
565**/\r
566VOID\r
567ShellFreeEnvVarList (\r
568 VOID\r
569 )\r
570{\r
571 FreeEnvironmentVariableList (&gShellEnvVarList.Link);\r
572 InitializeListHead(&gShellEnvVarList.Link);\r
573\r
574 return;\r
575}\r
576\r