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