SHEL1
[efi/shell/.git] / date / date.c
1 /*++
2
3 Copyright (c) 2005, Intel Corporation                                                         
4 All rights reserved. This program and the accompanying materials                          
5 are licensed and made available under the terms and conditions of the BSD License         
6 which accompanies this distribution. The full text of the license may be found at         
7 http://opensource.org/licenses/bsd-license.php                                            
8                                                                                           
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
11
12 Module Name:
13
14   date.c
15
16 Abstract: 
17
18   shell command "date"
19
20 Revision History
21
22 --*/
23
24 #include "EfiShellLib.h"
25 #include "date.h"
26
27 extern UINT8  STRING_ARRAY_NAME[];
28
29 //
30 // This is the generated header file which includes whatever needs to be exported (strings + IFR)
31 //
32 #include STRING_DEFINES_FILE
33
34 //
35 // Global Variables
36 //
37 EFI_GUID  EfiDateGuid = EFI_DATE_GUID;
38
39 //
40 //
41 //
42 EFI_STATUS
43 InitializeDate (
44   IN EFI_HANDLE           ImageHandle,
45   IN EFI_SYSTEM_TABLE     *SystemTable
46   );
47
48 //
49 //
50 //
51 STATIC
52 BOOLEAN
53 GetNumber (
54   IN      CHAR16  *Str,
55   IN OUT  INTN    *Position,
56   IN OUT  INTN    *Number,
57   IN BOOLEAN      EndNum
58   );
59
60 STATIC
61 BOOLEAN
62 ValidDay (
63   IN  EFI_TIME  time
64   );
65
66 STATIC
67 BOOLEAN
68 IsLeapYear (
69   IN EFI_TIME   time
70   );
71
72 EFI_BOOTSHELL_CODE(
73   EFI_APPLICATION_ENTRY_POINT(InitializeDate)
74 )
75
76 INTN  DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
77 SHELL_VAR_CHECK_ITEM    DateCheckList[] = {
78   {
79     L"-b",
80     0x01,
81     0,
82     FlagTypeSingle
83   },
84   {
85     L"-?",
86     0x02,
87     0,
88     FlagTypeSingle
89   },
90   {
91     NULL,
92     0,
93     0,
94     0
95   }
96 };
97
98 //
99 //
100 //
101 EFI_STATUS
102 InitializeDate (
103   IN EFI_HANDLE           ImageHandle,
104   IN EFI_SYSTEM_TABLE     *SystemTable
105   )
106 /*++
107
108 Routine Description:
109   Display or set date
110   
111 Arguments:
112   ImageHandle     The image handle.
113   SystemTable     The system table.
114
115 Returns:
116   EFI_SUCCESS             - Command completed successfully
117   EFI_INVALID_PARAMETER   - Command usage error
118   Other value             - Unknown error
119   
120 Notes:  
121   date [mm/dd/yyyy]
122
123 --*/
124 {
125   EFI_STATUS              Status;
126   EFI_TIME                Time;
127   UINTN                   Offset;
128   UINTN                   Data;
129   EFI_HII_HANDLE          HiiHandle;
130   SHELL_VAR_CHECK_PACKAGE ChkPck;
131   CHAR16                  *Useful;
132   SHELL_VAR_CHECK_CODE    RetCode;
133
134   ZeroMem (&ChkPck, sizeof (SHELL_VAR_CHECK_PACKAGE));
135
136   EFI_SHELL_APP_INIT (ImageHandle, SystemTable);
137   //
138   // Register our string package with HII and return the handle to it.
139   // If previously registered we will simply receive the handle
140   //
141   Status = LibInitializeStrings (&HiiHandle, STRING_ARRAY_NAME, &EfiDateGuid);
142   if (EFI_ERROR (Status)) {
143     return Status;
144   }
145
146   if (!EFI_PROPER_VERSION (0, 99)) {
147     PrintToken (
148       STRING_TOKEN (STR_SHELLENV_GNC_COMMAND_NOT_SUPPORT),
149       HiiHandle,
150       L"date",
151       EFI_VERSION_0_99 
152       );
153     Status = EFI_UNSUPPORTED;
154     goto Done;
155   }
156
157   RetCode = LibCheckVariables (SI, DateCheckList, &ChkPck, &Useful);
158   if (VarCheckOk != RetCode) {
159     switch (RetCode) {
160     case VarCheckUnknown:
161       PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_UNKNOWN_FLAG), HiiHandle, L"date", Useful);
162       break;
163
164     case VarCheckDuplicate:
165       PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_DUP_FLAG), HiiHandle, L"date", Useful);
166       break;
167
168     default:
169       break;
170     }
171
172     Status = EFI_INVALID_PARAMETER;
173     goto Done;
174   }
175   //
176   // Out put help.
177   //
178   if (LibCheckVarGetFlag (&ChkPck, L"-b") != NULL) {
179     EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF);
180   }
181
182   if (LibCheckVarGetFlag (&ChkPck, L"-?") != NULL) {
183     if (IS_OLD_SHELL) {
184       PrintToken (STRING_TOKEN (STR_NO_HELP), HiiHandle);
185     } else if (ChkPck.ValueCount > 0 ||
186              ChkPck.FlagCount > 2 ||
187              (2 == ChkPck.FlagCount && !LibCheckVarGetFlag (&ChkPck, L"-b"))
188             ) {
189       PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_TOO_MANY), HiiHandle, L"date");
190       Status = EFI_INVALID_PARAMETER;
191     } else {
192       PrintToken (STRING_TOKEN (STR_DATE_VERBOSE_HELP), HiiHandle);
193       Status = EFI_SUCCESS;
194     }
195
196     goto Done;
197   }
198
199   if (ChkPck.ValueCount == 0) {
200     Status = RT->GetTime (&Time, NULL);
201     if (!EFI_ERROR (Status)) {
202       PrintToken (STRING_TOKEN (STR_DATE_PRINTDATE), HiiHandle, Time.Month, Time.Day, Time.Year);
203     } else {
204       PrintToken (STRING_TOKEN (STR_DATE_CLOCK_NOT_FUNC), HiiHandle);
205     }
206
207     goto Done;
208   }
209
210   if (ChkPck.ValueCount > 1) {
211     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_TOO_MANY), HiiHandle, L"date");
212     Status = EFI_INVALID_PARAMETER;
213     goto Done;
214   }
215   //
216   // Get current time
217   //
218   Status = RT->GetTime (&Time, NULL);
219   if (EFI_ERROR (Status)) {
220     //
221     // Error in GetTime, so set all fields of Timer to default value.
222     //
223     Time.Second = 0;
224     Time.Minute = 0;
225     Time.Hour   = 0;
226     Time.Day    = 1;
227     Time.Month  = 1;
228     Time.Year   = 2001;
229   }
230   //
231   // Init start number of argument and
232   // offset position in argument string
233   //
234   Offset = 0;
235
236   //
237   // Get month
238   //
239   if (!GetNumber (ChkPck.VarList->VarStr, &Offset, &Data, FALSE)) {
240     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_INVALID_ARG), HiiHandle, L"date", ChkPck.VarList->VarStr);
241     Status = EFI_INVALID_PARAMETER;
242     goto Done;
243   }
244
245   if (Data < 1 || Data > 12) {
246     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_INVALID_ARG), HiiHandle, L"date", ChkPck.VarList->VarStr);
247     Status = EFI_INVALID_PARAMETER;
248     goto Done;
249   }
250
251   Time.Month = (UINT8) Data;
252
253   //
254   // Get day
255   //
256   if (!GetNumber (ChkPck.VarList->VarStr, &Offset, &Data, FALSE)) {
257     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_INVALID_ARG), HiiHandle, L"date", ChkPck.VarList->VarStr);
258     Status = EFI_INVALID_PARAMETER;
259     goto Done;
260   }
261
262   if (Data < 1 || Data > 31) {
263     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_INVALID_ARG), HiiHandle, L"date", ChkPck.VarList->VarStr);
264     Status = EFI_INVALID_PARAMETER;
265     goto Done;
266   }
267
268   Time.Day = (UINT8) Data;
269
270   //
271   // Get year.
272   //
273   if (!GetNumber (ChkPck.VarList->VarStr, &Offset, &Data, TRUE)) {
274     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_INVALID_ARG), HiiHandle, L"date", ChkPck.VarList->VarStr);
275     Status = EFI_INVALID_PARAMETER;
276     goto Done;
277   }
278   //
279   // Minimal year number supported is 1998
280   //
281   if (Data < 100) {
282     Data = Data + 1900;
283     if (Data < 1998) {
284       Data = Data + 100;
285     }
286   }
287
288   if (Data < 1998 || Data > 2099) {
289     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_INVALID_ARG), HiiHandle, L"date", ChkPck.VarList->VarStr);
290     Status = EFI_INVALID_PARAMETER;
291     goto Done;
292   }
293
294   Time.Year = (UINT16) Data;
295
296   if (!ValidDay (Time)) {
297     PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_INVALID_ARG), HiiHandle, L"date", ChkPck.VarList->VarStr);
298     Status = EFI_INVALID_PARAMETER;
299     goto Done;
300   }
301
302   Status = RT->SetTime (&Time);
303   if (EFI_ERROR (Status)) {
304     PrintToken (STRING_TOKEN (STR_DATE_CLOCK_NOT_FUNC), HiiHandle);
305   }
306
307 Done:
308   LibCheckVarFreeVarList (&ChkPck);
309   LibUnInitializeStrings ();
310   return Status;
311 }
312 //
313 // Get number from arguments
314 //
315 STATIC
316 BOOLEAN
317 GetNumber (
318   IN      CHAR16    *Str,
319   IN OUT  INTN      *Position,
320   IN OUT  INTN      *Number,
321   IN BOOLEAN        EndNum
322   )
323 {
324   CHAR16  Char;
325   INTN    Data;
326   BOOLEAN FindNum;
327
328   Data    = 0;
329   FindNum = FALSE;
330
331   for (; Str[*Position] != '/' && Str[*Position] != 0; (*Position)++) {
332     Char = Str[*Position];
333     if (Char >= '0' && Char <= '9') {
334       FindNum = TRUE;
335       Data    = Data * 10 + (Char - '0');
336       //
337       // to aVOID data over-flow
338       //
339       if (Data > 10000) {
340         return FALSE;
341       }
342     } else {
343       //
344       // Any other characters regards as invalid
345       //
346       return FALSE;
347     }
348   }
349
350   if (!FindNum) {
351     return FALSE;
352   }
353
354   if ((Str[*Position] == '/' && EndNum) || (Str[*Position] == 0 && !EndNum)) {
355     return FALSE;
356   }
357
358   if (Str[*Position] == '/') {
359     (*Position)++;
360   }
361
362   *Number = Data;
363   return TRUE;
364 }
365
366 STATIC
367 BOOLEAN
368 ValidDay (
369   IN  EFI_TIME  time
370   )
371 {
372   if (time.Day > DayOfMonth[time.Month - 1]) {
373     return FALSE;
374   }
375   //
376   // Pay attention to month==2
377   //
378   if (time.Month == 2 && ((IsLeapYear (time) && time.Day > 29) || (!IsLeapYear (time) && time.Day > 28))) {
379     return FALSE;
380   }
381
382   return TRUE;
383 }
384
385 STATIC
386 BOOLEAN
387 IsLeapYear (
388   IN EFI_TIME   time
389   )
390 {
391   if (time.Year % 4 == 0) {
392     if (time.Year % 100 == 0) {
393       if (time.Year % 400 == 0) {
394         return TRUE;
395       } else {
396         return FALSE;
397       }
398     } else {
399       return TRUE;
400     }
401   } else {
402     return FALSE;
403   }
404 }
405
406 EFI_STATUS
407 InitializeDateGetLineHelp (
408   OUT CHAR16              **Str
409   )
410 /*++
411
412 Routine Description:
413
414   Get this command's line help
415
416 Arguments:
417
418   Str - The line help
419
420 Returns:
421
422   EFI_SUCCESS   - Success
423
424 --*/
425 {
426   return LibCmdGetStringByToken (STRING_ARRAY_NAME, &EfiDateGuid, STRING_TOKEN (STR_DATE_LINE_HELP), Str);
427 }