]> git.proxmox.com Git - grub2.git/blame - kern/misc.c
2007-07-02 Robert Millan <rmh@aybabtu.com>
[grub2.git] / kern / misc.c
CommitLineData
6a161fa9 1/* misc.c - definitions of misc functions */
2/*
4b13b216 3 * GRUB -- GRand Unified Bootloader
21c8cbb1 4 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
6a161fa9 5 *
4b13b216 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
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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
4b13b216 17 * along with GRUB; if not, write to the Free Software
6a161fa9 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
4b13b216 21#include <grub/misc.h>
22#include <grub/err.h>
23#include <grub/mm.h>
6a161fa9 24#include <stdarg.h>
4b13b216 25#include <grub/term.h>
26#include <grub/env.h>
6a161fa9 27
28void *
4b13b216 29grub_memmove (void *dest, const void *src, grub_size_t n)
6a161fa9 30{
31 char *d = (char *) dest;
a5ffe966 32 const char *s = (const char *) src;
33
34 if (d < s)
35 while (n--)
36 *d++ = *s++;
37 else
38 {
39 d += n;
40 s += n;
41
42 while (n--)
43 *--d = *--s;
44 }
6a161fa9 45
46 return dest;
47}
062b24c2 48void *memmove (void *dest, const void *src, grub_size_t n)
49 __attribute__ ((alias ("grub_memmove")));
8c8cc205 50/* GCC emits references to memcpy() for struct copies etc. */
4b13b216 51void *memcpy (void *dest, const void *src, grub_size_t n)
52 __attribute__ ((alias ("grub_memmove")));
6a161fa9 53
a5ffe966 54char *
4b13b216 55grub_strcpy (char *dest, const char *src)
a5ffe966 56{
57 char *p = dest;
58
59 while ((*p++ = *src++) != '\0')
60 ;
61
62 return dest;
63}
64
a35eed7c 65char *
4b13b216 66grub_strncpy (char *dest, const char *src, int c)
a35eed7c 67{
68 char *p = dest;
e15199cb 69
70 while ((*p++ = *src++) != '\0' && --c)
71 ;
a35eed7c 72
73 return dest;
74}
75
9a5c1ade 76char *
4b13b216 77grub_stpcpy (char *dest, const char *src)
9a5c1ade 78{
79 char *d = dest;
80 const char *s = src;
81
82 do
83 *d++ = *s;
84 while (*s++ != '\0');
85
86 return d - 1;
87}
88
a5ffe966 89char *
4b13b216 90grub_strcat (char *dest, const char *src)
a5ffe966 91{
92 char *p = dest;
93
94 while (*p)
95 p++;
96
97 while ((*p++ = *src++) != '\0')
98 ;
99
100 return dest;
101}
a5ffe966 102
ad0bd20b 103char *
104grub_strncat (char *dest, const char *src, int c)
105{
106 char *p = dest;
107
108 while (*p)
109 p++;
110
111 while ((*p++ = *src++) != '\0' && --c)
112 ;
113 *(--p) = '\0';
114
115 return dest;
116}
117
6a161fa9 118int
4b13b216 119grub_printf (const char *fmt, ...)
6a161fa9 120{
121 va_list ap;
122 int ret;
123
124 va_start (ap, fmt);
4b13b216 125 ret = grub_vprintf (fmt, ap);
6a161fa9 126 va_end (ap);
127
128 return ret;
129}
130
708b345f 131void
9cacaa17 132grub_real_dprintf (const char *file, const int line, const char *condition,
133 const char *fmt, ...)
708b345f 134{
135 va_list args;
136 const char *debug = grub_env_get ("debug");
9cacaa17 137
708b345f 138 if (! debug)
139 return;
9cacaa17 140
708b345f 141 if (grub_strword (debug, "all") || grub_strword (debug, condition))
142 {
9cacaa17 143 grub_printf ("%s:%d: ", file, line);
708b345f 144 va_start (args, fmt);
145 grub_vprintf (fmt, args);
146 va_end (args);
147 }
148}
149
6a161fa9 150int
4b13b216 151grub_vprintf (const char *fmt, va_list args)
6a161fa9 152{
4d4e372e 153 int ret;
154
155 ret = grub_vsprintf (0, fmt, args);
156 grub_refresh ();
157 return ret;
6a161fa9 158}
159
160int
4b13b216 161grub_memcmp (const void *s1, const void *s2, grub_size_t n)
6a161fa9 162{
163 const char *t1 = s1;
164 const char *t2 = s2;
165
166 while (n--)
167 {
168 if (*t1 != *t2)
169 return (int) *t1 - (int) *t2;
170
171 t1++;
172 t2++;
173 }
174
175 return 0;
176}
21c8cbb1 177int memcmp (const void *s1, const void *s2, grub_size_t n)
062b24c2 178 __attribute__ ((alias ("grub_memcmp")));
6a161fa9 179
180int
4b13b216 181grub_strcmp (const char *s1, const char *s2)
6a161fa9 182{
183 while (*s1 && *s2)
184 {
185 if (*s1 != *s2)
186 return (int) *s1 - (int) *s2;
187
188 s1++;
189 s2++;
190 }
191
192 return (int) *s1 - (int) *s2;
193}
194
a35eed7c 195int
8de3495c 196grub_strncmp (const char *s1, const char *s2, grub_size_t n)
a35eed7c 197{
8de3495c 198 if (n == 0)
199 return 0;
200
201 while (*s1 && *s2 && --n)
a35eed7c 202 {
203 if (*s1 != *s2)
204 return (int) *s1 - (int) *s2;
205
206 s1++;
207 s2++;
a35eed7c 208 }
209
210 return (int) *s1 - (int) *s2;
211}
212
64372eb4 213int
214grub_strncasecmp (const char *s1, const char *s2, int c)
215{
216 int p = 1;
217
218 while (grub_tolower (*s1) && grub_tolower (*s2) && p < c)
219 {
220 if (grub_tolower (*s1) != grub_tolower (*s2))
221 return (int) grub_tolower (*s1) - (int) grub_tolower (*s2);
222
223 s1++;
224 s2++;
225 p++;
226 }
227
228 return (int) *s1 - (int) *s2;
229}
230
6a161fa9 231char *
4b13b216 232grub_strchr (const char *s, int c)
6a161fa9 233{
234 while (*s)
235 {
236 if (*s == c)
237 return (char *) s;
238 s++;
239 }
240
241 return 0;
242}
243
244char *
4b13b216 245grub_strrchr (const char *s, int c)
6a161fa9 246{
247 char *p = 0;
248
249 while (*s)
250 {
251 if (*s == c)
252 p = (char *) s;
253 s++;
254 }
255
256 return p;
257}
258
2b002173 259/* Copied from gnulib.
260 Written by Bruno Haible <bruno@clisp.org>, 2005. */
261char *
262grub_strstr (const char *haystack, const char *needle)
263{
264 /* Be careful not to look at the entire extent of haystack or needle
265 until needed. This is useful because of these two cases:
266 - haystack may be very long, and a match of needle found early,
267 - needle may be very long, and not even a short initial segment of
268 needle may be found in haystack. */
269 if (*needle != '\0')
270 {
271 /* Speed up the following searches of needle by caching its first
272 character. */
273 char b = *needle++;
274
275 for (;; haystack++)
276 {
277 if (*haystack == '\0')
278 /* No match. */
279 return NULL;
280 if (*haystack == b)
281 /* The first character matches. */
282 {
283 const char *rhaystack = haystack + 1;
284 const char *rneedle = needle;
285
286 for (;; rhaystack++, rneedle++)
287 {
288 if (*rneedle == '\0')
289 /* Found a match. */
290 return (char *) haystack;
291 if (*rhaystack == '\0')
292 /* No match. */
293 return NULL;
294 if (*rhaystack != *rneedle)
295 /* Nothing in this round. */
296 break;
297 }
298 }
299 }
300 }
301 else
302 return (char *) haystack;
303}
304
708b345f 305int
306grub_strword (const char *haystack, const char *needle)
307{
308 const char *n_pos = needle;
309
310 while (grub_iswordseparator (*haystack))
311 haystack++;
312
313 while (*haystack)
314 {
315 /* Crawl both the needle and the haystack word we're on. */
316 while(*haystack && !grub_iswordseparator (*haystack)
317 && *haystack == *n_pos)
318 {
319 haystack++;
320 n_pos++;
321 }
322
323 /* If we reached the end of both words at the same time, the word
324 is found. If not, eat everything in the haystack that isn't the
325 next word (or the end of string) and "reset" the needle. */
326 if ( (!*haystack || grub_iswordseparator (*haystack))
327 && (!*n_pos || grub_iswordseparator (*n_pos)))
328 return 1;
329 else
330 {
331 n_pos = needle;
332 while (*haystack && !grub_iswordseparator (*haystack))
333 haystack++;
334 while (grub_iswordseparator (*haystack))
335 haystack++;
336 }
337 }
338
339 return 0;
340}
341
342int
343grub_iswordseparator (int c)
344{
345 return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&');
346}
347
6a161fa9 348int
4b13b216 349grub_isspace (int c)
6a161fa9 350{
351 return (c == '\n' || c == '\r' || c == ' ' || c == '\t');
352}
353
354int
4b13b216 355grub_isprint (int c)
6a161fa9 356{
357 return (c >= ' ' && c <= '~');
358}
359
360int
4b13b216 361grub_isalpha (int c)
6a161fa9 362{
363 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
364}
365
db1771cf 366int
4b13b216 367grub_isdigit (int c)
db1771cf 368{
369 return (c >= '0' && c <= '9');
370}
371
372int
4b13b216 373grub_isgraph (int c)
db1771cf 374{
375 return (c >= '!' && c <= '~');
376}
377
6a161fa9 378int
4b13b216 379grub_tolower (int c)
6a161fa9 380{
381 if (c >= 'A' && c <= 'Z')
382 return c - 'A' + 'a';
383
384 return c;
385}
386
524a1e6a 387
6a161fa9 388unsigned long
4b13b216 389grub_strtoul (const char *str, char **end, int base)
6a161fa9 390{
524a1e6a 391 unsigned long long num;
392
393 num = grub_strtoull (str, end, base);
394 if (num > ~0UL)
395 {
396 grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow is detected");
397 return ~0UL;
398 }
399
400 return (unsigned long) num;
401}
402
403unsigned long long
404grub_strtoull (const char *str, char **end, int base)
405{
406 unsigned long long num = 0;
6a161fa9 407 int found = 0;
408
409 /* Skip white spaces. */
4b13b216 410 while (*str && grub_isspace (*str))
6a161fa9 411 str++;
412
413 /* Guess the base, if not specified. The prefix `0x' means 16, and
414 the prefix `0' means 8. */
da849d2d 415 if (base == 0 && str[0] == '0')
6a161fa9 416 {
417 if (str[1] == 'x')
418 {
419 if (base == 0 || base == 16)
420 {
421 base = 16;
422 str += 2;
423 }
424 }
425 else if (str[1] >= '0' && str[1] <= '7')
426 base = 8;
427 }
428
429 if (base == 0)
430 base = 10;
431
432 while (*str)
433 {
434 unsigned long digit;
435
4b13b216 436 digit = grub_tolower (*str) - '0';
6a161fa9 437 if (digit > 9)
438 {
439 digit += '0' - 'a' + 10;
440 if (digit >= (unsigned long) base)
441 break;
442 }
443
444 found = 1;
524a1e6a 445
446 /* NUM * BASE + DIGIT > ~0ULL */
447 if (num > grub_divmod64 (~0ULL - digit, base, 0))
6a161fa9 448 {
4b13b216 449 grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow is detected");
524a1e6a 450 return ~0ULL;
6a161fa9 451 }
452
e15199cb 453 num = num * base + digit;
6a161fa9 454 str++;
455 }
456
457 if (! found)
458 {
4b13b216 459 grub_error (GRUB_ERR_BAD_NUMBER, "unrecognized number");
6a161fa9 460 return 0;
461 }
462
463 if (end)
464 *end = (char *) str;
465
466 return num;
467}
468
469char *
4b13b216 470grub_strdup (const char *s)
6a161fa9 471{
4b13b216 472 grub_size_t len;
6a161fa9 473 char *p;
474
4b13b216 475 len = grub_strlen (s) + 1;
476 p = (char *) grub_malloc (len);
5aded270 477 if (! p)
478 return 0;
479
4b13b216 480 return grub_memcpy (p, s, len);
5aded270 481}
482
483char *
4b13b216 484grub_strndup (const char *s, grub_size_t n)
5aded270 485{
e3741a27 486 grub_size_t len;
487 char *p;
5aded270 488
e3741a27 489 len = grub_strlen (s);
490 if (len > n)
491 len = n;
492 p = (char *) grub_malloc (len + 1);
6a161fa9 493 if (! p)
494 return 0;
e3741a27 495
496 grub_memcpy (p, s, len);
497 p[len] = '\0';
498 return p;
6a161fa9 499}
500
501void *
4b13b216 502grub_memset (void *s, int c, grub_size_t n)
6a161fa9 503{
504 unsigned char *p = (unsigned char *) s;
505
506 while (n--)
507 *p++ = (unsigned char) c;
508
509 return s;
510}
062b24c2 511void *memset (void *s, int c, grub_size_t n)
512 __attribute__ ((alias ("grub_memset")));
6a161fa9 513
4b13b216 514grub_size_t
515grub_strlen (const char *s)
6a161fa9 516{
a5ffe966 517 const char *p = s;
6a161fa9 518
519 while (*p)
520 p++;
521
522 return p - s;
523}
524
525static inline void
4b13b216 526grub_reverse (char *str)
6a161fa9 527{
4b13b216 528 char *p = str + grub_strlen (str) - 1;
6a161fa9 529
530 while (str < p)
531 {
532 char tmp;
533
534 tmp = *str;
535 *str = *p;
536 *p = tmp;
537 str++;
538 p--;
539 }
540}
541
a5ffe966 542static char *
4b13b216 543grub_itoa (char *str, int c, unsigned n)
6a161fa9 544{
545 unsigned base = (c == 'x') ? 16 : 10;
546 char *p;
547
548 if ((int) n < 0 && c == 'd')
549 {
550 n = (unsigned) (-((int) n));
551 *str++ = '-';
552 }
553
554 p = str;
555 do
556 {
557 unsigned d = n % base;
558 *p++ = (d > 9) ? d + 'a' - 10 : d + '0';
559 }
560 while (n /= base);
561 *p = 0;
562
4b13b216 563 grub_reverse (str);
6a161fa9 564 return p;
565}
566
524a1e6a 567/* Divide N by D, return the quotient, and store the remainder in *R. */
568grub_uint64_t
569grub_divmod64 (grub_uint64_t n, grub_uint32_t d, grub_uint32_t *r)
570{
571 /* This algorithm is typically implemented by hardware. The idea
572 is to get the highest bit in N, 64 times, by keeping
573 upper(N * 2^i) = upper((Q * 10 + M) * 2^i), where upper
574 represents the high 64 bits in 128-bits space. */
575 unsigned bits = 64;
576 unsigned long long q = 0;
577 unsigned m = 0;
578
579 /* Skip the slow computation, if 32-bit arithmetics are possible. */
580 if (n < 0xffffffff)
581 {
582 if (r)
583 *r = ((grub_uint32_t) n) % d;
584
585 return ((grub_uint32_t) n) / d;
586 }
587
588 while (bits--)
589 {
590 m <<= 1;
591
592 if (n & (1ULL << 63))
593 m |= 1;
594
595 q <<= 1;
596 n <<= 1;
597
598 if (m >= d)
599 {
600 q |= 1;
601 m -= d;
602 }
603 }
604
605 if (r)
606 *r = m;
607
608 return q;
609}
610
970d3b8a 611/* Convert a long long value to a string. This function avoids 64-bit
612 modular arithmetic or divisions. */
613static char *
614grub_lltoa (char *str, int c, unsigned long long n)
615{
616 unsigned base = (c == 'x') ? 16 : 10;
617 char *p;
618
619 if ((long long) n < 0 && c == 'd')
620 {
621 n = (unsigned long long) (-((long long) n));
622 *str++ = '-';
623 }
624
625 p = str;
626
627 if (base == 16)
628 do
629 {
630 unsigned d = (unsigned) (n & 0xf);
631 *p++ = (d > 9) ? d + 'a' - 10 : d + '0';
632 }
633 while (n >>= 4);
634 else
635 /* BASE == 10 */
636 do
637 {
524a1e6a 638 unsigned m;
639
640 n = grub_divmod64 (n, 10, &m);
49986a9f 641 *p++ = m + '0';
970d3b8a 642 }
643 while (n);
644
645 *p = 0;
646
647 grub_reverse (str);
648 return p;
649}
650
db1771cf 651static char *
4b13b216 652grub_ftoa (char *str, double f, int round)
db1771cf 653{
654 unsigned int intp;
655 unsigned int fractp;
656 unsigned int power = 1;
657 int i;
658
659 for (i = 0; i < round; i++)
660 power *= 10;
661
662 intp = f;
663 fractp = (f - (float) intp) * power;
664
4b13b216 665 grub_sprintf (str, "%d.%d", intp, fractp);
db1771cf 666 return str;
667}
668
6a161fa9 669int
4b13b216 670grub_vsprintf (char *str, const char *fmt, va_list args)
6a161fa9 671{
672 char c;
673 int count = 0;
18d9c7cd 674 auto void write_char (unsigned char ch);
6a161fa9 675 auto void write_str (const char *s);
db1771cf 676 auto void write_fill (const char ch, int n);
6a161fa9 677
18d9c7cd 678 void write_char (unsigned char ch)
6a161fa9 679 {
680 if (str)
a5ffe966 681 *str++ = ch;
6a161fa9 682 else
4b13b216 683 grub_putchar (ch);
6a161fa9 684
685 count++;
686 }
687
688 void write_str (const char *s)
689 {
690 while (*s)
691 write_char (*s++);
692 }
db1771cf 693
694 void write_fill (const char ch, int n)
695 {
696 int i;
697 for (i = 0; i < n; i++)
698 write_char (ch);
699 }
6a161fa9 700
701 while ((c = *fmt++) != 0)
702 {
703 if (c != '%')
704 write_char (c);
705 else
706 {
970d3b8a 707 char tmp[32];
6a161fa9 708 char *p;
db1771cf 709 unsigned int format1 = 0;
710 unsigned int format2 = 3;
711 char zerofill = ' ';
712 int rightfill = 0;
6a161fa9 713 int n;
e75d76e1 714 int longfmt = 0;
970d3b8a 715 int longlongfmt = 0;
e75d76e1 716
db1771cf 717 if (*fmt && *fmt =='-')
718 {
719 rightfill = 1;
720 fmt++;
721 }
e75d76e1 722
db1771cf 723 p = (char *) fmt;
724 /* Read formatting parameters. */
4b13b216 725 while (*p && grub_isdigit (*p))
db1771cf 726 p++;
727
728 if (p > fmt)
729 {
25fe6f03 730 char s[p - fmt + 1];
4b13b216 731 grub_strncpy (s, fmt, p - fmt);
25fe6f03 732 s[p - fmt] = 0;
db1771cf 733 if (s[0] == '0')
734 zerofill = '0';
4b13b216 735 format1 = grub_strtoul (s, 0, 10);
db1771cf 736 fmt = p;
737 if (*p && *p == '.')
738 {
739 p++;
740 fmt++;
4b13b216 741 while (*p && grub_isdigit (*p))
db1771cf 742 p++;
743
744 if (p > fmt)
745 {
746 char fstr[p - fmt];
4b13b216 747 grub_strncpy (fstr, fmt, p - fmt);
748 format2 = grub_strtoul (fstr, 0, 10);
db1771cf 749 fmt = p;
750 }
751 }
752 }
753
754 c = *fmt++;
e75d76e1 755 if (c == 'l')
756 {
757 longfmt = 1;
758 c = *fmt++;
970d3b8a 759 if (c == 'l')
760 {
761 longlongfmt = 1;
762 c = *fmt++;
763 }
e75d76e1 764 }
db1771cf 765
6a161fa9 766 switch (c)
767 {
768 case 'p':
769 write_str ("0x");
770 c = 'x';
970d3b8a 771 longlongfmt = (sizeof (void *) == sizeof (long long));
6a161fa9 772 /* fall through */
773 case 'x':
774 case 'u':
775 case 'd':
970d3b8a 776 if (longlongfmt)
777 {
778 long long ll;
779
780 ll = va_arg (args, long long);
781 grub_lltoa (tmp, c, ll);
782 }
e75d76e1 783 else
970d3b8a 784 {
785 if (longfmt)
786 n = va_arg (args, long);
787 else
788 n = va_arg (args, int);
789 grub_itoa (tmp, c, n);
790 }
791 if (! rightfill && grub_strlen (tmp) < format1)
4b13b216 792 write_fill (zerofill, format1 - grub_strlen (tmp));
6a161fa9 793 write_str (tmp);
4b13b216 794 if (rightfill && grub_strlen (tmp) < format1)
795 write_fill (zerofill, format1 - grub_strlen (tmp));
6a161fa9 796 break;
db1771cf 797
6a161fa9 798 case 'c':
799 n = va_arg (args, int);
18d9c7cd 800 write_char (n & 0xff);
801 break;
802
db1771cf 803 case 'f':
804 {
805 float f;
806 f = va_arg (args, double);
4b13b216 807 grub_ftoa (tmp, f, format2);
808 if (!rightfill && grub_strlen (tmp) < format1)
809 write_fill (zerofill, format1 - grub_strlen (tmp));
db1771cf 810 write_str (tmp);
4b13b216 811 if (rightfill && grub_strlen (tmp) < format1)
812 write_fill (zerofill, format1 - grub_strlen (tmp));
db1771cf 813 break;
814 }
815
18d9c7cd 816 case 'C':
817 {
4b13b216 818 grub_uint32_t code = va_arg (args, grub_uint32_t);
18d9c7cd 819 int shift;
820 unsigned mask;
821
822 if (code <= 0x7f)
823 {
824 shift = 0;
825 mask = 0;
826 }
827 else if (code <= 0x7ff)
828 {
829 shift = 6;
830 mask = 0xc0;
831 }
832 else if (code <= 0xffff)
833 {
834 shift = 12;
835 mask = 0xe0;
836 }
837 else if (code <= 0x1fffff)
838 {
839 shift = 18;
840 mask = 0xf0;
841 }
842 else if (code <= 0x3ffffff)
843 {
844 shift = 24;
845 mask = 0xf8;
846 }
847 else if (code <= 0x7fffffff)
848 {
849 shift = 30;
850 mask = 0xfc;
851 }
852 else
853 {
854 code = '?';
855 shift = 0;
856 mask = 0;
857 }
858
859 write_char (mask | (code >> shift));
860
861 for (shift -= 6; shift >= 0; shift -= 6)
862 write_char (0x80 | (0x3f & (code >> shift)));
863 }
6a161fa9 864 break;
865
866 case 's':
867 p = va_arg (args, char *);
868 if (p)
db1771cf 869 {
4b13b216 870 if (!rightfill && grub_strlen (p) < format1)
871 write_fill (zerofill, format1 - grub_strlen (p));
db1771cf 872
873 write_str (p);
874
4b13b216 875 if (rightfill && grub_strlen (p) < format1)
876 write_fill (zerofill, format1 - grub_strlen (p));
db1771cf 877 }
6a161fa9 878 else
879 write_str ("(null)");
db1771cf 880
6a161fa9 881 break;
882
883 default:
884 write_char (c);
885 break;
886 }
887 }
888 }
889
890 if (str)
891 *str = '\0';
1f7315a3 892
893 if (count && !str)
4b13b216 894 grub_refresh ();
6a161fa9 895
896 return count;
897}
898
899int
4b13b216 900grub_sprintf (char *str, const char *fmt, ...)
6a161fa9 901{
902 va_list ap;
903 int ret;
904
905 va_start (ap, fmt);
4b13b216 906 ret = grub_vsprintf (str, fmt, ap);
6a161fa9 907 va_end (ap);
908
909 return ret;
910}
db1771cf 911
ef095434 912/* Convert UTF-16 to UTF-8. */
aa033560 913grub_uint8_t *
914grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src,
915 grub_size_t size)
916{
917 grub_uint32_t code_high = 0;
918
919 while (size--)
920 {
921 grub_uint32_t code = *src++;
922
923 if (code_high)
924 {
925 if (code >= 0xDC00 && code <= 0xDFFF)
926 {
927 /* Surrogate pair. */
928 code = ((code_high - 0xD800) << 12) + (code - 0xDC00) + 0x10000;
929
930 *dest++ = (code >> 18) | 0xF0;
931 *dest++ = ((code >> 12) & 0x3F) | 0x80;
932 *dest++ = ((code >> 6) & 0x3F) | 0x80;
933 *dest++ = (code & 0x3F) | 0x80;
934 }
935 else
936 {
937 /* Error... */
938 *dest++ = '?';
939 }
940
941 code_high = 0;
942 }
943 else
944 {
945 if (code <= 0x007F)
946 *dest++ = code;
947 else if (code <= 0x07FF)
948 {
949 *dest++ = (code >> 6) | 0xC0;
950 *dest++ = (code & 0x3F) | 0x80;
951 }
952 else if (code >= 0xD800 && code <= 0xDBFF)
953 {
954 code_high = code;
955 continue;
956 }
957 else if (code >= 0xDC00 && code <= 0xDFFF)
958 {
959 /* Error... */
960 *dest++ = '?';
961 }
962 else
963 {
964 *dest++ = (code >> 16) | 0xE0;
965 *dest++ = ((code >> 12) & 0x3F) | 0x80;
966 *dest++ = (code & 0x3F) | 0x80;
967 }
968 }
969 }
970
971 return dest;
972}
973
ef095434 974/* Convert an UTF-8 string to an UCS-4 string. Return the number of
975 characters converted. DEST must be able to hold at least SIZE
976 characters (when the input is unknown). If an invalid sequence is found,
977 return -1. */
978grub_ssize_t
385c6a92 979grub_utf8_to_ucs4 (grub_uint32_t *dest, const grub_uint8_t *src,
980 grub_size_t size)
ef095434 981{
982 grub_uint32_t *p = dest;
983 int count = 0;
984 grub_uint32_t code = 0;
985
986 while (size--)
987 {
988 grub_uint32_t c = *src++;
989
990 if (count)
991 {
992 if ((c & 0xc0) != 0x80)
993 {
994 /* invalid */
995 return -1;
996 }
997 else
998 {
999 code <<= 6;
1000 code |= (c & 0x3f);
1001 count--;
1002 }
1003 }
1004 else
1005 {
1006 if ((c & 0x80) == 0x00)
1007 code = c;
1008 else if ((c & 0xe0) == 0xc0)
1009 {
1010 count = 1;
1011 code = c & 0x1f;
1012 }
1013 else if ((c & 0xf0) == 0xe0)
1014 {
1015 count = 2;
1016 code = c & 0x0f;
1017 }
1018 else if ((c & 0xf8) == 0xf0)
1019 {
1020 count = 3;
1021 code = c & 0x07;
1022 }
1023 else if ((c & 0xfc) == 0xf8)
1024 {
1025 count = 4;
1026 code = c & 0x03;
1027 }
1028 else if ((c & 0xfe) == 0xfc)
1029 {
1030 count = 5;
1031 code = c & 0x01;
1032 }
1033 else
1034 /* invalid */
1035 return -1;
1036 }
1037
1038 if (count == 0)
1039 *p++ = code;
1040 }
1041
1042 return p - dest;
1043}
9cacaa17 1044
1045/* Abort GRUB. This function does not return. */
1046void
1047grub_abort (void)
1048{
1049 if (grub_term_get_current ())
1050 {
2965c7cc 1051 grub_printf ("\nAborted. Press any key to exit.");
9cacaa17 1052 grub_getkey ();
1053 }
2965c7cc 1054
9cacaa17 1055 grub_exit ();
1056}
71538dff 1057/* GCC emits references to abort(). */
1058void abort (void) __attribute__ ((alias ("grub_abort")));