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