]> git.proxmox.com Git - grub2.git/blob - grub-core/kern/misc.c
Import grub2_2.02+dfsg1.orig.tar.xz
[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 > 9)
395 {
396 digit += '0' - 'a' + 10;
397 if (digit >= (unsigned long) base)
398 break;
399 }
400
401 found = 1;
402
403 /* NUM * BASE + DIGIT > ~0ULL */
404 if (num > grub_divmod64 (~0ULL - digit, base, 0))
405 {
406 grub_error (GRUB_ERR_OUT_OF_RANGE,
407 N_("overflow is detected"));
408 return ~0ULL;
409 }
410
411 num = num * base + digit;
412 str++;
413 }
414
415 if (! found)
416 {
417 grub_error (GRUB_ERR_BAD_NUMBER,
418 N_("unrecognized number"));
419 return 0;
420 }
421
422 if (end)
423 *end = (char *) str;
424
425 return num;
426 }
427
428 char *
429 grub_strdup (const char *s)
430 {
431 grub_size_t len;
432 char *p;
433
434 len = grub_strlen (s) + 1;
435 p = (char *) grub_malloc (len);
436 if (! p)
437 return 0;
438
439 return grub_memcpy (p, s, len);
440 }
441
442 char *
443 grub_strndup (const char *s, grub_size_t n)
444 {
445 grub_size_t len;
446 char *p;
447
448 len = grub_strlen (s);
449 if (len > n)
450 len = n;
451 p = (char *) grub_malloc (len + 1);
452 if (! p)
453 return 0;
454
455 grub_memcpy (p, s, len);
456 p[len] = '\0';
457 return p;
458 }
459
460 /* clang detects that we're implementing here a memset so it decides to
461 optimise and calls memset resulting in infinite recursion. With volatile
462 we make it not optimise in this way. */
463 #ifdef __clang__
464 #define VOLATILE_CLANG volatile
465 #else
466 #define VOLATILE_CLANG
467 #endif
468
469 void *
470 grub_memset (void *s, int c, grub_size_t len)
471 {
472 void *p = s;
473 grub_uint8_t pattern8 = c;
474
475 if (len >= 3 * sizeof (unsigned long))
476 {
477 unsigned long patternl = 0;
478 grub_size_t i;
479
480 for (i = 0; i < sizeof (unsigned long); i++)
481 patternl |= ((unsigned long) pattern8) << (8 * i);
482
483 while (len > 0 && (((grub_addr_t) p) & (sizeof (unsigned long) - 1)))
484 {
485 *(VOLATILE_CLANG grub_uint8_t *) p = pattern8;
486 p = (grub_uint8_t *) p + 1;
487 len--;
488 }
489 while (len >= sizeof (unsigned long))
490 {
491 *(VOLATILE_CLANG unsigned long *) p = patternl;
492 p = (unsigned long *) p + 1;
493 len -= sizeof (unsigned long);
494 }
495 }
496
497 while (len > 0)
498 {
499 *(VOLATILE_CLANG grub_uint8_t *) p = pattern8;
500 p = (grub_uint8_t *) p + 1;
501 len--;
502 }
503
504 return s;
505 }
506
507 grub_size_t
508 grub_strlen (const char *s)
509 {
510 const char *p = s;
511
512 while (*p)
513 p++;
514
515 return p - s;
516 }
517
518 static inline void
519 grub_reverse (char *str)
520 {
521 char *p = str + grub_strlen (str) - 1;
522
523 while (str < p)
524 {
525 char tmp;
526
527 tmp = *str;
528 *str = *p;
529 *p = tmp;
530 str++;
531 p--;
532 }
533 }
534
535 /* Divide N by D, return the quotient, and store the remainder in *R. */
536 grub_uint64_t
537 grub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r)
538 {
539 /* This algorithm is typically implemented by hardware. The idea
540 is to get the highest bit in N, 64 times, by keeping
541 upper(N * 2^i) = (Q * D + M), where upper
542 represents the high 64 bits in 128-bits space. */
543 unsigned bits = 64;
544 grub_uint64_t q = 0;
545 grub_uint64_t m = 0;
546
547 /* ARM and IA64 don't have a fast 32-bit division.
548 Using that code would just make us use software division routines, calling
549 ourselves indirectly and hence getting infinite recursion.
550 */
551 #if !GRUB_DIVISION_IN_SOFTWARE
552 /* Skip the slow computation if 32-bit arithmetic is possible. */
553 if (n < 0xffffffff && d < 0xffffffff)
554 {
555 if (r)
556 *r = ((grub_uint32_t) n) % (grub_uint32_t) d;
557
558 return ((grub_uint32_t) n) / (grub_uint32_t) d;
559 }
560 #endif
561
562 while (bits--)
563 {
564 m <<= 1;
565
566 if (n & (1ULL << 63))
567 m |= 1;
568
569 q <<= 1;
570 n <<= 1;
571
572 if (m >= d)
573 {
574 q |= 1;
575 m -= d;
576 }
577 }
578
579 if (r)
580 *r = m;
581
582 return q;
583 }
584
585 /* Convert a long long value to a string. This function avoids 64-bit
586 modular arithmetic or divisions. */
587 static inline char *
588 grub_lltoa (char *str, int c, unsigned long long n)
589 {
590 unsigned base = (c == 'x') ? 16 : 10;
591 char *p;
592
593 if ((long long) n < 0 && c == 'd')
594 {
595 n = (unsigned long long) (-((long long) n));
596 *str++ = '-';
597 }
598
599 p = str;
600
601 if (base == 16)
602 do
603 {
604 unsigned d = (unsigned) (n & 0xf);
605 *p++ = (d > 9) ? d + 'a' - 10 : d + '0';
606 }
607 while (n >>= 4);
608 else
609 /* BASE == 10 */
610 do
611 {
612 grub_uint64_t m;
613
614 n = grub_divmod64 (n, 10, &m);
615 *p++ = m + '0';
616 }
617 while (n);
618
619 *p = 0;
620
621 grub_reverse (str);
622 return p;
623 }
624
625 static void
626 parse_printf_args (const char *fmt0, struct printf_args *args,
627 va_list args_in)
628 {
629 const char *fmt;
630 char c;
631 grub_size_t n = 0;
632
633 args->count = 0;
634
635 COMPILE_TIME_ASSERT (sizeof (int) == sizeof (grub_uint32_t));
636 COMPILE_TIME_ASSERT (sizeof (int) <= sizeof (long long));
637 COMPILE_TIME_ASSERT (sizeof (long) <= sizeof (long long));
638 COMPILE_TIME_ASSERT (sizeof (long long) == sizeof (void *)
639 || sizeof (int) == sizeof (void *));
640
641 fmt = fmt0;
642 while ((c = *fmt++) != 0)
643 {
644 if (c != '%')
645 continue;
646
647 if (*fmt =='-')
648 fmt++;
649
650 while (grub_isdigit (*fmt))
651 fmt++;
652
653 if (*fmt == '$')
654 fmt++;
655
656 if (*fmt =='-')
657 fmt++;
658
659 while (grub_isdigit (*fmt))
660 fmt++;
661
662 if (*fmt =='.')
663 fmt++;
664
665 while (grub_isdigit (*fmt))
666 fmt++;
667
668 c = *fmt++;
669 if (c == 'l')
670 c = *fmt++;
671 if (c == 'l')
672 c = *fmt++;
673
674 switch (c)
675 {
676 case 'p':
677 case 'x':
678 case 'u':
679 case 'd':
680 case 'c':
681 case 'C':
682 case 's':
683 args->count++;
684 break;
685 }
686 }
687
688 if (args->count <= ARRAY_SIZE (args->prealloc))
689 args->ptr = args->prealloc;
690 else
691 {
692 args->ptr = grub_malloc (args->count * sizeof (args->ptr[0]));
693 if (!args->ptr)
694 {
695 grub_errno = GRUB_ERR_NONE;
696 args->ptr = args->prealloc;
697 args->count = ARRAY_SIZE (args->prealloc);
698 }
699 }
700
701 grub_memset (args->ptr, 0, args->count * sizeof (args->ptr[0]));
702
703 fmt = fmt0;
704 n = 0;
705 while ((c = *fmt++) != 0)
706 {
707 int longfmt = 0;
708 grub_size_t curn;
709 const char *p;
710
711 if (c != '%')
712 continue;
713
714 curn = n++;
715
716 if (*fmt =='-')
717 fmt++;
718
719 p = fmt;
720
721 while (grub_isdigit (*fmt))
722 fmt++;
723
724 if (*fmt == '$')
725 {
726 curn = grub_strtoull (p, 0, 10) - 1;
727 fmt++;
728 }
729
730 if (*fmt =='-')
731 fmt++;
732
733 while (grub_isdigit (*fmt))
734 fmt++;
735
736 if (*fmt =='.')
737 fmt++;
738
739 while (grub_isdigit (*fmt))
740 fmt++;
741
742 c = *fmt++;
743 if (c == '%')
744 {
745 n--;
746 continue;
747 }
748
749 if (c == 'l')
750 {
751 c = *fmt++;
752 longfmt = 1;
753 }
754 if (c == 'l')
755 {
756 c = *fmt++;
757 longfmt = 2;
758 }
759 if (curn >= args->count)
760 continue;
761 switch (c)
762 {
763 case 'x':
764 case 'u':
765 args->ptr[curn].type = UNSIGNED_INT + longfmt;
766 break;
767 case 'd':
768 args->ptr[curn].type = INT + longfmt;
769 break;
770 case 'p':
771 case 's':
772 if (sizeof (void *) == sizeof (long long))
773 args->ptr[curn].type = UNSIGNED_LONGLONG;
774 else
775 args->ptr[curn].type = UNSIGNED_INT;
776 break;
777 case 'C':
778 case 'c':
779 args->ptr[curn].type = INT;
780 break;
781 }
782 }
783
784 for (n = 0; n < args->count; n++)
785 switch (args->ptr[n].type)
786 {
787 case INT:
788 args->ptr[n].ll = va_arg (args_in, int);
789 break;
790 case LONG:
791 args->ptr[n].ll = va_arg (args_in, long);
792 break;
793 case UNSIGNED_INT:
794 args->ptr[n].ll = va_arg (args_in, unsigned int);
795 break;
796 case UNSIGNED_LONG:
797 args->ptr[n].ll = va_arg (args_in, unsigned long);
798 break;
799 case LONGLONG:
800 case UNSIGNED_LONGLONG:
801 args->ptr[n].ll = va_arg (args_in, long long);
802 break;
803 }
804 }
805
806 static inline void __attribute__ ((always_inline))
807 write_char (char *str, grub_size_t *count, grub_size_t max_len, unsigned char ch)
808 {
809 if (*count < max_len)
810 str[*count] = ch;
811
812 (*count)++;
813 }
814
815 static int
816 grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0,
817 struct printf_args *args)
818 {
819 char c;
820 grub_size_t n = 0;
821 grub_size_t count = 0;
822 const char *fmt;
823
824 fmt = fmt0;
825
826 while ((c = *fmt++) != 0)
827 {
828 unsigned int format1 = 0;
829 unsigned int format2 = ~ 0U;
830 char zerofill = ' ';
831 char rightfill = 0;
832 grub_size_t curn;
833
834 if (c != '%')
835 {
836 write_char (str, &count, max_len,c);
837 continue;
838 }
839
840 curn = n++;
841
842 rescan:;
843
844 if (*fmt =='-')
845 {
846 rightfill = 1;
847 fmt++;
848 }
849
850 /* Read formatting parameters. */
851 if (grub_isdigit (*fmt))
852 {
853 if (fmt[0] == '0')
854 zerofill = '0';
855 format1 = grub_strtoul (fmt, (char **) &fmt, 10);
856 }
857
858 if (*fmt == '.')
859 fmt++;
860
861 if (grub_isdigit (*fmt))
862 format2 = grub_strtoul (fmt, (char **) &fmt, 10);
863
864 if (*fmt == '$')
865 {
866 curn = format1 - 1;
867 fmt++;
868 format1 = 0;
869 format2 = ~ 0U;
870 zerofill = ' ';
871 rightfill = 0;
872
873 goto rescan;
874 }
875
876 c = *fmt++;
877 if (c == 'l')
878 c = *fmt++;
879 if (c == 'l')
880 c = *fmt++;
881
882 if (c == '%')
883 {
884 write_char (str, &count, max_len,c);
885 n--;
886 continue;
887 }
888
889 if (curn >= args->count)
890 continue;
891
892 long long curarg = args->ptr[curn].ll;
893
894 switch (c)
895 {
896 case 'p':
897 write_char (str, &count, max_len, '0');
898 write_char (str, &count, max_len, 'x');
899 c = 'x';
900 /* Fall through. */
901 case 'x':
902 case 'u':
903 case 'd':
904 {
905 char tmp[32];
906 const char *p = tmp;
907 grub_size_t len;
908 grub_size_t fill;
909
910 len = grub_lltoa (tmp, c, curarg) - tmp;
911 fill = len < format1 ? format1 - len : 0;
912 if (! rightfill)
913 while (fill--)
914 write_char (str, &count, max_len, zerofill);
915 while (*p)
916 write_char (str, &count, max_len, *p++);
917 if (rightfill)
918 while (fill--)
919 write_char (str, &count, max_len, zerofill);
920 }
921 break;
922
923 case 'c':
924 write_char (str, &count, max_len,curarg & 0xff);
925 break;
926
927 case 'C':
928 {
929 grub_uint32_t code = curarg;
930 int shift;
931 unsigned mask;
932
933 if (code <= 0x7f)
934 {
935 shift = 0;
936 mask = 0;
937 }
938 else if (code <= 0x7ff)
939 {
940 shift = 6;
941 mask = 0xc0;
942 }
943 else if (code <= 0xffff)
944 {
945 shift = 12;
946 mask = 0xe0;
947 }
948 else if (code <= 0x10ffff)
949 {
950 shift = 18;
951 mask = 0xf0;
952 }
953 else
954 {
955 code = '?';
956 shift = 0;
957 mask = 0;
958 }
959
960 write_char (str, &count, max_len,mask | (code >> shift));
961
962 for (shift -= 6; shift >= 0; shift -= 6)
963 write_char (str, &count, max_len,0x80 | (0x3f & (code >> shift)));
964 }
965 break;
966
967 case 's':
968 {
969 grub_size_t len = 0;
970 grub_size_t fill;
971 const char *p = ((char *) (grub_addr_t) curarg) ? : "(null)";
972 grub_size_t i;
973
974 while (len < format2 && p[len])
975 len++;
976
977 fill = len < format1 ? format1 - len : 0;
978
979 if (!rightfill)
980 while (fill--)
981 write_char (str, &count, max_len, zerofill);
982
983 for (i = 0; i < len; i++)
984 write_char (str, &count, max_len,*p++);
985
986 if (rightfill)
987 while (fill--)
988 write_char (str, &count, max_len, zerofill);
989 }
990
991 break;
992
993 default:
994 write_char (str, &count, max_len,c);
995 break;
996 }
997 }
998
999 if (count < max_len)
1000 str[count] = '\0';
1001 else
1002 str[max_len] = '\0';
1003 return count;
1004 }
1005
1006 int
1007 grub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list ap)
1008 {
1009 grub_size_t ret;
1010 struct printf_args args;
1011
1012 if (!n)
1013 return 0;
1014
1015 n--;
1016
1017 parse_printf_args (fmt, &args, ap);
1018
1019 ret = grub_vsnprintf_real (str, n, fmt, &args);
1020
1021 free_printf_args (&args);
1022
1023 return ret < n ? ret : n;
1024 }
1025
1026 int
1027 grub_snprintf (char *str, grub_size_t n, const char *fmt, ...)
1028 {
1029 va_list ap;
1030 int ret;
1031
1032 va_start (ap, fmt);
1033 ret = grub_vsnprintf (str, n, fmt, ap);
1034 va_end (ap);
1035
1036 return ret;
1037 }
1038
1039 char *
1040 grub_xvasprintf (const char *fmt, va_list ap)
1041 {
1042 grub_size_t s, as = PREALLOC_SIZE;
1043 char *ret;
1044 struct printf_args args;
1045
1046 parse_printf_args (fmt, &args, ap);
1047
1048 while (1)
1049 {
1050 ret = grub_malloc (as + 1);
1051 if (!ret)
1052 {
1053 free_printf_args (&args);
1054 return NULL;
1055 }
1056
1057 s = grub_vsnprintf_real (ret, as, fmt, &args);
1058
1059 if (s <= as)
1060 {
1061 free_printf_args (&args);
1062 return ret;
1063 }
1064
1065 grub_free (ret);
1066 as = s;
1067 }
1068 }
1069
1070 char *
1071 grub_xasprintf (const char *fmt, ...)
1072 {
1073 va_list ap;
1074 char *ret;
1075
1076 va_start (ap, fmt);
1077 ret = grub_xvasprintf (fmt, ap);
1078 va_end (ap);
1079
1080 return ret;
1081 }
1082
1083 /* Abort GRUB. This function does not return. */
1084 static void __attribute__ ((noreturn))
1085 grub_abort (void)
1086 {
1087 grub_printf ("\nAborted.");
1088
1089 #ifndef GRUB_UTIL
1090 if (grub_term_inputs)
1091 #endif
1092 {
1093 grub_printf (" Press any key to exit.");
1094 grub_getkey ();
1095 }
1096
1097 grub_exit ();
1098 }
1099
1100 void
1101 grub_fatal (const char *fmt, ...)
1102 {
1103 va_list ap;
1104
1105 va_start (ap, fmt);
1106 grub_vprintf (_(fmt), ap);
1107 va_end (ap);
1108
1109 grub_refresh ();
1110
1111 grub_abort ();
1112 }
1113
1114 #if BOOT_TIME_STATS
1115
1116 #include <grub/time.h>
1117
1118 struct grub_boot_time *grub_boot_time_head;
1119 static struct grub_boot_time **boot_time_last = &grub_boot_time_head;
1120
1121 void
1122 grub_real_boot_time (const char *file,
1123 const int line,
1124 const char *fmt, ...)
1125 {
1126 struct grub_boot_time *n;
1127 va_list args;
1128
1129 grub_error_push ();
1130 n = grub_malloc (sizeof (*n));
1131 if (!n)
1132 {
1133 grub_errno = 0;
1134 grub_error_pop ();
1135 return;
1136 }
1137 n->file = file;
1138 n->line = line;
1139 n->tp = grub_get_time_ms ();
1140 n->next = 0;
1141
1142 va_start (args, fmt);
1143 n->msg = grub_xvasprintf (fmt, args);
1144 va_end (args);
1145
1146 *boot_time_last = n;
1147 boot_time_last = &n->next;
1148
1149 grub_errno = 0;
1150 grub_error_pop ();
1151 }
1152 #endif