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