]> git.proxmox.com Git - grub2.git/blob - grub-core/kern/misc.c
Add %X to grub_vsnprintf_real and friends
[grub2.git] / grub-core / kern / misc.c
1 /* misc.c - definitions of misc functions */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
5 *
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <grub/misc.h>
21 #include <grub/err.h>
22 #include <grub/mm.h>
23 #include <stdarg.h>
24 #include <grub/term.h>
25 #include <grub/env.h>
26 #include <grub/i18n.h>
27
28 union printf_arg
29 {
30 /* Yes, type is also part of union as the moment we fill the value
31 we don't need to store its type anymore (when we'll need it, we'll
32 have format spec again. So save some space. */
33 enum
34 {
35 INT, LONG, LONGLONG,
36 UNSIGNED_INT = 3, UNSIGNED_LONG, UNSIGNED_LONGLONG
37 } type;
38 long long ll;
39 };
40
41 struct printf_args
42 {
43 union printf_arg prealloc[32];
44 union printf_arg *ptr;
45 grub_size_t count;
46 };
47
48 static void
49 parse_printf_args (const char *fmt0, struct printf_args *args,
50 va_list args_in);
51 static int
52 grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0,
53 struct printf_args *args);
54
55 static void
56 free_printf_args (struct printf_args *args)
57 {
58 if (args->ptr != args->prealloc)
59 grub_free (args->ptr);
60 }
61
62 static int
63 grub_iswordseparator (int c)
64 {
65 return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&');
66 }
67
68 /* grub_gettext_dummy is not translating anything. */
69 static const char *
70 grub_gettext_dummy (const char *s)
71 {
72 return s;
73 }
74
75 const char* (*grub_gettext) (const char *s) = grub_gettext_dummy;
76
77 void *
78 grub_memmove (void *dest, const void *src, grub_size_t n)
79 {
80 char *d = (char *) dest;
81 const char *s = (const char *) src;
82
83 if (d < s)
84 while (n--)
85 *d++ = *s++;
86 else
87 {
88 d += n;
89 s += n;
90
91 while (n--)
92 *--d = *--s;
93 }
94
95 return dest;
96 }
97
98 char *
99 grub_strcpy (char *dest, const char *src)
100 {
101 char *p = dest;
102
103 while ((*p++ = *src++) != '\0')
104 ;
105
106 return dest;
107 }
108
109 int
110 grub_printf (const char *fmt, ...)
111 {
112 va_list ap;
113 int ret;
114
115 va_start (ap, fmt);
116 ret = grub_vprintf (fmt, ap);
117 va_end (ap);
118
119 return ret;
120 }
121
122 int
123 grub_printf_ (const char *fmt, ...)
124 {
125 va_list ap;
126 int ret;
127
128 va_start (ap, fmt);
129 ret = grub_vprintf (_(fmt), ap);
130 va_end (ap);
131
132 return ret;
133 }
134
135 int
136 grub_puts_ (const char *s)
137 {
138 return grub_puts (_(s));
139 }
140
141 #if defined (__APPLE__) && ! defined (GRUB_UTIL)
142 int
143 grub_err_printf (const char *fmt, ...)
144 {
145 va_list ap;
146 int ret;
147
148 va_start (ap, fmt);
149 ret = grub_vprintf (fmt, ap);
150 va_end (ap);
151
152 return ret;
153 }
154 #endif
155
156 #if ! defined (__APPLE__) && ! defined (GRUB_UTIL)
157 int grub_err_printf (const char *fmt, ...)
158 __attribute__ ((alias("grub_printf")));
159 #endif
160
161 void
162 grub_real_dprintf (const char *file, const int line, const char *condition,
163 const char *fmt, ...)
164 {
165 va_list args;
166 const char *debug = grub_env_get ("debug");
167
168 if (! debug)
169 return;
170
171 if (grub_strword (debug, "all") || grub_strword (debug, condition))
172 {
173 grub_printf ("%s:%d: ", file, line);
174 va_start (args, fmt);
175 grub_vprintf (fmt, args);
176 va_end (args);
177 grub_refresh ();
178 }
179 }
180
181 #define PREALLOC_SIZE 255
182
183 int
184 grub_vprintf (const char *fmt, va_list ap)
185 {
186 grub_size_t s;
187 static char buf[PREALLOC_SIZE + 1];
188 char *curbuf = buf;
189 struct printf_args args;
190
191 parse_printf_args (fmt, &args, ap);
192
193 s = grub_vsnprintf_real (buf, PREALLOC_SIZE, fmt, &args);
194 if (s > PREALLOC_SIZE)
195 {
196 curbuf = grub_malloc (s + 1);
197 if (!curbuf)
198 {
199 grub_errno = GRUB_ERR_NONE;
200 buf[PREALLOC_SIZE - 3] = '.';
201 buf[PREALLOC_SIZE - 2] = '.';
202 buf[PREALLOC_SIZE - 1] = '.';
203 buf[PREALLOC_SIZE] = 0;
204 curbuf = buf;
205 }
206 else
207 s = grub_vsnprintf_real (curbuf, s, fmt, &args);
208 }
209
210 free_printf_args (&args);
211
212 grub_xputs (curbuf);
213
214 if (curbuf != buf)
215 grub_free (curbuf);
216
217 return s;
218 }
219
220 int
221 grub_memcmp (const void *s1, const void *s2, grub_size_t n)
222 {
223 const grub_uint8_t *t1 = s1;
224 const grub_uint8_t *t2 = s2;
225
226 while (n--)
227 {
228 if (*t1 != *t2)
229 return (int) *t1 - (int) *t2;
230
231 t1++;
232 t2++;
233 }
234
235 return 0;
236 }
237
238 int
239 grub_strcmp (const char *s1, const char *s2)
240 {
241 while (*s1 && *s2)
242 {
243 if (*s1 != *s2)
244 break;
245
246 s1++;
247 s2++;
248 }
249
250 return (int) (grub_uint8_t) *s1 - (int) (grub_uint8_t) *s2;
251 }
252
253 int
254 grub_strncmp (const char *s1, const char *s2, grub_size_t n)
255 {
256 if (n == 0)
257 return 0;
258
259 while (*s1 && *s2 && --n)
260 {
261 if (*s1 != *s2)
262 break;
263
264 s1++;
265 s2++;
266 }
267
268 return (int) (grub_uint8_t) *s1 - (int) (grub_uint8_t) *s2;
269 }
270
271 char *
272 grub_strchr (const char *s, int c)
273 {
274 do
275 {
276 if (*s == c)
277 return (char *) s;
278 }
279 while (*s++);
280
281 return 0;
282 }
283
284 char *
285 grub_strrchr (const char *s, int c)
286 {
287 char *p = NULL;
288
289 do
290 {
291 if (*s == c)
292 p = (char *) s;
293 }
294 while (*s++);
295
296 return p;
297 }
298
299 int
300 grub_strword (const char *haystack, const char *needle)
301 {
302 const char *n_pos = needle;
303
304 while (grub_iswordseparator (*haystack))
305 haystack++;
306
307 while (*haystack)
308 {
309 /* Crawl both the needle and the haystack word we're on. */
310 while(*haystack && !grub_iswordseparator (*haystack)
311 && *haystack == *n_pos)
312 {
313 haystack++;
314 n_pos++;
315 }
316
317 /* If we reached the end of both words at the same time, the word
318 is found. If not, eat everything in the haystack that isn't the
319 next word (or the end of string) and "reset" the needle. */
320 if ( (!*haystack || grub_iswordseparator (*haystack))
321 && (!*n_pos || grub_iswordseparator (*n_pos)))
322 return 1;
323 else
324 {
325 n_pos = needle;
326 while (*haystack && !grub_iswordseparator (*haystack))
327 haystack++;
328 while (grub_iswordseparator (*haystack))
329 haystack++;
330 }
331 }
332
333 return 0;
334 }
335
336 int
337 grub_isspace (int c)
338 {
339 return (c == '\n' || c == '\r' || c == ' ' || c == '\t');
340 }
341
342 unsigned long
343 grub_strtoul (const char *str, char **end, int base)
344 {
345 unsigned long long num;
346
347 num = grub_strtoull (str, end, base);
348 #if GRUB_CPU_SIZEOF_LONG != 8
349 if (num > ~0UL)
350 {
351 grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
352 return ~0UL;
353 }
354 #endif
355
356 return (unsigned long) num;
357 }
358
359 unsigned long long
360 grub_strtoull (const char *str, char **end, int base)
361 {
362 unsigned long long num = 0;
363 int found = 0;
364
365 /* Skip white spaces. */
366 /* grub_isspace checks that *str != '\0'. */
367 while (grub_isspace (*str))
368 str++;
369
370 /* Guess the base, if not specified. The prefix `0x' means 16, and
371 the prefix `0' means 8. */
372 if (str[0] == '0')
373 {
374 if (str[1] == 'x')
375 {
376 if (base == 0 || base == 16)
377 {
378 base = 16;
379 str += 2;
380 }
381 }
382 else if (base == 0 && str[1] >= '0' && str[1] <= '7')
383 base = 8;
384 }
385
386 if (base == 0)
387 base = 10;
388
389 while (*str)
390 {
391 unsigned long digit;
392
393 digit = grub_tolower (*str) - '0';
394 if (digit >= 'a' - '0')
395 digit += '0' - 'a' + 10;
396 else if (digit > 9)
397 break;
398
399 if (digit >= (unsigned long) base)
400 break;
401
402 found = 1;
403
404 /* NUM * BASE + DIGIT > ~0ULL */
405 if (num > grub_divmod64 (~0ULL - digit, base, 0))
406 {
407 grub_error (GRUB_ERR_OUT_OF_RANGE,
408 N_("overflow is detected"));
409 return ~0ULL;
410 }
411
412 num = num * base + digit;
413 str++;
414 }
415
416 if (! found)
417 {
418 grub_error (GRUB_ERR_BAD_NUMBER,
419 N_("unrecognized number"));
420 return 0;
421 }
422
423 if (end)
424 *end = (char *) str;
425
426 return num;
427 }
428
429 char *
430 grub_strdup (const char *s)
431 {
432 grub_size_t len;
433 char *p;
434
435 len = grub_strlen (s) + 1;
436 p = (char *) grub_malloc (len);
437 if (! p)
438 return 0;
439
440 return grub_memcpy (p, s, len);
441 }
442
443 char *
444 grub_strndup (const char *s, grub_size_t n)
445 {
446 grub_size_t len;
447 char *p;
448
449 len = grub_strlen (s);
450 if (len > n)
451 len = n;
452 p = (char *) grub_malloc (len + 1);
453 if (! p)
454 return 0;
455
456 grub_memcpy (p, s, len);
457 p[len] = '\0';
458 return p;
459 }
460
461 /* clang detects that we're implementing here a memset so it decides to
462 optimise and calls memset resulting in infinite recursion. With volatile
463 we make it not optimise in this way. */
464 #ifdef __clang__
465 #define VOLATILE_CLANG volatile
466 #else
467 #define VOLATILE_CLANG
468 #endif
469
470 void *
471 grub_memset (void *s, int c, grub_size_t len)
472 {
473 void *p = s;
474 grub_uint8_t pattern8 = c;
475
476 if (len >= 3 * sizeof (unsigned long))
477 {
478 unsigned long patternl = 0;
479 grub_size_t i;
480
481 for (i = 0; i < sizeof (unsigned long); i++)
482 patternl |= ((unsigned long) pattern8) << (8 * i);
483
484 while (len > 0 && (((grub_addr_t) p) & (sizeof (unsigned long) - 1)))
485 {
486 *(VOLATILE_CLANG grub_uint8_t *) p = pattern8;
487 p = (grub_uint8_t *) p + 1;
488 len--;
489 }
490 while (len >= sizeof (unsigned long))
491 {
492 *(VOLATILE_CLANG unsigned long *) p = patternl;
493 p = (unsigned long *) p + 1;
494 len -= sizeof (unsigned long);
495 }
496 }
497
498 while (len > 0)
499 {
500 *(VOLATILE_CLANG grub_uint8_t *) p = pattern8;
501 p = (grub_uint8_t *) p + 1;
502 len--;
503 }
504
505 return s;
506 }
507
508 grub_size_t
509 grub_strlen (const char *s)
510 {
511 const char *p = s;
512
513 while (*p)
514 p++;
515
516 return p - s;
517 }
518
519 static inline void
520 grub_reverse (char *str)
521 {
522 char *p = str + grub_strlen (str) - 1;
523
524 while (str < p)
525 {
526 char tmp;
527
528 tmp = *str;
529 *str = *p;
530 *p = tmp;
531 str++;
532 p--;
533 }
534 }
535
536 /* Divide N by D, return the quotient, and store the remainder in *R. */
537 grub_uint64_t
538 grub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r)
539 {
540 /* This algorithm is typically implemented by hardware. The idea
541 is to get the highest bit in N, 64 times, by keeping
542 upper(N * 2^i) = (Q * D + M), where upper
543 represents the high 64 bits in 128-bits space. */
544 unsigned bits = 64;
545 grub_uint64_t q = 0;
546 grub_uint64_t m = 0;
547
548 /* ARM and IA64 don't have a fast 32-bit division.
549 Using that code would just make us use software division routines, calling
550 ourselves indirectly and hence getting infinite recursion.
551 */
552 #if !GRUB_DIVISION_IN_SOFTWARE
553 /* Skip the slow computation if 32-bit arithmetic is possible. */
554 if (n < 0xffffffff && d < 0xffffffff)
555 {
556 if (r)
557 *r = ((grub_uint32_t) n) % (grub_uint32_t) d;
558
559 return ((grub_uint32_t) n) / (grub_uint32_t) d;
560 }
561 #endif
562
563 while (bits--)
564 {
565 m <<= 1;
566
567 if (n & (1ULL << 63))
568 m |= 1;
569
570 q <<= 1;
571 n <<= 1;
572
573 if (m >= d)
574 {
575 q |= 1;
576 m -= d;
577 }
578 }
579
580 if (r)
581 *r = m;
582
583 return q;
584 }
585
586 /* Convert a long long value to a string. This function avoids 64-bit
587 modular arithmetic or divisions. */
588 static inline char *
589 grub_lltoa (char *str, int c, unsigned long long n)
590 {
591 unsigned base = (c == 'x' || c == 'X') ? 16 : 10;
592 char *p;
593
594 if ((long long) n < 0 && c == 'd')
595 {
596 n = (unsigned long long) (-((long long) n));
597 *str++ = '-';
598 }
599
600 p = str;
601
602 if (base == 16)
603 do
604 {
605 unsigned d = (unsigned) (n & 0xf);
606 *p++ = (d > 9) ? d + ((c == 'x') ? 'a' : 'A') - 10 : d + '0';
607 }
608 while (n >>= 4);
609 else
610 /* BASE == 10 */
611 do
612 {
613 grub_uint64_t m;
614
615 n = grub_divmod64 (n, 10, &m);
616 *p++ = m + '0';
617 }
618 while (n);
619
620 *p = 0;
621
622 grub_reverse (str);
623 return p;
624 }
625
626 static void
627 parse_printf_args (const char *fmt0, struct printf_args *args,
628 va_list args_in)
629 {
630 const char *fmt;
631 char c;
632 grub_size_t n = 0;
633
634 args->count = 0;
635
636 COMPILE_TIME_ASSERT (sizeof (int) == sizeof (grub_uint32_t));
637 COMPILE_TIME_ASSERT (sizeof (int) <= sizeof (long long));
638 COMPILE_TIME_ASSERT (sizeof (long) <= sizeof (long long));
639 COMPILE_TIME_ASSERT (sizeof (long long) == sizeof (void *)
640 || sizeof (int) == sizeof (void *));
641
642 fmt = fmt0;
643 while ((c = *fmt++) != 0)
644 {
645 if (c != '%')
646 continue;
647
648 if (*fmt =='-')
649 fmt++;
650
651 while (grub_isdigit (*fmt))
652 fmt++;
653
654 if (*fmt == '$')
655 fmt++;
656
657 if (*fmt =='-')
658 fmt++;
659
660 while (grub_isdigit (*fmt))
661 fmt++;
662
663 if (*fmt =='.')
664 fmt++;
665
666 while (grub_isdigit (*fmt))
667 fmt++;
668
669 c = *fmt++;
670 if (c == 'l')
671 c = *fmt++;
672 if (c == 'l')
673 c = *fmt++;
674
675 switch (c)
676 {
677 case 'p':
678 case 'x':
679 case 'X':
680 case 'u':
681 case 'd':
682 case 'c':
683 case 'C':
684 case 's':
685 args->count++;
686 break;
687 }
688 }
689
690 if (args->count <= ARRAY_SIZE (args->prealloc))
691 args->ptr = args->prealloc;
692 else
693 {
694 args->ptr = grub_malloc (args->count * sizeof (args->ptr[0]));
695 if (!args->ptr)
696 {
697 grub_errno = GRUB_ERR_NONE;
698 args->ptr = args->prealloc;
699 args->count = ARRAY_SIZE (args->prealloc);
700 }
701 }
702
703 grub_memset (args->ptr, 0, args->count * sizeof (args->ptr[0]));
704
705 fmt = fmt0;
706 n = 0;
707 while ((c = *fmt++) != 0)
708 {
709 int longfmt = 0;
710 grub_size_t curn;
711 const char *p;
712
713 if (c != '%')
714 continue;
715
716 curn = n++;
717
718 if (*fmt =='-')
719 fmt++;
720
721 p = fmt;
722
723 while (grub_isdigit (*fmt))
724 fmt++;
725
726 if (*fmt == '$')
727 {
728 curn = grub_strtoull (p, 0, 10) - 1;
729 fmt++;
730 }
731
732 if (*fmt =='-')
733 fmt++;
734
735 while (grub_isdigit (*fmt))
736 fmt++;
737
738 if (*fmt =='.')
739 fmt++;
740
741 while (grub_isdigit (*fmt))
742 fmt++;
743
744 c = *fmt++;
745 if (c == '%')
746 {
747 n--;
748 continue;
749 }
750
751 if (c == 'l')
752 {
753 c = *fmt++;
754 longfmt = 1;
755 }
756 if (c == 'l')
757 {
758 c = *fmt++;
759 longfmt = 2;
760 }
761 if (curn >= args->count)
762 continue;
763 switch (c)
764 {
765 case 'x':
766 case 'X':
767 case 'u':
768 args->ptr[curn].type = UNSIGNED_INT + longfmt;
769 break;
770 case 'd':
771 args->ptr[curn].type = INT + longfmt;
772 break;
773 case 'p':
774 case 's':
775 if (sizeof (void *) == sizeof (long long))
776 args->ptr[curn].type = UNSIGNED_LONGLONG;
777 else
778 args->ptr[curn].type = UNSIGNED_INT;
779 break;
780 case 'C':
781 case 'c':
782 args->ptr[curn].type = INT;
783 break;
784 }
785 }
786
787 for (n = 0; n < args->count; n++)
788 switch (args->ptr[n].type)
789 {
790 case INT:
791 args->ptr[n].ll = va_arg (args_in, int);
792 break;
793 case LONG:
794 args->ptr[n].ll = va_arg (args_in, long);
795 break;
796 case UNSIGNED_INT:
797 args->ptr[n].ll = va_arg (args_in, unsigned int);
798 break;
799 case UNSIGNED_LONG:
800 args->ptr[n].ll = va_arg (args_in, unsigned long);
801 break;
802 case LONGLONG:
803 case UNSIGNED_LONGLONG:
804 args->ptr[n].ll = va_arg (args_in, long long);
805 break;
806 }
807 }
808
809 static inline void __attribute__ ((always_inline))
810 write_char (char *str, grub_size_t *count, grub_size_t max_len, unsigned char ch)
811 {
812 if (*count < max_len)
813 str[*count] = ch;
814
815 (*count)++;
816 }
817
818 static int
819 grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0,
820 struct printf_args *args)
821 {
822 char c;
823 grub_size_t n = 0;
824 grub_size_t count = 0;
825 const char *fmt;
826
827 fmt = fmt0;
828
829 while ((c = *fmt++) != 0)
830 {
831 unsigned int format1 = 0;
832 unsigned int format2 = ~ 0U;
833 char zerofill = ' ';
834 char rightfill = 0;
835 grub_size_t curn;
836
837 if (c != '%')
838 {
839 write_char (str, &count, max_len,c);
840 continue;
841 }
842
843 curn = n++;
844
845 rescan:;
846
847 if (*fmt =='-')
848 {
849 rightfill = 1;
850 fmt++;
851 }
852
853 /* Read formatting parameters. */
854 if (grub_isdigit (*fmt))
855 {
856 if (fmt[0] == '0')
857 zerofill = '0';
858 format1 = grub_strtoul (fmt, (char **) &fmt, 10);
859 }
860
861 if (*fmt == '.')
862 fmt++;
863
864 if (grub_isdigit (*fmt))
865 format2 = grub_strtoul (fmt, (char **) &fmt, 10);
866
867 if (*fmt == '$')
868 {
869 curn = format1 - 1;
870 fmt++;
871 format1 = 0;
872 format2 = ~ 0U;
873 zerofill = ' ';
874 rightfill = 0;
875
876 goto rescan;
877 }
878
879 c = *fmt++;
880 if (c == 'l')
881 c = *fmt++;
882 if (c == 'l')
883 c = *fmt++;
884
885 if (c == '%')
886 {
887 write_char (str, &count, max_len,c);
888 n--;
889 continue;
890 }
891
892 if (curn >= args->count)
893 continue;
894
895 long long curarg = args->ptr[curn].ll;
896
897 switch (c)
898 {
899 case 'p':
900 write_char (str, &count, max_len, '0');
901 write_char (str, &count, max_len, 'x');
902 c = 'x';
903 /* Fall through. */
904 case 'x':
905 case 'X':
906 case 'u':
907 case 'd':
908 {
909 char tmp[32];
910 const char *p = tmp;
911 grub_size_t len;
912 grub_size_t fill;
913
914 len = grub_lltoa (tmp, c, curarg) - tmp;
915 fill = len < format1 ? format1 - len : 0;
916 if (! rightfill)
917 while (fill--)
918 write_char (str, &count, max_len, zerofill);
919 while (*p)
920 write_char (str, &count, max_len, *p++);
921 if (rightfill)
922 while (fill--)
923 write_char (str, &count, max_len, zerofill);
924 }
925 break;
926
927 case 'c':
928 write_char (str, &count, max_len,curarg & 0xff);
929 break;
930
931 case 'C':
932 {
933 grub_uint32_t code = curarg;
934 int shift;
935 unsigned mask;
936
937 if (code <= 0x7f)
938 {
939 shift = 0;
940 mask = 0;
941 }
942 else if (code <= 0x7ff)
943 {
944 shift = 6;
945 mask = 0xc0;
946 }
947 else if (code <= 0xffff)
948 {
949 shift = 12;
950 mask = 0xe0;
951 }
952 else if (code <= 0x10ffff)
953 {
954 shift = 18;
955 mask = 0xf0;
956 }
957 else
958 {
959 code = '?';
960 shift = 0;
961 mask = 0;
962 }
963
964 write_char (str, &count, max_len,mask | (code >> shift));
965
966 for (shift -= 6; shift >= 0; shift -= 6)
967 write_char (str, &count, max_len,0x80 | (0x3f & (code >> shift)));
968 }
969 break;
970
971 case 's':
972 {
973 grub_size_t len = 0;
974 grub_size_t fill;
975 const char *p = ((char *) (grub_addr_t) curarg) ? : "(null)";
976 grub_size_t i;
977
978 while (len < format2 && p[len])
979 len++;
980
981 fill = len < format1 ? format1 - len : 0;
982
983 if (!rightfill)
984 while (fill--)
985 write_char (str, &count, max_len, zerofill);
986
987 for (i = 0; i < len; i++)
988 write_char (str, &count, max_len,*p++);
989
990 if (rightfill)
991 while (fill--)
992 write_char (str, &count, max_len, zerofill);
993 }
994
995 break;
996
997 default:
998 write_char (str, &count, max_len,c);
999 break;
1000 }
1001 }
1002
1003 if (count < max_len)
1004 str[count] = '\0';
1005 else
1006 str[max_len] = '\0';
1007 return count;
1008 }
1009
1010 int
1011 grub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list ap)
1012 {
1013 grub_size_t ret;
1014 struct printf_args args;
1015
1016 if (!n)
1017 return 0;
1018
1019 n--;
1020
1021 parse_printf_args (fmt, &args, ap);
1022
1023 ret = grub_vsnprintf_real (str, n, fmt, &args);
1024
1025 free_printf_args (&args);
1026
1027 return ret < n ? ret : n;
1028 }
1029
1030 int
1031 grub_snprintf (char *str, grub_size_t n, const char *fmt, ...)
1032 {
1033 va_list ap;
1034 int ret;
1035
1036 va_start (ap, fmt);
1037 ret = grub_vsnprintf (str, n, fmt, ap);
1038 va_end (ap);
1039
1040 return ret;
1041 }
1042
1043 char *
1044 grub_xvasprintf (const char *fmt, va_list ap)
1045 {
1046 grub_size_t s, as = PREALLOC_SIZE;
1047 char *ret;
1048 struct printf_args args;
1049
1050 parse_printf_args (fmt, &args, ap);
1051
1052 while (1)
1053 {
1054 ret = grub_malloc (as + 1);
1055 if (!ret)
1056 {
1057 free_printf_args (&args);
1058 return NULL;
1059 }
1060
1061 s = grub_vsnprintf_real (ret, as, fmt, &args);
1062
1063 if (s <= as)
1064 {
1065 free_printf_args (&args);
1066 return ret;
1067 }
1068
1069 grub_free (ret);
1070 as = s;
1071 }
1072 }
1073
1074 char *
1075 grub_xasprintf (const char *fmt, ...)
1076 {
1077 va_list ap;
1078 char *ret;
1079
1080 va_start (ap, fmt);
1081 ret = grub_xvasprintf (fmt, ap);
1082 va_end (ap);
1083
1084 return ret;
1085 }
1086
1087 /* Abort GRUB. This function does not return. */
1088 static void __attribute__ ((noreturn))
1089 grub_abort (void)
1090 {
1091 grub_printf ("\nAborted.");
1092
1093 #ifndef GRUB_UTIL
1094 if (grub_term_inputs)
1095 #endif
1096 {
1097 grub_printf (" Press any key to exit.");
1098 grub_getkey ();
1099 }
1100
1101 grub_exit ();
1102 }
1103
1104 void
1105 grub_fatal (const char *fmt, ...)
1106 {
1107 va_list ap;
1108
1109 va_start (ap, fmt);
1110 grub_vprintf (_(fmt), ap);
1111 va_end (ap);
1112
1113 grub_refresh ();
1114
1115 grub_abort ();
1116 }
1117
1118 #if BOOT_TIME_STATS
1119
1120 #include <grub/time.h>
1121
1122 struct grub_boot_time *grub_boot_time_head;
1123 static struct grub_boot_time **boot_time_last = &grub_boot_time_head;
1124
1125 void
1126 grub_real_boot_time (const char *file,
1127 const int line,
1128 const char *fmt, ...)
1129 {
1130 struct grub_boot_time *n;
1131 va_list args;
1132
1133 grub_error_push ();
1134 n = grub_malloc (sizeof (*n));
1135 if (!n)
1136 {
1137 grub_errno = 0;
1138 grub_error_pop ();
1139 return;
1140 }
1141 n->file = file;
1142 n->line = line;
1143 n->tp = grub_get_time_ms ();
1144 n->next = 0;
1145
1146 va_start (args, fmt);
1147 n->msg = grub_xvasprintf (fmt, args);
1148 va_end (args);
1149
1150 *boot_time_last = n;
1151 boot_time_last = &n->next;
1152
1153 grub_errno = 0;
1154 grub_error_pop ();
1155 }
1156 #endif