1 | /*++␍␊ |
2 | ␍␊ |
3 | Copyright (c) 1998 Intel Corporation␍␊ |
4 | ␍␊ |
5 | Module Name:␍␊ |
6 | ␍␊ |
7 | print.c␍␊ |
8 | ␍␊ |
9 | Abstract:␍␊ |
10 | ␍␊ |
11 | ␍␊ |
12 | ␍␊ |
13 | ␍␊ |
14 | Revision History␍␊ |
15 | ␍␊ |
16 | --*/␍␊ |
17 | #include <efi.h>␍␊ |
18 | ␍␊ |
19 | ␍␊ |
20 | ␍␊ |
21 | //␍␊ |
22 | //␍␊ |
23 | //␍␊ |
24 | ␍␊ |
25 | ␍␊ |
26 | #define PRINT_STRING_LEN 200␍␊ |
27 | #define PRINT_ITEM_BUFFER_LEN 100␍␊ |
28 | ␍␊ |
29 | typedef struct {␍␊ |
30 | BOOLEAN Ascii;␍␊ |
31 | UINTN Index;␍␊ |
32 | union {␍␊ |
33 | CHAR16 *pw;␍␊ |
34 | CHAR8 *pc;␍␊ |
35 | } un;␍␊ |
36 | } POINTER;␍␊ |
37 | ␍␊ |
38 | #define pw␉un.pw␍␊ |
39 | #define pc␉un.pc␍␊ |
40 | ␍␊ |
41 | typedef struct _pitem {␍␊ |
42 | ␍␊ |
43 | POINTER Item;␍␊ |
44 | CHAR16 Scratch[PRINT_ITEM_BUFFER_LEN];␍␊ |
45 | UINTN Width;␍␊ |
46 | UINTN FieldWidth;␍␊ |
47 | UINTN *WidthParse;␍␊ |
48 | CHAR16 Pad;␍␊ |
49 | BOOLEAN PadBefore;␍␊ |
50 | BOOLEAN Comma;␍␊ |
51 | BOOLEAN Long;␍␊ |
52 | } PRINT_ITEM;␍␊ |
53 | ␍␊ |
54 | ␍␊ |
55 | typedef struct _pstate {␍␊ |
56 | // Input␍␊ |
57 | POINTER fmt;␍␊ |
58 | va_list args;␍␊ |
59 | ␍␊ |
60 | // Output␍␊ |
61 | CHAR16 *Buffer;␍␊ |
62 | CHAR16 *End;␍␊ |
63 | CHAR16 *Pos;␍␊ |
64 | UINTN Len;␍␊ |
65 | ␍␊ |
66 | UINTN Attr;␍␊ |
67 | UINTN RestoreAttr;␍␊ |
68 | ␍␊ |
69 | UINTN AttrNorm;␍␊ |
70 | UINTN AttrHighlight;␍␊ |
71 | UINTN AttrError;␍␊ |
72 | ␍␊ |
73 | INTN (*Output)(VOID *context, CHAR16 *str);␍␊ |
74 | INTN (*SetAttr)(VOID *context, UINTN attr);␍␊ |
75 | VOID *Context;␍␊ |
76 | ␍␊ |
77 | // Current item being formatted␍␊ |
78 | struct _pitem *Item;␍␊ |
79 | } PRINT_STATE;␍␊ |
80 | ␍␊ |
81 | ␍␊ |
82 | //␍␊ |
83 | //␍␊ |
84 | //␍␊ |
85 | ␍␊ |
86 | STATIC␍␊ |
87 | UINTN␍␊ |
88 | _Print (␍␊ |
89 | IN PRINT_STATE *ps␍␊ |
90 | );␍␊ |
91 | ␍␊ |
92 | ␍␊ |
93 | INTN␍␊ |
94 | _SPrint (␍␊ |
95 | IN VOID *Context,␍␊ |
96 | IN CHAR16 *Buffer␍␊ |
97 | );␍␊ |
98 | ␍␊ |
99 | INTN␍␊ |
100 | _PoolPrint (␍␊ |
101 | IN VOID *Context,␍␊ |
102 | IN CHAR16 *Buffer␍␊ |
103 | );␍␊ |
104 | ␍␊ |
105 | VOID␍␊ |
106 | _PoolCatPrint (␍␊ |
107 | IN CHAR16 *fmt,␍␊ |
108 | IN va_list args,␍␊ |
109 | IN OUT POOL_PRINT *spc,␍␊ |
110 | IN INTN (*Output)(VOID *context, CHAR16 *str)␍␊ |
111 | );␍␊ |
112 | ␍␊ |
113 | VOID␍␊ |
114 | _PoolCatPrint (␍␊ |
115 | IN CHAR16 *fmt,␍␊ |
116 | IN va_list args,␍␊ |
117 | IN OUT POOL_PRINT *spc,␍␊ |
118 | IN INTN (*Output)(VOID *context, CHAR16 *str)␍␊ |
119 | )␍␊ |
120 | // Dispath function for SPrint, PoolPrint, and CatPrint␍␊ |
121 | {␍␊ |
122 | PRINT_STATE ps;␍␊ |
123 | ␍␊ |
124 | ZeroMem (&ps, sizeof(ps));␍␊ |
125 | ps.Output = Output;␍␊ |
126 | ps.Context = spc;␍␊ |
127 | ps.fmt.pw = fmt;␍␊ |
128 | va_copy(ps.args, args);␍␊ |
129 | _Print (&ps);␍␊ |
130 | va_end(ps.args);␍␊ |
131 | }␍␊ |
132 | ␍␊ |
133 | ␍␊ |
134 | INTN␍␊ |
135 | _SPrint (␍␊ |
136 | IN VOID *Context,␍␊ |
137 | IN CHAR16 *Buffer␍␊ |
138 | )␍␊ |
139 | // Append string worker for SPrint, PoolPrint and CatPrint␍␊ |
140 | {␍␊ |
141 | UINTN len;␍␊ |
142 | POOL_PRINT *spc;␍␊ |
143 | ␍␊ |
144 | spc = Context;␍␊ |
145 | len = StrLen(Buffer);␍␊ |
146 | ␍␊ |
147 | //␍␊ |
148 | // Is the string is over the max truncate it␍␊ |
149 | //␍␊ |
150 | ␍␊ |
151 | if (spc->len + len > spc->maxlen) {␍␊ |
152 | len = spc->maxlen - spc->len;␍␊ |
153 | }␍␊ |
154 | ␍␊ |
155 | //␍␊ |
156 | // Append the new text␍␊ |
157 | //␍␊ |
158 | ␍␊ |
159 | CopyMem (spc->str + spc->len, Buffer, len * sizeof(CHAR16));␍␊ |
160 | spc->len += len;␍␊ |
161 | ␍␊ |
162 | //␍␊ |
163 | // Null terminate it␍␊ |
164 | //␍␊ |
165 | ␍␊ |
166 | if (spc->len < spc->maxlen) {␍␊ |
167 | spc->str[spc->len] = 0;␍␊ |
168 | } else if (spc->maxlen) {␍␊ |
169 | spc->str[spc->maxlen-1] = 0;␍␊ |
170 | }␍␊ |
171 | ␍␊ |
172 | return 0;␍␊ |
173 | }␍␊ |
174 | ␍␊ |
175 | ␍␊ |
176 | INTN␍␊ |
177 | _PoolPrint (␍␊ |
178 | IN VOID *Context,␍␊ |
179 | IN CHAR16 *Buffer␍␊ |
180 | )␍␊ |
181 | // Append string worker for PoolPrint and CatPrint␍␊ |
182 | {␍␊ |
183 | UINTN newlen;␍␊ |
184 | POOL_PRINT *spc;␍␊ |
185 | ␍␊ |
186 | spc = Context;␍␊ |
187 | newlen = spc->len + StrLen(Buffer) + 1;␍␊ |
188 | ␍␊ |
189 | //␍␊ |
190 | // Is the string is over the max, grow the buffer␍␊ |
191 | //␍␊ |
192 | ␍␊ |
193 | if (newlen > spc->maxlen) {␍␊ |
194 | ␍␊ |
195 | //␍␊ |
196 | // Grow the pool buffer␍␊ |
197 | //␍␊ |
198 | ␍␊ |
199 | newlen += PRINT_STRING_LEN;␍␊ |
200 | spc->maxlen = newlen;␍␊ |
201 | spc->str = ReallocatePool ( ␍␊ |
202 | spc->len * sizeof(CHAR16),␍␊ |
203 | spc->maxlen * sizeof(CHAR16),␍␊ |
204 | spc->str␍␊ |
205 | );␍␊ |
206 | ␍␊ |
207 | if (!spc->str) {␍␊ |
208 | spc->len = 0;␍␊ |
209 | spc->maxlen = 0;␍␊ |
210 | }␍␊ |
211 | }␍␊ |
212 | ␍␊ |
213 | //␍␊ |
214 | // Append the new text␍␊ |
215 | //␍␊ |
216 | ␍␊ |
217 | return _SPrint (Context, Buffer);␍␊ |
218 | }␍␊ |
219 | ␍␊ |
220 | ␍␊ |
221 | ␍␊ |
222 | ␍␊ |
223 | UINTN␍␊ |
224 | SPrint (␍␊ |
225 | OUT CHAR16 *Str,␍␊ |
226 | IN UINTN StrSize,␍␊ |
227 | IN CHAR16 *fmt,␍␊ |
228 | ...␍␊ |
229 | )␍␊ |
230 | /*++␍␊ |
231 | ␍␊ |
232 | Routine Description:␍␊ |
233 | ␍␊ |
234 | Prints a formatted unicode string to a buffer␍␊ |
235 | ␍␊ |
236 | Arguments:␍␊ |
237 | ␍␊ |
238 | Str - Output buffer to print the formatted string into␍␊ |
239 | ␍␊ |
240 | StrSize - Size of Str. String is truncated to this size.␍␊ |
241 | A size of 0 means there is no limit␍␊ |
242 | ␍␊ |
243 | fmt - The format string␍␊ |
244 | ␍␊ |
245 | Returns:␍␊ |
246 | ␍␊ |
247 | String length returned in buffer␍␊ |
248 | ␍␊ |
249 | --*/␍␊ |
250 | {␍␊ |
251 | POOL_PRINT spc;␍␊ |
252 | va_list args;␍␊ |
253 | ␍␊ |
254 | ␍␊ |
255 | va_start (args, fmt);␍␊ |
256 | spc.str = Str;␍␊ |
257 | spc.maxlen = StrSize / sizeof(CHAR16) - 1;␍␊ |
258 | spc.len = 0;␍␊ |
259 | ␍␊ |
260 | _PoolCatPrint (fmt, args, &spc, _SPrint);␍␊ |
261 | va_end (args);␍␊ |
262 | return spc.len;␍␊ |
263 | }␍␊ |
264 | ␍␊ |
265 | ␍␊ |
266 | CHAR16 *␍␊ |
267 | PoolPrint (␍␊ |
268 | IN CHAR16 *fmt,␍␊ |
269 | ...␍␊ |
270 | )␍␊ |
271 | /*++␍␊ |
272 | ␍␊ |
273 | Routine Description:␍␊ |
274 | ␍␊ |
275 | Prints a formatted unicode string to allocated pool. The caller␍␊ |
276 | must free the resulting buffer.␍␊ |
277 | ␍␊ |
278 | Arguments:␍␊ |
279 | ␍␊ |
280 | fmt - The format string␍␊ |
281 | ␍␊ |
282 | Returns:␍␊ |
283 | ␍␊ |
284 | Allocated buffer with the formatted string printed in it.␍␊ |
285 | The caller must free the allocated buffer. The buffer␍␊ |
286 | allocation is not packed.␍␊ |
287 | ␍␊ |
288 | --*/␍␊ |
289 | {␍␊ |
290 | POOL_PRINT spc;␍␊ |
291 | va_list args;␍␊ |
292 | ␍␊ |
293 | ZeroMem (&spc, sizeof(spc));␍␊ |
294 | va_start (args, fmt);␍␊ |
295 | _PoolCatPrint (fmt, args, &spc, _PoolPrint);␍␊ |
296 | va_end (args);␍␊ |
297 | return spc.str;␍␊ |
298 | }␍␊ |
299 | ␍␊ |
300 | ␍␊ |
301 | ␍␊ |
302 | CHAR16 *␍␊ |
303 | CatPrint (␍␊ |
304 | IN OUT POOL_PRINT *Str,␍␊ |
305 | IN CHAR16 *fmt,␍␊ |
306 | ...␍␊ |
307 | )␍␊ |
308 | /*++␍␊ |
309 | ␍␊ |
310 | Routine Description:␍␊ |
311 | ␍␊ |
312 | Concatenates a formatted unicode string to allocated pool.␍␊ |
313 | The caller must free the resulting buffer.␍␊ |
314 | ␍␊ |
315 | Arguments:␍␊ |
316 | ␍␊ |
317 | Str - Tracks the allocated pool, size in use, and␍␊ |
318 | amount of pool allocated.␍␊ |
319 | ␍␊ |
320 | fmt - The format string␍␊ |
321 | ␍␊ |
322 | Returns:␍␊ |
323 | ␍␊ |
324 | Allocated buffer with the formatted string printed in it.␍␊ |
325 | The caller must free the allocated buffer. The buffer␍␊ |
326 | allocation is not packed.␍␊ |
327 | ␍␊ |
328 | --*/␍␊ |
329 | {␍␊ |
330 | va_list args;␍␊ |
331 | ␍␊ |
332 | va_start (args, fmt);␍␊ |
333 | _PoolCatPrint (fmt, args, Str, _PoolPrint);␍␊ |
334 | va_end (args);␍␊ |
335 | return Str->str;␍␊ |
336 | }␍␊ |
337 | ␍␊ |
338 | ␍␊ |
339 | VOID␍␊ |
340 | TimeToString (␍␊ |
341 | OUT CHAR16 *Buffer,␍␊ |
342 | IN EFI_TIME *Time␍␊ |
343 | )␍␊ |
344 | {␍␊ |
345 | UINTN Hour, Year;␍␊ |
346 | CHAR16 AmPm;␍␊ |
347 | ␍␊ |
348 | AmPm = 'a';␍␊ |
349 | Hour = Time->Hour;␍␊ |
350 | if (Time->Hour == 0) {␍␊ |
351 | Hour = 12;␍␊ |
352 | } else if (Time->Hour >= 12) {␍␊ |
353 | AmPm = 'p';␍␊ |
354 | if (Time->Hour >= 13) {␍␊ |
355 | Hour -= 12;␍␊ |
356 | }␍␊ |
357 | }␍␊ |
358 | ␍␊ |
359 | Year = Time->Year % 100;␍␊ |
360 | ␍␊ |
361 | // bugbug: for now just print it any old way␍␊ |
362 | SPrint (Buffer, 0, L"%02d/%02d/%02d %02d:%02d%c",␍␊ |
363 | Time->Month,␍␊ |
364 | Time->Day,␍␊ |
365 | Year,␍␊ |
366 | Hour,␍␊ |
367 | Time->Minute,␍␊ |
368 | AmPm␍␊ |
369 | );␍␊ |
370 | }␍␊ |
371 | ␍␊ |
372 | STATIC␍␊ |
373 | VOID␍␊ |
374 | PFLUSH (␍␊ |
375 | IN OUT PRINT_STATE *ps␍␊ |
376 | )␍␊ |
377 | {␍␊ |
378 | *ps->Pos = 0;␍␊ |
379 | //if (IsLocalPrint(ps->Output))␍␊ |
380 | ps->Output(ps->Context, ps->Buffer);␍␊ |
381 | //else␍␊ |
382 | //␉uefi_call_wrapper(ps->Output, 2, ps->Context, ps->Buffer);␍␊ |
383 | ps->Pos = ps->Buffer;␍␊ |
384 | }␍␊ |
385 | ␍␊ |
386 | STATIC␍␊ |
387 | VOID␍␊ |
388 | PSETATTR (␍␊ |
389 | IN OUT PRINT_STATE *ps,␍␊ |
390 | IN UINTN Attr␍␊ |
391 | )␍␊ |
392 | {␍␊ |
393 | PFLUSH (ps);␍␊ |
394 | ␍␊ |
395 | ps->RestoreAttr = ps->Attr;␍␊ |
396 | //if (ps->SetAttr) {␍␊ |
397 | // uefi_call_wrapper(ps->SetAttr, 2, ps->Context, Attr);␍␊ |
398 | //}␍␊ |
399 | ␍␊ |
400 | ps->Attr = Attr;␍␊ |
401 | }␍␊ |
402 | ␍␊ |
403 | STATIC␍␊ |
404 | VOID␍␊ |
405 | PPUTC (␍␊ |
406 | IN OUT PRINT_STATE *ps,␍␊ |
407 | IN CHAR16 c␍␊ |
408 | )␍␊ |
409 | {␍␊ |
410 | // if this is a newline, add a carraige return␍␊ |
411 | if (c == '\n') {␍␊ |
412 | PPUTC (ps, '\r');␍␊ |
413 | }␍␊ |
414 | ␍␊ |
415 | *ps->Pos = c;␍␊ |
416 | ps->Pos += 1;␍␊ |
417 | ps->Len += 1;␍␊ |
418 | ␍␊ |
419 | // if at the end of the buffer, flush it␍␊ |
420 | if (ps->Pos >= ps->End) {␍␊ |
421 | PFLUSH(ps);␍␊ |
422 | }␍␊ |
423 | }␍␊ |
424 | ␍␊ |
425 | ␍␊ |
426 | STATIC␍␊ |
427 | CHAR16␍␊ |
428 | PGETC (␍␊ |
429 | IN POINTER *p␍␊ |
430 | )␍␊ |
431 | {␍␊ |
432 | CHAR16 c;␍␊ |
433 | ␍␊ |
434 | c = p->Ascii ? p->pc[p->Index] : p->pw[p->Index];␍␊ |
435 | p->Index += 1;␍␊ |
436 | ␍␊ |
437 | return c;␍␊ |
438 | }␍␊ |
439 | ␍␊ |
440 | ␍␊ |
441 | STATIC␍␊ |
442 | VOID␍␊ |
443 | PITEM (␍␊ |
444 | IN OUT PRINT_STATE *ps␍␊ |
445 | )␍␊ |
446 | {␍␊ |
447 | UINTN Len, i;␍␊ |
448 | PRINT_ITEM *Item;␍␊ |
449 | CHAR16 c;␍␊ |
450 | ␍␊ |
451 | // Get the length of the item␍␊ |
452 | Item = ps->Item;␍␊ |
453 | Item->Item.Index = 0;␍␊ |
454 | while (Item->Item.Index < Item->FieldWidth) {␍␊ |
455 | c = PGETC(&Item->Item);␍␊ |
456 | if (!c) {␍␊ |
457 | Item->Item.Index -= 1;␍␊ |
458 | break;␍␊ |
459 | }␍␊ |
460 | }␍␊ |
461 | Len = Item->Item.Index;␍␊ |
462 | ␍␊ |
463 | // if there is no item field width, use the items width␍␊ |
464 | if (Item->FieldWidth == (UINTN) -1) {␍␊ |
465 | Item->FieldWidth = Len;␍␊ |
466 | }␍␊ |
467 | ␍␊ |
468 | // if item is larger then width, update width␍␊ |
469 | if (Len > Item->Width) {␍␊ |
470 | Item->Width = Len;␍␊ |
471 | }␍␊ |
472 | ␍␊ |
473 | ␍␊ |
474 | // if pad field before, add pad char␍␊ |
475 | if (Item->PadBefore) {␍␊ |
476 | for (i=Item->Width; i < Item->FieldWidth; i+=1) {␍␊ |
477 | PPUTC (ps, ' ');␍␊ |
478 | }␍␊ |
479 | }␍␊ |
480 | ␍␊ |
481 | // pad item␍␊ |
482 | for (i=Len; i < Item->Width; i++) {␍␊ |
483 | PPUTC (ps, Item->Pad);␍␊ |
484 | }␍␊ |
485 | ␍␊ |
486 | // add the item␍␊ |
487 | Item->Item.Index=0;␍␊ |
488 | while (Item->Item.Index < Len) {␍␊ |
489 | PPUTC (ps, PGETC(&Item->Item));␍␊ |
490 | }␍␊ |
491 | ␍␊ |
492 | // If pad at the end, add pad char␍␊ |
493 | if (!Item->PadBefore) {␍␊ |
494 | for (i=Item->Width; i < Item->FieldWidth; i+=1) {␍␊ |
495 | PPUTC (ps, ' ');␍␊ |
496 | }␍␊ |
497 | }␍␊ |
498 | }␍␊ |
499 | ␍␊ |
500 | STATIC␍␊ |
501 | UINTN␍␊ |
502 | _Print (␍␊ |
503 | IN PRINT_STATE *ps␍␊ |
504 | )␍␊ |
505 | /*++␍␊ |
506 | ␍␊ |
507 | Routine Description:␍␊ |
508 | ␍␊ |
509 | %w.lF - w = width␍␊ |
510 | l = field width␍␊ |
511 | F = format of arg␍␊ |
512 | ␍␊ |
513 | Args F:␍␊ |
514 | 0 - pad with zeros␍␊ |
515 | - - justify on left (default is on right)␍␊ |
516 | , - add comma's to field␍␊ |
517 | * - width provided on stack␍␊ |
518 | n - Set output attribute to normal (for this field only)␍␊ |
519 | h - Set output attribute to highlight (for this field only)␍␊ |
520 | e - Set output attribute to error (for this field only)␍␊ |
521 | l - Value is 64 bits␍␊ |
522 | ␍␊ |
523 | a - ascii string␍␊ |
524 | s - unicode string␍␊ |
525 | X - fixed 8 byte value in hex␍␊ |
526 | x - hex value␍␊ |
527 | d - value as decimal␍␊ |
528 | c - Unicode char␍␊ |
529 | t - EFI time structure␍␊ |
530 | g - Pointer to GUID␍␊ |
531 | r - EFI status code (result code)␍␊ |
532 | ␍␊ |
533 | N - Set output attribute to normal␍␊ |
534 | H - Set output attribute to highlight␍␊ |
535 | E - Set output attribute to error␍␊ |
536 | % - Print a %␍␊ |
537 | ␍␊ |
538 | Arguments:␍␊ |
539 | ␍␊ |
540 | SystemTable - The system table␍␊ |
541 | ␍␊ |
542 | Returns:␍␊ |
543 | ␍␊ |
544 | Number of charactors written␍␊ |
545 | ␍␊ |
546 | --*/␍␊ |
547 | {␍␊ |
548 | CHAR16 c;␍␊ |
549 | UINTN Attr;␍␊ |
550 | PRINT_ITEM Item;␍␊ |
551 | CHAR16 Buffer[PRINT_STRING_LEN];␍␊ |
552 | ␍␊ |
553 | ps->Len = 0;␍␊ |
554 | ps->Buffer = Buffer;␍␊ |
555 | ps->Pos = Buffer;␍␊ |
556 | ps->End = Buffer + PRINT_STRING_LEN - 1;␍␊ |
557 | ps->Item = &Item;␍␊ |
558 | ␍␊ |
559 | ps->fmt.Index = 0;␍␊ |
560 | while ((c = PGETC(&ps->fmt))) {␍␊ |
561 | ␍␊ |
562 | if (c != '%') {␍␊ |
563 | PPUTC ( ps, c );␍␊ |
564 | continue;␍␊ |
565 | }␍␊ |
566 | ␍␊ |
567 | // setup for new item␍␊ |
568 | Item.FieldWidth = (UINTN) -1;␍␊ |
569 | Item.Width = 0;␍␊ |
570 | Item.WidthParse = &Item.Width;␍␊ |
571 | Item.Pad = ' ';␍␊ |
572 | Item.PadBefore = TRUE;␍␊ |
573 | Item.Comma = FALSE;␍␊ |
574 | Item.Long = FALSE;␍␊ |
575 | Item.Item.Ascii = FALSE;␍␊ |
576 | Item.Item.pw = NULL;␍␊ |
577 | ps->RestoreAttr = 0;␍␊ |
578 | Attr = 0;␍␊ |
579 | ␍␊ |
580 | while ((c = PGETC(&ps->fmt))) {␍␊ |
581 | ␍␊ |
582 | switch (c) {␍␊ |
583 | ␍␊ |
584 | case '%':␍␊ |
585 | //␍␊ |
586 | // %% -> %␍␊ |
587 | //␍␊ |
588 | Item.Item.pw = Item.Scratch;␍␊ |
589 | Item.Item.pw[0] = '%';␍␊ |
590 | Item.Item.pw[1] = 0;␍␊ |
591 | break;␍␊ |
592 | ␍␊ |
593 | case '0':␍␊ |
594 | Item.Pad = '0';␍␊ |
595 | break;␍␊ |
596 | ␍␊ |
597 | case '-':␍␊ |
598 | Item.PadBefore = FALSE;␍␊ |
599 | break;␍␊ |
600 | ␍␊ |
601 | case ',':␍␊ |
602 | Item.Comma = TRUE;␍␊ |
603 | break;␍␊ |
604 | ␍␊ |
605 | case '.':␍␊ |
606 | Item.WidthParse = &Item.FieldWidth;␍␊ |
607 | break;␍␊ |
608 | ␍␊ |
609 | case '*':␍␊ |
610 | *Item.WidthParse = va_arg(ps->args, UINTN);␍␊ |
611 | break;␍␊ |
612 | ␍␊ |
613 | case '1':␍␊ |
614 | case '2':␍␊ |
615 | case '3':␍␊ |
616 | case '4':␍␊ |
617 | case '5':␍␊ |
618 | case '6':␍␊ |
619 | case '7':␍␊ |
620 | case '8':␍␊ |
621 | case '9':␍␊ |
622 | *Item.WidthParse = 0;␍␊ |
623 | do {␍␊ |
624 | *Item.WidthParse = *Item.WidthParse * 10 + c - '0';␍␊ |
625 | c = PGETC(&ps->fmt);␍␊ |
626 | } while (c >= '0' && c <= '9') ;␍␊ |
627 | ps->fmt.Index -= 1;␍␊ |
628 | break;␍␊ |
629 | ␍␊ |
630 | case 'a':␍␊ |
631 | Item.Item.pc = va_arg(ps->args, CHAR8 *);␍␊ |
632 | Item.Item.Ascii = TRUE;␍␊ |
633 | if (!Item.Item.pc) {␍␊ |
634 | Item.Item.pc = (CHAR8 *)"(null)";␍␊ |
635 | }␍␊ |
636 | break;␍␊ |
637 | ␍␊ |
638 | case 's':␍␊ |
639 | Item.Item.pw = va_arg(ps->args, CHAR16 *);␍␊ |
640 | if (!Item.Item.pw) {␍␊ |
641 | Item.Item.pw = L"(null)";␍␊ |
642 | }␍␊ |
643 | break;␍␊ |
644 | ␍␊ |
645 | case 'c':␍␊ |
646 | Item.Item.pw = Item.Scratch;␍␊ |
647 | Item.Item.pw[0] = (CHAR16) va_arg(ps->args, UINTN);␍␊ |
648 | Item.Item.pw[1] = 0;␍␊ |
649 | break;␍␊ |
650 | ␍␊ |
651 | case 'l':␍␊ |
652 | Item.Long = TRUE;␍␊ |
653 | break;␍␊ |
654 | ␍␊ |
655 | case 'X':␍␊ |
656 | Item.Width = Item.Long ? 16 : 8;␍␊ |
657 | Item.Pad = '0';␍␊ |
658 | case 'x':␍␊ |
659 | Item.Item.pw = Item.Scratch;␍␊ |
660 | ValueToHex (␍␊ |
661 | Item.Item.pw,␍␊ |
662 | Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)␍␊ |
663 | );␍␊ |
664 | ␍␊ |
665 | break;␍␊ |
666 | ␍␊ |
667 | ␍␊ |
668 | case 'g':␍␊ |
669 | //Item.Item.pw = Item.Scratch;␍␊ |
670 | //GuidToString (Item.Item.pw, va_arg(ps->args, EFI_GUID *));␍␊ |
671 | break;␍␊ |
672 | ␍␊ |
673 | case 'd':␍␊ |
674 | Item.Item.pw = Item.Scratch;␍␊ |
675 | ValueToString (␍␊ |
676 | Item.Item.pw,␍␊ |
677 | Item.Comma,␍␊ |
678 | Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)␍␊ |
679 | );␍␊ |
680 | break␍␊ |
681 | ;␍␊ |
682 | case 't':␍␊ |
683 | Item.Item.pw = Item.Scratch;␍␊ |
684 | TimeToString (Item.Item.pw, va_arg(ps->args, EFI_TIME *));␍␊ |
685 | break;␍␊ |
686 | ␍␊ |
687 | case 'r':␍␊ |
688 | Item.Item.pw = Item.Scratch;␍␊ |
689 | StatusToString (Item.Item.pw, va_arg(ps->args, EFI_STATUS));␍␊ |
690 | break;␍␊ |
691 | ␍␊ |
692 | case 'n':␍␊ |
693 | PSETATTR(ps, ps->AttrNorm);␍␊ |
694 | break;␍␊ |
695 | ␍␊ |
696 | case 'h':␍␊ |
697 | PSETATTR(ps, ps->AttrHighlight);␍␊ |
698 | break;␍␊ |
699 | ␍␊ |
700 | case 'e':␍␊ |
701 | PSETATTR(ps, ps->AttrError);␍␊ |
702 | break;␍␊ |
703 | ␍␊ |
704 | case 'N':␍␊ |
705 | Attr = ps->AttrNorm;␍␊ |
706 | break;␍␊ |
707 | ␍␊ |
708 | case 'H':␍␊ |
709 | Attr = ps->AttrHighlight;␍␊ |
710 | break;␍␊ |
711 | ␍␊ |
712 | case 'E':␍␊ |
713 | Attr = ps->AttrError;␍␊ |
714 | break;␍␊ |
715 | ␍␊ |
716 | default:␍␊ |
717 | Item.Item.pw = Item.Scratch;␍␊ |
718 | Item.Item.pw[0] = '?';␍␊ |
719 | Item.Item.pw[1] = 0;␍␊ |
720 | break;␍␊ |
721 | }␍␊ |
722 | ␍␊ |
723 | // if we have an Item␍␊ |
724 | if (Item.Item.pw) {␍␊ |
725 | PITEM (ps);␍␊ |
726 | break;␍␊ |
727 | }␍␊ |
728 | ␍␊ |
729 | // if we have an Attr set␍␊ |
730 | if (Attr) {␍␊ |
731 | PSETATTR(ps, Attr);␍␊ |
732 | ps->RestoreAttr = 0;␍␊ |
733 | break;␍␊ |
734 | }␍␊ |
735 | }␍␊ |
736 | ␍␊ |
737 | if (ps->RestoreAttr) {␍␊ |
738 | PSETATTR(ps, ps->RestoreAttr);␍␊ |
739 | }␍␊ |
740 | }␍␊ |
741 | ␍␊ |
742 | // Flush buffer␍␊ |
743 | PFLUSH (ps);␍␊ |
744 | return ps->Len;␍␊ |
745 | }␍␊ |
746 | ␍␊ |
747 | STATIC CHAR8 Hex[] = {'0','1','2','3','4','5','6','7',␍␊ |
748 | '8','9','A','B','C','D','E','F'};␍␊ |
749 | ␍␊ |
750 | VOID␍␊ |
751 | ValueToHex (␍␊ |
752 | IN CHAR16 *Buffer,␍␊ |
753 | IN UINT64 v␍␊ |
754 | )␍␊ |
755 | {␍␊ |
756 | CHAR8 str[30], *p1;␍␊ |
757 | CHAR16 *p2;␍␊ |
758 | ␍␊ |
759 | if (!v) {␍␊ |
760 | Buffer[0] = '0';␍␊ |
761 | Buffer[1] = 0;␍␊ |
762 | return ;␍␊ |
763 | }␍␊ |
764 | ␍␊ |
765 | p1 = str;␍␊ |
766 | p2 = Buffer;␍␊ |
767 | ␍␊ |
768 | while (v) {␍␊ |
769 | *(p1++) = Hex[v & 0xf];␍␊ |
770 | v = RShiftU64 (v, 4);␍␊ |
771 | }␍␊ |
772 | ␍␊ |
773 | while (p1 != str) {␍␊ |
774 | *(p2++) = *(--p1);␍␊ |
775 | }␍␊ |
776 | *p2 = 0;␍␊ |
777 | }␍␊ |
778 | ␍␊ |
779 | ␍␊ |
780 | VOID␍␊ |
781 | ValueToString (␍␊ |
782 | IN CHAR16 *Buffer,␍␊ |
783 | IN BOOLEAN Comma,␍␊ |
784 | IN INT64 v␍␊ |
785 | )␍␊ |
786 | {␍␊ |
787 | STATIC CHAR8 ca[] = { 3, 1, 2 };␍␊ |
788 | CHAR8 str[40], *p1;␍␊ |
789 | CHAR16 *p2;␍␊ |
790 | UINTN c, r;␍␊ |
791 | ␍␊ |
792 | if (!v) {␍␊ |
793 | Buffer[0] = '0';␍␊ |
794 | Buffer[1] = 0;␍␊ |
795 | return ;␍␊ |
796 | }␍␊ |
797 | ␍␊ |
798 | p1 = str;␍␊ |
799 | p2 = Buffer;␍␊ |
800 | ␍␊ |
801 | if (v < 0) {␍␊ |
802 | *(p2++) = '-';␍␊ |
803 | v = -v;␍␊ |
804 | }␍␊ |
805 | ␍␊ |
806 | while (v) {␍␊ |
807 | v = (INT64)DivU64x32 ((UINT64)v, 10, &r);␍␊ |
808 | *(p1++) = (CHAR8)r + '0';␍␊ |
809 | }␍␊ |
810 | ␍␊ |
811 | c = (Comma ? ca[(p1 - str) % 3] : 999) + 1;␍␊ |
812 | while (p1 != str) {␍␊ |
813 | ␍␊ |
814 | c -= 1;␍␊ |
815 | if (!c) {␍␊ |
816 | *(p2++) = ',';␍␊ |
817 | c = 3;␍␊ |
818 | }␍␊ |
819 | ␍␊ |
820 | *(p2++) = *(--p1);␍␊ |
821 | }␍␊ |
822 | *p2 = 0;␍␊ |
823 | }␍␊ |
824 | ␍␊ |
825 | struct {␍␊ |
826 | EFI_STATUS Code;␍␊ |
827 | CHAR_W␉ *Desc;␍␊ |
828 | } ErrorCodeTable[] = {␍␊ |
829 | ␉{ EFI_SUCCESS, L"Success"},␍␊ |
830 | ␉{ EFI_LOAD_ERROR, L"Load Error"},␍␊ |
831 | ␉{ EFI_INVALID_PARAMETER, L"Invalid Parameter"},␍␊ |
832 | ␉{ EFI_UNSUPPORTED, L"Unsupported"},␍␊ |
833 | ␉{ EFI_BAD_BUFFER_SIZE, L"Bad Buffer Size"},␍␊ |
834 | ␉{ EFI_BUFFER_TOO_SMALL, L"Buffer Too Small"},␍␊ |
835 | ␉{ EFI_NOT_READY, L"Not Ready"},␍␊ |
836 | ␉{ EFI_DEVICE_ERROR, L"Device Error"},␍␊ |
837 | ␉{ EFI_WRITE_PROTECTED, L"Write Protected"},␍␊ |
838 | ␉{ EFI_OUT_OF_RESOURCES, L"Out of Resources"},␍␊ |
839 | ␉{ EFI_VOLUME_CORRUPTED, L"Volume Corrupt"},␍␊ |
840 | ␉{ EFI_VOLUME_FULL, L"Volume Full"},␍␊ |
841 | ␉{ EFI_NO_MEDIA, L"No Media"},␍␊ |
842 | ␉{ EFI_MEDIA_CHANGED, L"Media changed"},␍␊ |
843 | ␉{ EFI_NOT_FOUND, L"Not Found"},␍␊ |
844 | ␉{ EFI_ACCESS_DENIED, L"Access Denied"},␍␊ |
845 | ␉{ EFI_NO_RESPONSE, L"No Response"},␍␊ |
846 | ␉{ EFI_NO_MAPPING, L"No mapping"},␍␊ |
847 | ␉{ EFI_TIMEOUT, L"Time out"},␍␊ |
848 | ␉{ EFI_NOT_STARTED, L"Not started"},␍␊ |
849 | ␉{ EFI_ALREADY_STARTED, L"Already started"},␍␊ |
850 | ␉{ EFI_ABORTED, L"Aborted"},␍␊ |
851 | ␉{ EFI_ICMP_ERROR, L"ICMP Error"},␍␊ |
852 | ␉{ EFI_TFTP_ERROR, L"TFTP Error"},␍␊ |
853 | ␉{ EFI_PROTOCOL_ERROR, L"Protocol Error"},␍␊ |
854 | ␍␊ |
855 | ␉// warnings␍␊ |
856 | ␉{ EFI_WARN_DELETE_FAILURE, L"Warning Delete Failure"},␍␊ |
857 | ␉{ EFI_WARN_WRITE_FAILURE, L"Warning Write Failure"},␍␊ |
858 | ␉{ EFI_WARN_BUFFER_TOO_SMALL, L"Warning Buffer Too Small"},␍␊ |
859 | ␉{ 0, NULL}␍␊ |
860 | } ;␍␊ |
861 | ␍␊ |
862 | ␍␊ |
863 | VOID␍␊ |
864 | StatusToString (␍␊ |
865 | OUT CHAR16 *Buffer,␍␊ |
866 | IN EFI_STATUS Status␍␊ |
867 | )␍␊ |
868 | {␍␊ |
869 | UINTN Index;␍␊ |
870 | ␍␊ |
871 | for (Index = 0; ErrorCodeTable[Index].Desc; Index +=1) {␍␊ |
872 | if (ErrorCodeTable[Index].Code == Status) {␍␊ |
873 | StrCpy (Buffer, ErrorCodeTable[Index].Desc);␍␊ |
874 | return;␍␊ |
875 | }␍␊ |
876 | }␍␊ |
877 | ␍␊ |
878 | SPrint (Buffer, 0, L"%X", Status);␍␊ |
879 | }␍␊ |
880 | |