Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

392 lines
12 KiB

  1. /*++
  2. Copyright (c) 1999 Intel Corporation
  3. Module Name:
  4. for.c
  5. Abstract:
  6. Internal Shell cmd "for" & "endfor"
  7. Revision History
  8. --*/
  9. #include "shelle.h"
  10. /*
  11. * Datatypes
  12. */
  13. #define FOR_LOOP_INFO_SIGNATURE EFI_SIGNATURE_32('f','l','i','s')
  14. typedef struct {
  15. UINTN Signature;
  16. LIST_ENTRY Link;
  17. UINT64 LoopFilePos;
  18. CHAR16 *IndexVarName;
  19. LIST_ENTRY IndexValueList;
  20. } FOR_LOOP_INFO;
  21. #define FOR_LOOP_INDEXVAL_SIGNATURE EFI_SIGNATURE_32('f','l','v','s')
  22. typedef struct {
  23. UINTN Signature;
  24. LIST_ENTRY Link;
  25. CHAR16 *Value;
  26. } FOR_LOOP_INDEXVAL;
  27. /*
  28. * Statics
  29. */
  30. STATIC LIST_ENTRY ForLoopInfoStack;
  31. STATIC UINTN NumActiveForLoops;
  32. VOID
  33. DumpForLoopInfoStack(VOID)
  34. {
  35. LIST_ENTRY *InfoLink;
  36. LIST_ENTRY *IndexLink;
  37. FOR_LOOP_INFO *LoopInfo;
  38. FOR_LOOP_INDEXVAL *LoopIndexVal;
  39. Print( L"FOR LOOP INFO STACK DUMP\n" );
  40. for ( InfoLink = ForLoopInfoStack.Flink; InfoLink!=&ForLoopInfoStack; InfoLink=InfoLink->Flink) {
  41. LoopInfo = CR(InfoLink, FOR_LOOP_INFO, Link, FOR_LOOP_INFO_SIGNATURE);
  42. if ( LoopInfo ) {
  43. Print( L" LoopFilePos 0x%X\n", LoopInfo->LoopFilePos );
  44. Print( L" IndexVarName %s (0x%X)\n", LoopInfo->IndexVarName, LoopInfo->IndexVarName );
  45. for ( IndexLink = LoopInfo->IndexValueList.Flink; IndexLink!=&LoopInfo->IndexValueList; IndexLink=IndexLink->Flink ) {
  46. LoopIndexVal = CR(IndexLink, FOR_LOOP_INDEXVAL, Link, FOR_LOOP_INDEXVAL_SIGNATURE);
  47. if ( LoopIndexVal ) {
  48. if ( LoopIndexVal->Value ) {
  49. Print( L" Loop index value %s\n", LoopIndexVal->Value );
  50. } else {
  51. Print( L" Loop index value is NULL\n" );
  52. }
  53. } else {
  54. Print( L" Loop index value structure pointer is NULL\n" );
  55. }
  56. }
  57. } else {
  58. Print( L" LoopInfo NULL\n" );
  59. }
  60. }
  61. return;
  62. }
  63. /*///////////////////////////////////////////////////////////////////////
  64. Function Name:
  65. SEnvInitForLoopInfo
  66. Description:
  67. Initialize data structures used in or loop management.
  68. */
  69. VOID
  70. SEnvInitForLoopInfo (
  71. VOID
  72. )
  73. {
  74. InitializeListHead( &ForLoopInfoStack );
  75. NumActiveForLoops = 0;
  76. return;
  77. }
  78. /*///////////////////////////////////////////////////////////////////////
  79. Function Name:
  80. SEnvSubstituteForLoopIndex
  81. Description:
  82. Builtin shell command "for" for conditional execution in script files.
  83. */
  84. EFI_STATUS
  85. SEnvSubstituteForLoopIndex(
  86. IN CHAR16 *Str,
  87. OUT CHAR16 **Val
  88. )
  89. {
  90. LIST_ENTRY *InfoLink = NULL;
  91. LIST_ENTRY *IndexLink = NULL;
  92. FOR_LOOP_INFO *LoopInfo = NULL;
  93. FOR_LOOP_INDEXVAL *LoopIndexVal = NULL;
  94. EFI_STATUS Status = EFI_SUCCESS;
  95. /*
  96. * Check if Str is a forloop index variable name on the forloop info stack
  97. * If it is, return the current value
  98. * Otherwise, just return the string.
  99. */
  100. if ( Str[0] != L'%' || !IsWhiteSpace(Str[2]) ) {
  101. Status = EFI_INVALID_PARAMETER;
  102. goto Done;
  103. }
  104. /*
  105. * We may have nested for loops, so we have to search through the variables for
  106. * each for loop on the stack to see if we can match the variable name.
  107. */
  108. for ( InfoLink = ForLoopInfoStack.Flink; InfoLink!=&ForLoopInfoStack; InfoLink=InfoLink->Flink) {
  109. LoopInfo = CR(InfoLink, FOR_LOOP_INFO, Link, FOR_LOOP_INFO_SIGNATURE);
  110. if ( LoopInfo ) {
  111. if ( Str[1] == LoopInfo->IndexVarName[0] ) {
  112. /* Found a match */
  113. IndexLink = LoopInfo->IndexValueList.Flink;
  114. LoopIndexVal = CR(IndexLink, FOR_LOOP_INDEXVAL, Link, FOR_LOOP_INDEXVAL_SIGNATURE);
  115. if ( LoopIndexVal && LoopIndexVal->Value ) {
  116. *Val = LoopIndexVal->Value;
  117. Status = EFI_SUCCESS;
  118. goto Done;
  119. } else {
  120. Status = EFI_INVALID_PARAMETER;
  121. goto Done;
  122. }
  123. }
  124. }
  125. }
  126. *Val = NULL;
  127. Done:
  128. return Status;
  129. }
  130. /*///////////////////////////////////////////////////////////////////////
  131. Function Name:
  132. SEnvCmdFor
  133. Description:
  134. Builtin shell command "for" for conditional execution in script files.
  135. */
  136. EFI_STATUS
  137. SEnvCmdFor (
  138. IN EFI_HANDLE ImageHandle,
  139. IN EFI_SYSTEM_TABLE *SystemTable
  140. )
  141. {
  142. CHAR16 **Argv;
  143. UINTN Argc = 0;
  144. UINTN Index = 0;
  145. EFI_STATUS Status = EFI_SUCCESS;
  146. UINTN i = 0;
  147. LIST_ENTRY FileList;
  148. LIST_ENTRY *Link = NULL;
  149. SHELL_FILE_ARG *Arg = NULL;
  150. FOR_LOOP_INFO *NewInfo = NULL;
  151. FOR_LOOP_INDEXVAL *NewIndexVal = NULL;
  152. InitializeShellApplication (ImageHandle, SystemTable);
  153. Argv = SI->Argv;
  154. Argc = SI->Argc;
  155. InitializeListHead( &FileList );
  156. if ( !SEnvBatchIsActive() ) {
  157. Print( L"Error: FOR command only supported in script files\n" );
  158. Status = EFI_UNSUPPORTED;
  159. goto Done;
  160. }
  161. /*
  162. * First, parse the command line arguments
  163. *
  164. * for %<var> in <string | file [[string | file]...]>
  165. */
  166. if ( Argc < 4 ||
  167. (StriCmp( Argv[2], L"in" ) != 0) ||
  168. !(StrLen(Argv[1]) == 1 && IsAlpha(Argv[1][0]) ) )
  169. {
  170. Print( L"Argc %d, Argv[2] %s, StrLen(Argv[1]) %d, Argv[1][0] %c\n", Argc, Argv[2], StrLen(Argv[1]), Argv[1][0] );
  171. Status = EFI_INVALID_PARAMETER;
  172. goto Done;
  173. }
  174. /*
  175. * Allocate a new forloop info structure for this for loop, and
  176. * puch it on the for loop info stack.
  177. */
  178. NewInfo = AllocateZeroPool( sizeof( FOR_LOOP_INFO ) );
  179. if ( !NewInfo ) {
  180. Status = EFI_OUT_OF_RESOURCES;
  181. goto Done;
  182. }
  183. NewInfo->Signature = FOR_LOOP_INFO_SIGNATURE;
  184. InsertHeadList( &ForLoopInfoStack, &NewInfo->Link );
  185. /*
  186. * Save the current script file position and the index variable name on
  187. * the for-loop info stack. Increment the active-for-loop counter.
  188. */
  189. SEnvBatchGetFilePos( &NewInfo->LoopFilePos );
  190. InitializeListHead( &NewInfo->IndexValueList );
  191. NumActiveForLoops++;
  192. NewInfo->IndexVarName = StrDuplicate( Argv[1] );
  193. /*
  194. * Put the set of index values in the index value list for this for loop
  195. */
  196. for ( i=3; i<Argc; i++ ) {
  197. /*
  198. * Expand any wildcard filename arguments
  199. * Strings and non-wildcard filenames will accumulate in FileList
  200. */
  201. Status = ShellFileMetaArg( Argv[i], &FileList);
  202. if ( EFI_ERROR( Status ) ) {
  203. Print( L"ShellFileMetaArg error: %r\n", Status );
  204. }
  205. /*
  206. * Build the list of index values from the file list
  207. * This will contain either the unexpanded argument or
  208. * all the filenames matching an argument with wildcards
  209. */
  210. for (Link=FileList.Flink; Link!=&FileList; Link=Link->Flink) {
  211. Arg = CR(Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
  212. NewIndexVal = AllocateZeroPool( sizeof(FOR_LOOP_INDEXVAL) );
  213. if ( !NewIndexVal ) {
  214. Status = EFI_OUT_OF_RESOURCES;
  215. goto Done;
  216. }
  217. NewIndexVal->Signature = FOR_LOOP_INDEXVAL_SIGNATURE;
  218. InsertTailList( &NewInfo->IndexValueList, &NewIndexVal->Link );
  219. NewIndexVal->Value = AllocateZeroPool( StrSize(Arg->FileName) + sizeof(CHAR16) );
  220. if ( !NewIndexVal->Value ) {
  221. Status = EFI_OUT_OF_RESOURCES;
  222. goto Done;
  223. }
  224. StrCpy( NewIndexVal->Value, Arg->FileName );
  225. }
  226. /*
  227. * Free the file list that was allocated by ShellFileMetaArg
  228. */
  229. ShellFreeFileList (&FileList);
  230. }
  231. /*
  232. * Return control to the batch processing loop until an ENDFOR is encountered
  233. */
  234. Done:
  235. /*
  236. * Free the file list
  237. */
  238. if ( !IsListEmpty( &FileList ) ) {
  239. ShellFreeFileList (&FileList);
  240. }
  241. return Status;
  242. }
  243. /*///////////////////////////////////////////////////////////////////////
  244. Function Name:
  245. SEnvCmdEndfor
  246. Description:
  247. Builtin shell command "endfor".
  248. */
  249. EFI_STATUS
  250. SEnvCmdEndfor (
  251. IN EFI_HANDLE ImageHandle,
  252. IN EFI_SYSTEM_TABLE *SystemTable
  253. )
  254. {
  255. EFI_STATUS Status = EFI_SUCCESS;
  256. LIST_ENTRY *InfoLink = NULL;
  257. LIST_ENTRY *IndexLink = NULL;
  258. FOR_LOOP_INFO *LoopInfo = NULL;
  259. FOR_LOOP_INDEXVAL *LoopIndexVal = NULL;
  260. InitializeShellApplication (ImageHandle, SystemTable);
  261. if ( !SEnvBatchIsActive() ) {
  262. Print( L"Error: ENDFOR command only supported in script files\n" );
  263. Status = EFI_UNSUPPORTED;
  264. goto Done;
  265. }
  266. if ( NumActiveForLoops == 0 ) {
  267. Print( L"Error: ENDFOR with no corresponding FOR\n" );
  268. Status = EFI_INVALID_PARAMETER;
  269. goto Done;
  270. }
  271. /*
  272. * Discard the index value for the just-completed iteration
  273. */
  274. /* Get a pointer to the FOR_LOOP_INFO structure at the top of the stack (list) */
  275. InfoLink = ForLoopInfoStack.Flink;
  276. LoopInfo = CR(InfoLink, FOR_LOOP_INFO, Link, FOR_LOOP_INFO_SIGNATURE);
  277. if ( LoopInfo ) {
  278. /* Get a pointer to the FOR_LOOP_INDEXVAL structure at the front of the list */
  279. IndexLink = LoopInfo->IndexValueList.Flink;
  280. LoopIndexVal = CR(IndexLink, FOR_LOOP_INDEXVAL, Link, FOR_LOOP_INDEXVAL_SIGNATURE);
  281. if ( LoopIndexVal ) {
  282. /* Free the string containing the index value */
  283. if ( LoopIndexVal->Value ) {
  284. FreePool( LoopIndexVal->Value );
  285. LoopIndexVal->Value = NULL;
  286. }
  287. /* Remove the used index value structure from the list and free it */
  288. RemoveEntryList( &LoopIndexVal->Link );
  289. FreePool( LoopIndexVal );
  290. LoopIndexVal = NULL;
  291. /*
  292. * If there is another value, then jump back to top of loop,
  293. * otherwise, exit this FOR loop & pop the FOR loop info stack.
  294. */
  295. if ( !IsListEmpty( &LoopInfo->IndexValueList ) ) {
  296. /*
  297. * Set script file position back to top of this loop
  298. */
  299. Status = SEnvBatchSetFilePos( LoopInfo->LoopFilePos );
  300. if ( EFI_ERROR(Status) ) {
  301. goto Done;
  302. }
  303. } else {
  304. if ( LoopInfo->IndexVarName ) {
  305. FreePool( LoopInfo->IndexVarName );
  306. LoopInfo->IndexVarName = NULL;
  307. }
  308. /*
  309. * Pop the stack and free the popped for loop info struct
  310. */
  311. RemoveEntryList( &LoopInfo->Link );
  312. if ( LoopInfo->IndexVarName ) {
  313. FreePool( LoopInfo->IndexVarName );
  314. }
  315. FreePool( LoopInfo );
  316. LoopInfo = NULL;
  317. NumActiveForLoops--;
  318. }
  319. }
  320. }
  321. Done:
  322. return EFI_SUCCESS;
  323. }