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