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