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';
396 digit
+= '0' - 'a' + 10;
397 if (digit
>= (unsigned long) base
)
403 /* NUM * BASE + DIGIT > ~0ULL */
404 if (num
> grub_divmod64 (~0ULL - digit
, base
, 0))
406 grub_error (GRUB_ERR_OUT_OF_RANGE
,
407 N_("overflow is detected"));
411 num
= num
* base
+ digit
;
417 grub_error (GRUB_ERR_BAD_NUMBER
,
418 N_("unrecognized number"));
429 grub_strdup (const char *s
)
434 len
= grub_strlen (s
) + 1;
435 p
= (char *) grub_malloc (len
);
439 return grub_memcpy (p
, s
, len
);
443 grub_strndup (const char *s
, grub_size_t n
)
448 len
= grub_strlen (s
);
451 p
= (char *) grub_malloc (len
+ 1);
455 grub_memcpy (p
, s
, len
);
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. */
464 #define VOLATILE_CLANG volatile
466 #define VOLATILE_CLANG
470 grub_memset (void *s
, int c
, grub_size_t len
)
473 grub_uint8_t pattern8
= c
;
475 if (len
>= 3 * sizeof (unsigned long))
477 unsigned long patternl
= 0;
480 for (i
= 0; i
< sizeof (unsigned long); i
++)
481 patternl
|= ((unsigned long) pattern8
) << (8 * i
);
483 while (len
> 0 && (((grub_addr_t
) p
) & (sizeof (unsigned long) - 1)))
485 *(VOLATILE_CLANG grub_uint8_t
*) p
= pattern8
;
486 p
= (grub_uint8_t
*) p
+ 1;
489 while (len
>= sizeof (unsigned long))
491 *(VOLATILE_CLANG
unsigned long *) p
= patternl
;
492 p
= (unsigned long *) p
+ 1;
493 len
-= sizeof (unsigned long);
499 *(VOLATILE_CLANG grub_uint8_t
*) p
= pattern8
;
500 p
= (grub_uint8_t
*) p
+ 1;
508 grub_strlen (const char *s
)
519 grub_reverse (char *str
)
521 char *p
= str
+ grub_strlen (str
) - 1;
535 /* Divide N by D, return the quotient, and store the remainder in *R. */
537 grub_divmod64 (grub_uint64_t n
, grub_uint64_t d
, grub_uint64_t
*r
)
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. */
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.
551 #if !GRUB_DIVISION_IN_SOFTWARE
552 /* Skip the slow computation if 32-bit arithmetic is possible. */
553 if (n
< 0xffffffff && d
< 0xffffffff)
556 *r
= ((grub_uint32_t
) n
) % (grub_uint32_t
) d
;
558 return ((grub_uint32_t
) n
) / (grub_uint32_t
) d
;
566 if (n
& (1ULL << 63))
585 /* Convert a long long value to a string. This function avoids 64-bit
586 modular arithmetic or divisions. */
588 grub_lltoa (char *str
, int c
, unsigned long long n
)
590 unsigned base
= (c
== 'x') ? 16 : 10;
593 if ((long long) n
< 0 && c
== 'd')
595 n
= (unsigned long long) (-((long long) n
));
604 unsigned d
= (unsigned) (n
& 0xf);
605 *p
++ = (d
> 9) ? d
+ 'a' - 10 : d
+ '0';
614 n
= grub_divmod64 (n
, 10, &m
);
626 parse_printf_args (const char *fmt0
, struct printf_args
*args
,
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 *));
642 while ((c
= *fmt
++) != 0)
650 while (grub_isdigit (*fmt
))
659 while (grub_isdigit (*fmt
))
665 while (grub_isdigit (*fmt
))
688 if (args
->count
<= ARRAY_SIZE (args
->prealloc
))
689 args
->ptr
= args
->prealloc
;
692 args
->ptr
= grub_malloc (args
->count
* sizeof (args
->ptr
[0]));
695 grub_errno
= GRUB_ERR_NONE
;
696 args
->ptr
= args
->prealloc
;
697 args
->count
= ARRAY_SIZE (args
->prealloc
);
701 grub_memset (args
->ptr
, 0, args
->count
* sizeof (args
->ptr
[0]));
705 while ((c
= *fmt
++) != 0)
721 while (grub_isdigit (*fmt
))
726 curn
= grub_strtoull (p
, 0, 10) - 1;
733 while (grub_isdigit (*fmt
))
739 while (grub_isdigit (*fmt
))
759 if (curn
>= args
->count
)
765 args
->ptr
[curn
].type
= UNSIGNED_INT
+ longfmt
;
768 args
->ptr
[curn
].type
= INT
+ longfmt
;
772 if (sizeof (void *) == sizeof (long long))
773 args
->ptr
[curn
].type
= UNSIGNED_LONGLONG
;
775 args
->ptr
[curn
].type
= UNSIGNED_INT
;
779 args
->ptr
[curn
].type
= INT
;
784 for (n
= 0; n
< args
->count
; n
++)
785 switch (args
->ptr
[n
].type
)
788 args
->ptr
[n
].ll
= va_arg (args_in
, int);
791 args
->ptr
[n
].ll
= va_arg (args_in
, long);
794 args
->ptr
[n
].ll
= va_arg (args_in
, unsigned int);
797 args
->ptr
[n
].ll
= va_arg (args_in
, unsigned long);
800 case UNSIGNED_LONGLONG
:
801 args
->ptr
[n
].ll
= va_arg (args_in
, long long);
806 static inline void __attribute__ ((always_inline
))
807 write_char (char *str
, grub_size_t
*count
, grub_size_t max_len
, unsigned char ch
)
809 if (*count
< max_len
)
816 grub_vsnprintf_real (char *str
, grub_size_t max_len
, const char *fmt0
,
817 struct printf_args
*args
)
821 grub_size_t count
= 0;
826 while ((c
= *fmt
++) != 0)
828 unsigned int format1
= 0;
829 unsigned int format2
= ~ 0U;
836 write_char (str
, &count
, max_len
,c
);
850 /* Read formatting parameters. */
851 if (grub_isdigit (*fmt
))
855 format1
= grub_strtoul (fmt
, (char **) &fmt
, 10);
861 if (grub_isdigit (*fmt
))
862 format2
= grub_strtoul (fmt
, (char **) &fmt
, 10);
884 write_char (str
, &count
, max_len
,c
);
889 if (curn
>= args
->count
)
892 long long curarg
= args
->ptr
[curn
].ll
;
897 write_char (str
, &count
, max_len
, '0');
898 write_char (str
, &count
, max_len
, 'x');
910 len
= grub_lltoa (tmp
, c
, curarg
) - tmp
;
911 fill
= len
< format1
? format1
- len
: 0;
914 write_char (str
, &count
, max_len
, zerofill
);
916 write_char (str
, &count
, max_len
, *p
++);
919 write_char (str
, &count
, max_len
, zerofill
);
924 write_char (str
, &count
, max_len
,curarg
& 0xff);
929 grub_uint32_t code
= curarg
;
938 else if (code
<= 0x7ff)
943 else if (code
<= 0xffff)
948 else if (code
<= 0x10ffff)
960 write_char (str
, &count
, max_len
,mask
| (code
>> shift
));
962 for (shift
-= 6; shift
>= 0; shift
-= 6)
963 write_char (str
, &count
, max_len
,0x80 | (0x3f & (code
>> shift
)));
971 const char *p
= ((char *) (grub_addr_t
) curarg
) ? : "(null)";
974 while (len
< format2
&& p
[len
])
977 fill
= len
< format1
? format1
- len
: 0;
981 write_char (str
, &count
, max_len
, zerofill
);
983 for (i
= 0; i
< len
; i
++)
984 write_char (str
, &count
, max_len
,*p
++);
988 write_char (str
, &count
, max_len
, zerofill
);
994 write_char (str
, &count
, max_len
,c
);
1002 str
[max_len
] = '\0';
1007 grub_vsnprintf (char *str
, grub_size_t n
, const char *fmt
, va_list ap
)
1010 struct printf_args args
;
1017 parse_printf_args (fmt
, &args
, ap
);
1019 ret
= grub_vsnprintf_real (str
, n
, fmt
, &args
);
1021 free_printf_args (&args
);
1023 return ret
< n
? ret
: n
;
1027 grub_snprintf (char *str
, grub_size_t n
, const char *fmt
, ...)
1033 ret
= grub_vsnprintf (str
, n
, fmt
, ap
);
1040 grub_xvasprintf (const char *fmt
, va_list ap
)
1042 grub_size_t s
, as
= PREALLOC_SIZE
;
1044 struct printf_args args
;
1046 parse_printf_args (fmt
, &args
, ap
);
1050 ret
= grub_malloc (as
+ 1);
1053 free_printf_args (&args
);
1057 s
= grub_vsnprintf_real (ret
, as
, fmt
, &args
);
1061 free_printf_args (&args
);
1071 grub_xasprintf (const char *fmt
, ...)
1077 ret
= grub_xvasprintf (fmt
, ap
);
1083 /* Abort GRUB. This function does not return. */
1084 static void __attribute__ ((noreturn
))
1087 grub_printf ("\nAborted.");
1090 if (grub_term_inputs
)
1093 grub_printf (" Press any key to exit.");
1101 grub_fatal (const char *fmt
, ...)
1106 grub_vprintf (_(fmt
), ap
);
1116 #include <grub/time.h>
1118 struct grub_boot_time
*grub_boot_time_head
;
1119 static struct grub_boot_time
**boot_time_last
= &grub_boot_time_head
;
1122 grub_real_boot_time (const char *file
,
1124 const char *fmt
, ...)
1126 struct grub_boot_time
*n
;
1130 n
= grub_malloc (sizeof (*n
));
1139 n
->tp
= grub_get_time_ms ();
1142 va_start (args
, fmt
);
1143 n
->msg
= grub_xvasprintf (fmt
, args
);
1146 *boot_time_last
= n
;
1147 boot_time_last
= &n
->next
;