]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/LibC/Main/Main.c
523965fa4368b53d975b3b99027d34593954747b
[mirror_edk2.git] / StdLib / LibC / Main / Main.c
1 /** @file
2 Establish the program environment and the "main" entry point.
3
4 All of the global data in the gMD structure is initialized to 0, NULL, or
5 SIG_DFL; as appropriate.
6
7 Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials are licensed and made available under
9 the terms and conditions of the BSD License that accompanies this distribution.
10 The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 **/
16 #include <Uefi.h>
17 #include <Library/UefiLib.h>
18 #include <Library/DebugLib.h>
19
20 #include <Library/ShellCEntryLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/TimerLib.h>
23
24 #include <LibConfig.h>
25
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31 #include <MainData.h>
32 #include <unistd.h>
33
34 extern int main( int, char**);
35 extern int __sse2_available;
36
37 struct __MainData *gMD;
38
39 /* Worker function to keep GCC happy. */
40 void __main()
41 {
42 ;
43 }
44
45 /** Clean up data as required by the exit() function.
46
47 **/
48 void
49 exitCleanup(INTN ExitVal)
50 {
51 void (*CleanUp)(void); // Pointer to Cleanup Function
52 int i;
53
54 if(gMD != NULL) {
55 gMD->ExitValue = (int)ExitVal;
56 CleanUp = gMD->cleanup; // Preserve the pointer to the Cleanup Function
57
58 // Call all registered atexit functions in reverse order
59 i = gMD->num_atexit;
60 if( i > 0) {
61 do {
62 (gMD->atexit_handler[--i])();
63 } while( i > 0);
64 }
65
66 if (CleanUp != NULL) {
67 CleanUp();
68 }
69 }
70 }
71
72 /* Create mbcs versions of the Argv strings. */
73 static
74 char **
75 ArgvConvert(UINTN Argc, CHAR16 **Argv)
76 {
77 ssize_t AVsz; /* Size of a single nArgv string, or -1 */
78 UINTN count;
79 char **nArgv;
80 char *string;
81 INTN nArgvSize; /* Cumulative size of narrow Argv[i] */
82
83 DEBUG_CODE_BEGIN();
84 Print(L"ArgvConvert called with %d arguments.\n", Argc);
85 for(count = 0; count < ((Argc > 5)? 5: Argc); ++count) {
86 Print(L"Argument[%d] = \"%s\".\n", count, Argv[count]);
87 }
88 DEBUG_CODE_END();
89
90 nArgvSize = Argc;
91 /* Determine space needed for narrow Argv strings. */
92 for(count = 0; count < Argc; ++count) {
93 AVsz = (ssize_t)wcstombs(NULL, Argv[count], ARG_MAX);
94 if(AVsz < 0) {
95 Print(L"ABORTING: Argv[%d] contains an unconvertable character.\n", count);
96 exit(EXIT_FAILURE);
97 /* Not Reached */
98 }
99 nArgvSize += AVsz;
100 }
101
102 /* Reserve space for the converted strings. */
103 gMD->NCmdLine = (char *)AllocateZeroPool(nArgvSize+1);
104 if(gMD->NCmdLine == NULL) {
105 Print(L"ABORTING: Insufficient memory.\n");
106 exit(EXIT_FAILURE);
107 /* Not Reached */
108 }
109
110 /* Convert Argument Strings. */
111 nArgv = gMD->NArgV;
112 string = gMD->NCmdLine;
113 for(count = 0; count < Argc; ++count) {
114 nArgv[count] = string;
115 AVsz = wcstombs(string, Argv[count], nArgvSize);
116 string[AVsz] = 0; /* NULL terminate the argument */
117 DEBUG((DEBUG_INFO, "Cvt[%d] %d \"%s\" --> \"%a\"\n", (INT32)count, (INT32)AVsz, Argv[count], nArgv[count]));
118 string += AVsz + 1;
119 nArgvSize -= AVsz + 1;
120 if(nArgvSize < 0) {
121 Print(L"ABORTING: Internal Argv[%d] conversion error.\n", count);
122 exit(EXIT_FAILURE);
123 /* Not Reached */
124 }
125 }
126 return gMD->NArgV;
127 }
128
129 INTN
130 EFIAPI
131 ShellAppMain (
132 IN UINTN Argc,
133 IN CHAR16 **Argv
134 )
135 {
136 struct __filedes *mfd;
137 char **nArgv;
138 INTN ExitVal;
139 int i;
140
141 ExitVal = (INTN)RETURN_SUCCESS;
142 gMD = AllocateZeroPool(sizeof(struct __MainData));
143 if( gMD == NULL ) {
144 ExitVal = (INTN)RETURN_OUT_OF_RESOURCES;
145 }
146 else {
147 /* Initialize data */
148 __sse2_available = 0;
149 _fltused = 1;
150 errno = 0;
151 EFIerrno = 0;
152
153 gMD->ClocksPerSecond = 1;
154 gMD->AppStartTime = (clock_t)((UINT32)time(NULL));
155
156 // Initialize file descriptors
157 mfd = gMD->fdarray;
158 for(i = 0; i < (FOPEN_MAX); ++i) {
159 mfd[i].MyFD = (UINT16)i;
160 }
161
162 i = open("stdin:", O_RDONLY, 0444);
163 if(i == 0) {
164 i = open("stdout:", O_WRONLY, 0222);
165 if(i == 1) {
166 i = open("stderr:", O_WRONLY, 0222);
167 }
168 }
169 if(i != 2) {
170 Print(L"ERROR Initializing Standard IO: %a.\n %r\n",
171 strerror(errno), EFIerrno);
172 }
173
174 /* Create mbcs versions of the Argv strings. */
175 nArgv = ArgvConvert(Argc, Argv);
176 if(nArgv == NULL) {
177 ExitVal = (INTN)RETURN_INVALID_PARAMETER;
178 }
179 else {
180 if( setjmp(gMD->MainExit) == 0) {
181 ExitVal = (INTN)main( (int)Argc, gMD->NArgV);
182 exitCleanup(ExitVal);
183 }
184 /* You reach here if:
185 * normal return from main()
186 * call to _Exit(), either directly or through exit().
187 */
188 ExitVal = (INTN)gMD->ExitValue;
189 }
190
191 if( ExitVal == EXIT_FAILURE) {
192 ExitVal = RETURN_ABORTED;
193 }
194
195 /* Close any open files */
196 for(i = OPEN_MAX - 1; i >= 0; --i) {
197 (void)close(i); // Close properly handles closing a closed file.
198 }
199
200 /* Free the global MainData structure */
201 if(gMD != NULL) {
202 if(gMD->NCmdLine != NULL) {
203 FreePool( gMD->NCmdLine );
204 }
205 FreePool( gMD );
206 }
207 }
208 return ExitVal;
209 }