1 /* misc.c - definitions of misc functions */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include <grub/misc.h>
24 #include <grub/term.h>
26 #include <grub/i18n.h>
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. */
36 UNSIGNED_INT
= 3, UNSIGNED_LONG
, UNSIGNED_LONGLONG
43 union printf_arg prealloc
[32];
44 union printf_arg
*ptr
;
49 parse_printf_args (const char *fmt0
, struct printf_args
*args
,
52 grub_vsnprintf_real (char *str
, grub_size_t max_len
, const char *fmt0
,
53 struct printf_args
*args
);
56 free_printf_args (struct printf_args
*args
)
58 if (args
->ptr
!= args
->prealloc
)
59 grub_free (args
->ptr
);
63 grub_iswordseparator (int c
)
65 return (grub_isspace (c
) || c
== ',' || c
== ';' || c
== '|' || c
== '&');
68 /* grub_gettext_dummy is not translating anything. */
70 grub_gettext_dummy (const char *s
)
75 const char* (*grub_gettext
) (const char *s
) = grub_gettext_dummy
;
78 grub_memmove (void *dest
, const void *src
, grub_size_t n
)
80 char *d
= (char *) dest
;
81 const char *s
= (const char *) src
;
99 grub_strcpy (char *dest
, const char *src
)
103 while ((*p
++ = *src
++) != '\0')
110 grub_printf (const char *fmt
, ...)
116 ret
= grub_vprintf (fmt
, ap
);
123 grub_printf_ (const char *fmt
, ...)
129 ret
= grub_vprintf (_(fmt
), ap
);
136 grub_puts_ (const char *s
)
138 return grub_puts (_(s
));
141 #if defined (__APPLE__) && ! defined (GRUB_UTIL)
143 grub_err_printf (const char *fmt
, ...)
149 ret
= grub_vprintf (fmt
, ap
);
156 #if ! defined (__APPLE__) && ! defined (GRUB_UTIL)
157 int grub_err_printf (const char *fmt
, ...)
158 __attribute__ ((alias("grub_printf")));
162 grub_real_dprintf (const char *file
, const int line
, const char *condition
,
163 const char *fmt
, ...)
166 const char *debug
= grub_env_get ("debug");
171 if (grub_strword (debug
, "all") || grub_strword (debug
, condition
))
173 grub_printf ("%s:%d: ", file
, line
);
174 va_start (args
, fmt
);
175 grub_vprintf (fmt
, args
);
181 #define PREALLOC_SIZE 255
184 grub_vprintf (const char *fmt
, va_list ap
)
187 static char buf
[PREALLOC_SIZE
+ 1];
189 struct printf_args args
;
191 parse_printf_args (fmt
, &args
, ap
);
193 s
= grub_vsnprintf_real (buf
, PREALLOC_SIZE
, fmt
, &args
);
194 if (s
> PREALLOC_SIZE
)
196 curbuf
= grub_malloc (s
+ 1);
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;
207 s
= grub_vsnprintf_real (curbuf
, s
, fmt
, &args
);
210 free_printf_args (&args
);
221 grub_memcmp (const void *s1
, const void *s2
, grub_size_t n
)
223 const grub_uint8_t
*t1
= s1
;
224 const grub_uint8_t
*t2
= s2
;
229 return (int) *t1
- (int) *t2
;
239 grub_strcmp (const char *s1
, const char *s2
)
250 return (int) (grub_uint8_t
) *s1
- (int) (grub_uint8_t
) *s2
;
254 grub_strncmp (const char *s1
, const char *s2
, grub_size_t n
)
259 while (*s1
&& *s2
&& --n
)
268 return (int) (grub_uint8_t
) *s1
- (int) (grub_uint8_t
) *s2
;
272 grub_strchr (const char *s
, int c
)
285 grub_strrchr (const char *s
, int c
)
300 grub_strword (const char *haystack
, const char *needle
)
302 const char *n_pos
= needle
;
304 while (grub_iswordseparator (*haystack
))
309 /* Crawl both the needle and the haystack word we're on. */
310 while(*haystack
&& !grub_iswordseparator (*haystack
)
311 && *haystack
== *n_pos
)
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
)))
326 while (*haystack
&& !grub_iswordseparator (*haystack
))
328 while (grub_iswordseparator (*haystack
))
339 return (c
== '\n' || c
== '\r' || c
== ' ' || c
== '\t');
343 grub_strtoul (const char *str
, char **end
, int base
)
345 unsigned long long num
;
347 num
= grub_strtoull (str
, end
, base
);
348 #if GRUB_CPU_SIZEOF_LONG != 8
351 grub_error (GRUB_ERR_OUT_OF_RANGE
, N_("overflow is detected"));
356 return (unsigned long) num
;
360 grub_strtoull (const char *str
, char **end
, int base
)
362 unsigned long long num
= 0;
365 /* Skip white spaces. */
366 /* grub_isspace checks that *str != '\0'. */
367 while (grub_isspace (*str
))
370 /* Guess the base, if not specified. The prefix `0x' means 16, and
371 the prefix `0' means 8. */
376 if (base
== 0 || base
== 16)
382 else if (base
== 0 && str
[1] >= '0' && str
[1] <= '7')
393 digit
= grub_tolower (*str
) - '0';
394 if (digit
>= 'a' - '0')
395 digit
+= '0' - 'a' + 10;
399 if (digit
>= (unsigned long) base
)
404 /* NUM * BASE + DIGIT > ~0ULL */
405 if (num
> grub_divmod64 (~0ULL - digit
, base
, 0))
407 grub_error (GRUB_ERR_OUT_OF_RANGE
,
408 N_("overflow is detected"));
412 num
= num
* base
+ digit
;
418 grub_error (GRUB_ERR_BAD_NUMBER
,
419 N_("unrecognized number"));
430 grub_strdup (const char *s
)
435 len
= grub_strlen (s
) + 1;
436 p
= (char *) grub_malloc (len
);
440 return grub_memcpy (p
, s
, len
);
444 grub_strndup (const char *s
, grub_size_t n
)
449 len
= grub_strlen (s
);
452 p
= (char *) grub_malloc (len
+ 1);
456 grub_memcpy (p
, s
, len
);
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. */
465 #define VOLATILE_CLANG volatile
467 #define VOLATILE_CLANG
471 grub_memset (void *s
, int c
, grub_size_t len
)
474 grub_uint8_t pattern8
= c
;
476 if (len
>= 3 * sizeof (unsigned long))
478 unsigned long patternl
= 0;
481 for (i
= 0; i
< sizeof (unsigned long); i
++)
482 patternl
|= ((unsigned long) pattern8
) << (8 * i
);
484 while (len
> 0 && (((grub_addr_t
) p
) & (sizeof (unsigned long) - 1)))
486 *(VOLATILE_CLANG grub_uint8_t
*) p
= pattern8
;
487 p
= (grub_uint8_t
*) p
+ 1;
490 while (len
>= sizeof (unsigned long))
492 *(VOLATILE_CLANG
unsigned long *) p
= patternl
;
493 p
= (unsigned long *) p
+ 1;
494 len
-= sizeof (unsigned long);
500 *(VOLATILE_CLANG grub_uint8_t
*) p
= pattern8
;
501 p
= (grub_uint8_t
*) p
+ 1;
509 grub_strlen (const char *s
)
520 grub_reverse (char *str
)
522 char *p
= str
+ grub_strlen (str
) - 1;
536 /* Divide N by D, return the quotient, and store the remainder in *R. */
538 grub_divmod64 (grub_uint64_t n
, grub_uint64_t d
, grub_uint64_t
*r
)
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. */
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.
552 #if !GRUB_DIVISION_IN_SOFTWARE
553 /* Skip the slow computation if 32-bit arithmetic is possible. */
554 if (n
< 0xffffffff && d
< 0xffffffff)
557 *r
= ((grub_uint32_t
) n
) % (grub_uint32_t
) d
;
559 return ((grub_uint32_t
) n
) / (grub_uint32_t
) d
;
567 if (n
& (1ULL << 63))
586 /* Convert a long long value to a string. This function avoids 64-bit
587 modular arithmetic or divisions. */
589 grub_lltoa (char *str
, int c
, unsigned long long n
)
591 unsigned base
= (c
== 'x' || c
== 'X') ? 16 : 10;
594 if ((long long) n
< 0 && c
== 'd')
596 n
= (unsigned long long) (-((long long) n
));
605 unsigned d
= (unsigned) (n
& 0xf);
606 *p
++ = (d
> 9) ? d
+ ((c
== 'x') ? 'a' : 'A') - 10 : d
+ '0';
615 n
= grub_divmod64 (n
, 10, &m
);
627 parse_printf_args (const char *fmt0
, struct printf_args
*args
,
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 *));
643 while ((c
= *fmt
++) != 0)
651 while (grub_isdigit (*fmt
))
660 while (grub_isdigit (*fmt
))
666 while (grub_isdigit (*fmt
))
690 if (args
->count
<= ARRAY_SIZE (args
->prealloc
))
691 args
->ptr
= args
->prealloc
;
694 args
->ptr
= grub_malloc (args
->count
* sizeof (args
->ptr
[0]));
697 grub_errno
= GRUB_ERR_NONE
;
698 args
->ptr
= args
->prealloc
;
699 args
->count
= ARRAY_SIZE (args
->prealloc
);
703 grub_memset (args
->ptr
, 0, args
->count
* sizeof (args
->ptr
[0]));
707 while ((c
= *fmt
++) != 0)
723 while (grub_isdigit (*fmt
))
728 curn
= grub_strtoull (p
, 0, 10) - 1;
735 while (grub_isdigit (*fmt
))
741 while (grub_isdigit (*fmt
))
761 if (curn
>= args
->count
)
768 args
->ptr
[curn
].type
= UNSIGNED_INT
+ longfmt
;
771 args
->ptr
[curn
].type
= INT
+ longfmt
;
775 if (sizeof (void *) == sizeof (long long))
776 args
->ptr
[curn
].type
= UNSIGNED_LONGLONG
;
778 args
->ptr
[curn
].type
= UNSIGNED_INT
;
782 args
->ptr
[curn
].type
= INT
;
787 for (n
= 0; n
< args
->count
; n
++)
788 switch (args
->ptr
[n
].type
)
791 args
->ptr
[n
].ll
= va_arg (args_in
, int);
794 args
->ptr
[n
].ll
= va_arg (args_in
, long);
797 args
->ptr
[n
].ll
= va_arg (args_in
, unsigned int);
800 args
->ptr
[n
].ll
= va_arg (args_in
, unsigned long);
803 case UNSIGNED_LONGLONG
:
804 args
->ptr
[n
].ll
= va_arg (args_in
, long long);
809 static inline void __attribute__ ((always_inline
))
810 write_char (char *str
, grub_size_t
*count
, grub_size_t max_len
, unsigned char ch
)
812 if (*count
< max_len
)
819 grub_vsnprintf_real (char *str
, grub_size_t max_len
, const char *fmt0
,
820 struct printf_args
*args
)
824 grub_size_t count
= 0;
829 while ((c
= *fmt
++) != 0)
831 unsigned int format1
= 0;
832 unsigned int format2
= ~ 0U;
839 write_char (str
, &count
, max_len
,c
);
853 /* Read formatting parameters. */
854 if (grub_isdigit (*fmt
))
858 format1
= grub_strtoul (fmt
, (char **) &fmt
, 10);
864 if (grub_isdigit (*fmt
))
865 format2
= grub_strtoul (fmt
, (char **) &fmt
, 10);
887 write_char (str
, &count
, max_len
,c
);
892 if (curn
>= args
->count
)
895 long long curarg
= args
->ptr
[curn
].ll
;
900 write_char (str
, &count
, max_len
, '0');
901 write_char (str
, &count
, max_len
, 'x');
914 len
= grub_lltoa (tmp
, c
, curarg
) - tmp
;
915 fill
= len
< format1
? format1
- len
: 0;
918 write_char (str
, &count
, max_len
, zerofill
);
920 write_char (str
, &count
, max_len
, *p
++);
923 write_char (str
, &count
, max_len
, zerofill
);
928 write_char (str
, &count
, max_len
,curarg
& 0xff);
933 grub_uint32_t code
= curarg
;
942 else if (code
<= 0x7ff)
947 else if (code
<= 0xffff)
952 else if (code
<= 0x10ffff)
964 write_char (str
, &count
, max_len
,mask
| (code
>> shift
));
966 for (shift
-= 6; shift
>= 0; shift
-= 6)
967 write_char (str
, &count
, max_len
,0x80 | (0x3f & (code
>> shift
)));
975 const char *p
= ((char *) (grub_addr_t
) curarg
) ? : "(null)";
978 while (len
< format2
&& p
[len
])
981 fill
= len
< format1
? format1
- len
: 0;
985 write_char (str
, &count
, max_len
, zerofill
);
987 for (i
= 0; i
< len
; i
++)
988 write_char (str
, &count
, max_len
,*p
++);
992 write_char (str
, &count
, max_len
, zerofill
);
998 write_char (str
, &count
, max_len
,c
);
1003 if (count
< max_len
)
1006 str
[max_len
] = '\0';
1011 grub_vsnprintf (char *str
, grub_size_t n
, const char *fmt
, va_list ap
)
1014 struct printf_args args
;
1021 parse_printf_args (fmt
, &args
, ap
);
1023 ret
= grub_vsnprintf_real (str
, n
, fmt
, &args
);
1025 free_printf_args (&args
);
1027 return ret
< n
? ret
: n
;
1031 grub_snprintf (char *str
, grub_size_t n
, const char *fmt
, ...)
1037 ret
= grub_vsnprintf (str
, n
, fmt
, ap
);
1044 grub_xvasprintf (const char *fmt
, va_list ap
)
1046 grub_size_t s
, as
= PREALLOC_SIZE
;
1048 struct printf_args args
;
1050 parse_printf_args (fmt
, &args
, ap
);
1054 ret
= grub_malloc (as
+ 1);
1057 free_printf_args (&args
);
1061 s
= grub_vsnprintf_real (ret
, as
, fmt
, &args
);
1065 free_printf_args (&args
);
1075 grub_xasprintf (const char *fmt
, ...)
1081 ret
= grub_xvasprintf (fmt
, ap
);
1087 /* Abort GRUB. This function does not return. */
1088 static void __attribute__ ((noreturn
))
1091 grub_printf ("\nAborted.");
1094 if (grub_term_inputs
)
1097 grub_printf (" Press any key to exit.");
1105 grub_fatal (const char *fmt
, ...)
1110 grub_vprintf (_(fmt
), ap
);
1120 #include <grub/time.h>
1122 struct grub_boot_time
*grub_boot_time_head
;
1123 static struct grub_boot_time
**boot_time_last
= &grub_boot_time_head
;
1126 grub_real_boot_time (const char *file
,
1128 const char *fmt
, ...)
1130 struct grub_boot_time
*n
;
1134 n
= grub_malloc (sizeof (*n
));
1143 n
->tp
= grub_get_time_ms ();
1146 va_start (args
, fmt
);
1147 n
->msg
= grub_xvasprintf (fmt
, args
);
1150 *boot_time_last
= n
;
1151 boot_time_last
= &n
->next
;