~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to kern/misc.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2006-01-05 15:20:40 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060105152040-b72i5pq1a82z22yi
Tags: upstream-1.92
ImportĀ upstreamĀ versionĀ 1.92

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* misc.c - definitions of misc functions */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005  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 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
 
17
 *  along with GRUB; if not, write to the Free Software
 
18
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 */
 
20
 
 
21
#include <grub/misc.h>
 
22
#include <grub/err.h>
 
23
#include <grub/mm.h>
 
24
#include <stdarg.h>
 
25
#include <grub/term.h>
 
26
#include <grub/env.h>
 
27
 
 
28
void *
 
29
grub_memmove (void *dest, const void *src, grub_size_t n)
 
30
{
 
31
  char *d = (char *) dest;
 
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
    }
 
45
  
 
46
  return dest;
 
47
}
 
48
void *memmove (void *dest, const void *src, grub_size_t n)
 
49
  __attribute__ ((alias ("grub_memmove")));
 
50
/* GCC emits references to memcpy() for struct copies etc.  */
 
51
void *memcpy (void *dest, const void *src, grub_size_t n)
 
52
  __attribute__ ((alias ("grub_memmove")));
 
53
 
 
54
char *
 
55
grub_strcpy (char *dest, const char *src)
 
56
{
 
57
  char *p = dest;
 
58
 
 
59
  while ((*p++ = *src++) != '\0')
 
60
    ;
 
61
 
 
62
  return dest;
 
63
}
 
64
 
 
65
char *
 
66
grub_strncpy (char *dest, const char *src, int c)
 
67
{
 
68
  char *p = dest;
 
69
  
 
70
  while ((*p++ = *src++) != '\0' && --c)
 
71
    ;
 
72
 
 
73
  return dest;
 
74
}
 
75
 
 
76
char *
 
77
grub_stpcpy (char *dest, const char *src)
 
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
 
 
89
char *
 
90
grub_strcat (char *dest, const char *src)
 
91
{
 
92
  char *p = dest;
 
93
 
 
94
  while (*p)
 
95
    p++;
 
96
 
 
97
  while ((*p++ = *src++) != '\0')
 
98
    ;
 
99
 
 
100
  return dest;
 
101
}
 
102
 
 
103
char *
 
104
grub_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
 
 
118
int
 
119
grub_printf (const char *fmt, ...)
 
120
{
 
121
  va_list ap;
 
122
  int ret;
 
123
  
 
124
  va_start (ap, fmt);
 
125
  ret = grub_vprintf (fmt, ap);
 
126
  va_end (ap);
 
127
 
 
128
  return ret;
 
129
}  
 
130
 
 
131
void
 
132
grub_real_dprintf(const char *file, const int line, const char *condition,
 
133
                  const char *fmt, ...)
 
134
{
 
135
  va_list args;
 
136
  const char *debug = grub_env_get ("debug");
 
137
  if (! debug)
 
138
    return;
 
139
  if (grub_strword (debug, "all") || grub_strword (debug, condition))
 
140
    {
 
141
      grub_printf ("%s,%d : ", file, line);
 
142
      va_start (args, fmt);
 
143
      grub_vprintf (fmt, args);
 
144
      va_end (args);
 
145
    }
 
146
}
 
147
 
 
148
int
 
149
grub_vprintf (const char *fmt, va_list args)
 
150
{
 
151
  int ret;
 
152
 
 
153
  ret = grub_vsprintf (0, fmt, args);
 
154
  grub_refresh ();
 
155
  return ret;
 
156
}
 
157
 
 
158
int
 
159
grub_memcmp (const void *s1, const void *s2, grub_size_t n)
 
160
{
 
161
  const char *t1 = s1;
 
162
  const char *t2 = s2;
 
163
  
 
164
  while (n--)
 
165
    {
 
166
      if (*t1 != *t2)
 
167
        return (int) *t1 - (int) *t2;
 
168
 
 
169
      t1++;
 
170
      t2++;
 
171
    }
 
172
 
 
173
  return 0;
 
174
}
 
175
void *memcmp (const void *s1, const void *s2, grub_size_t n)
 
176
  __attribute__ ((alias ("grub_memcmp")));
 
177
 
 
178
int
 
179
grub_strcmp (const char *s1, const char *s2)
 
180
{
 
181
  while (*s1 && *s2)
 
182
    {
 
183
      if (*s1 != *s2)
 
184
        return (int) *s1 - (int) *s2;
 
185
      
 
186
      s1++;
 
187
      s2++;
 
188
    }
 
189
 
 
190
  return (int) *s1 - (int) *s2;
 
191
}
 
192
 
 
193
int
 
194
grub_strncmp (const char *s1, const char *s2, grub_size_t n)
 
195
{
 
196
  if (n == 0)
 
197
    return 0;
 
198
  
 
199
  while (*s1 && *s2 && --n)
 
200
    {
 
201
      if (*s1 != *s2)
 
202
        return (int) *s1 - (int) *s2;
 
203
      
 
204
      s1++;
 
205
      s2++;
 
206
    }
 
207
 
 
208
  return (int) *s1 - (int) *s2;
 
209
}
 
210
 
 
211
int
 
212
grub_strncasecmp (const char *s1, const char *s2, int c)
 
213
{
 
214
  int p = 1;
 
215
 
 
216
  while (grub_tolower (*s1) && grub_tolower (*s2) && p < c)
 
217
    {
 
218
      if (grub_tolower (*s1) != grub_tolower (*s2))
 
219
        return (int) grub_tolower (*s1) - (int) grub_tolower (*s2);
 
220
      
 
221
      s1++;
 
222
      s2++;
 
223
      p++;
 
224
    }
 
225
 
 
226
  return (int) *s1 - (int) *s2;
 
227
}
 
228
 
 
229
char *
 
230
grub_strchr (const char *s, int c)
 
231
{
 
232
  while (*s)
 
233
    {
 
234
      if (*s == c)
 
235
        return (char *) s;
 
236
      s++;
 
237
    }
 
238
 
 
239
  return 0;
 
240
}
 
241
 
 
242
char *
 
243
grub_strrchr (const char *s, int c)
 
244
{
 
245
  char *p = 0;
 
246
 
 
247
  while (*s)
 
248
    {
 
249
      if (*s == c)
 
250
        p = (char *) s;
 
251
      s++;
 
252
    }
 
253
 
 
254
  return p;
 
255
}
 
256
 
 
257
int
 
258
grub_strword (const char *haystack, const char *needle)
 
259
{
 
260
  const char *n_pos = needle;
 
261
 
 
262
  while (grub_iswordseparator (*haystack))
 
263
    haystack++;
 
264
 
 
265
  while (*haystack)
 
266
    {
 
267
      /* Crawl both the needle and the haystack word we're on.  */
 
268
      while(*haystack && !grub_iswordseparator (*haystack)
 
269
            && *haystack == *n_pos)
 
270
        {
 
271
          haystack++;
 
272
          n_pos++;
 
273
        }
 
274
 
 
275
      /* If we reached the end of both words at the same time, the word
 
276
      is found. If not, eat everything in the haystack that isn't the
 
277
      next word (or the end of string) and "reset" the needle.  */
 
278
      if ( (!*haystack || grub_iswordseparator (*haystack))
 
279
         && (!*n_pos || grub_iswordseparator (*n_pos)))
 
280
        return 1;
 
281
      else
 
282
        {
 
283
          n_pos = needle;
 
284
          while (*haystack && !grub_iswordseparator (*haystack))
 
285
            haystack++;
 
286
          while (grub_iswordseparator (*haystack))
 
287
            haystack++;
 
288
        }
 
289
    }
 
290
 
 
291
  return 0;
 
292
}
 
293
 
 
294
int
 
295
grub_iswordseparator (int c)
 
296
{
 
297
  return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&');
 
298
}
 
299
 
 
300
int
 
301
grub_isspace (int c)
 
302
{
 
303
  return (c == '\n' || c == '\r' || c == ' ' || c == '\t');
 
304
}
 
305
 
 
306
int
 
307
grub_isprint (int c)
 
308
{
 
309
  return (c >= ' ' && c <= '~');
 
310
}
 
311
 
 
312
int
 
313
grub_isalpha (int c)
 
314
{
 
315
  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
 
316
}
 
317
 
 
318
int
 
319
grub_isdigit (int c)
 
320
{
 
321
  return (c >= '0' && c <= '9');
 
322
}
 
323
 
 
324
int
 
325
grub_isgraph (int c)
 
326
{
 
327
  return (c >= '!' && c <= '~');
 
328
}
 
329
 
 
330
int
 
331
grub_tolower (int c)
 
332
{
 
333
  if (c >= 'A' && c <= 'Z')
 
334
    return c - 'A' + 'a';
 
335
 
 
336
  return c;
 
337
}
 
338
 
 
339
unsigned long
 
340
grub_strtoul (const char *str, char **end, int base)
 
341
{
 
342
  unsigned long num = 0;
 
343
  int found = 0;
 
344
  
 
345
  /* Skip white spaces.  */
 
346
  while (*str && grub_isspace (*str))
 
347
    str++;
 
348
  
 
349
  /* Guess the base, if not specified. The prefix `0x' means 16, and
 
350
     the prefix `0' means 8.  */
 
351
  if (str[0] == '0')
 
352
    {
 
353
      if (str[1] == 'x')
 
354
        {
 
355
          if (base == 0 || base == 16)
 
356
            {
 
357
              base = 16;
 
358
              str += 2;
 
359
            }
 
360
        }
 
361
      else if (str[1] >= '0' && str[1] <= '7')
 
362
        base = 8;
 
363
    }
 
364
  
 
365
  if (base == 0)
 
366
    base = 10;
 
367
 
 
368
  while (*str)
 
369
    {
 
370
      unsigned long digit;
 
371
 
 
372
      digit = grub_tolower (*str) - '0';
 
373
      if (digit > 9)
 
374
        {
 
375
          digit += '0' - 'a' + 10;
 
376
          if (digit >= (unsigned long) base)
 
377
            break;
 
378
        }
 
379
 
 
380
      found = 1;
 
381
      
 
382
      if (num > (~0UL - digit) / base)
 
383
        {
 
384
          grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow is detected");
 
385
          return 0;
 
386
        }
 
387
 
 
388
      num = num * base + digit;
 
389
      str++;
 
390
    }
 
391
 
 
392
  if (! found)
 
393
    {
 
394
      grub_error (GRUB_ERR_BAD_NUMBER, "unrecognized number");
 
395
      return 0;
 
396
    }
 
397
  
 
398
  if (end)
 
399
    *end = (char *) str;
 
400
 
 
401
  return num;
 
402
}
 
403
 
 
404
char *
 
405
grub_strdup (const char *s)
 
406
{
 
407
  grub_size_t len;
 
408
  char *p;
 
409
  
 
410
  len = grub_strlen (s) + 1;
 
411
  p = (char *) grub_malloc (len);
 
412
  if (! p)
 
413
    return 0;
 
414
 
 
415
  return grub_memcpy (p, s, len);
 
416
}
 
417
 
 
418
char *
 
419
grub_strndup (const char *s, grub_size_t n)
 
420
{
 
421
  grub_size_t len;
 
422
  char *p;
 
423
  
 
424
  len = grub_strlen (s);
 
425
  if (len > n)
 
426
    len = n;
 
427
  p = (char *) grub_malloc (len + 1);
 
428
  if (! p)
 
429
    return 0;
 
430
  
 
431
  grub_memcpy (p, s, len);
 
432
  p[len] = '\0';
 
433
  return p;
 
434
}
 
435
 
 
436
void *
 
437
grub_memset (void *s, int c, grub_size_t n)
 
438
{
 
439
  unsigned char *p = (unsigned char *) s;
 
440
 
 
441
  while (n--)
 
442
    *p++ = (unsigned char) c;
 
443
 
 
444
  return s;
 
445
}
 
446
void *memset (void *s, int c, grub_size_t n)
 
447
  __attribute__ ((alias ("grub_memset")));
 
448
 
 
449
grub_size_t
 
450
grub_strlen (const char *s)
 
451
{
 
452
  const char *p = s;
 
453
 
 
454
  while (*p)
 
455
    p++;
 
456
 
 
457
  return p - s;
 
458
}
 
459
 
 
460
static inline void
 
461
grub_reverse (char *str)
 
462
{
 
463
  char *p = str + grub_strlen (str) - 1;
 
464
 
 
465
  while (str < p)
 
466
    {
 
467
      char tmp;
 
468
 
 
469
      tmp = *str;
 
470
      *str = *p;
 
471
      *p = tmp;
 
472
      str++;
 
473
      p--;
 
474
    }
 
475
}
 
476
 
 
477
static char *
 
478
grub_itoa (char *str, int c, unsigned n)
 
479
{
 
480
  unsigned base = (c == 'x') ? 16 : 10;
 
481
  char *p;
 
482
  
 
483
  if ((int) n < 0 && c == 'd')
 
484
    {
 
485
      n = (unsigned) (-((int) n));
 
486
      *str++ = '-';
 
487
    }
 
488
 
 
489
  p = str;
 
490
  do
 
491
    {
 
492
      unsigned d = n % base;
 
493
      *p++ = (d > 9) ? d + 'a' - 10 : d + '0';
 
494
    }
 
495
  while (n /= base);
 
496
  *p = 0;
 
497
 
 
498
  grub_reverse (str);
 
499
  return p;
 
500
}
 
501
 
 
502
static char *
 
503
grub_ftoa (char *str, double f, int round)
 
504
{
 
505
  unsigned int intp;
 
506
  unsigned int fractp;
 
507
  unsigned int power = 1;
 
508
  int i;
 
509
 
 
510
  for (i = 0; i < round; i++)
 
511
    power *= 10;
 
512
 
 
513
  intp = f;
 
514
  fractp = (f - (float) intp) * power;
 
515
 
 
516
  grub_sprintf (str, "%d.%d", intp, fractp);
 
517
  return str;
 
518
}
 
519
 
 
520
int
 
521
grub_vsprintf (char *str, const char *fmt, va_list args)
 
522
{
 
523
  char c;
 
524
  int count = 0;
 
525
  auto void write_char (unsigned char ch);
 
526
  auto void write_str (const char *s);
 
527
  auto void write_fill (const char ch, int n);
 
528
  
 
529
  void write_char (unsigned char ch)
 
530
    {
 
531
      if (str)
 
532
        *str++ = ch;
 
533
      else
 
534
        grub_putchar (ch);
 
535
 
 
536
      count++;
 
537
    }
 
538
 
 
539
  void write_str (const char *s)
 
540
    {
 
541
      while (*s)
 
542
        write_char (*s++);
 
543
    }
 
544
 
 
545
  void write_fill (const char ch, int n)
 
546
    {
 
547
      int i;
 
548
      for (i = 0; i < n; i++)
 
549
        write_char (ch);
 
550
    }
 
551
  
 
552
  while ((c = *fmt++) != 0)
 
553
    {
 
554
      if (c != '%')
 
555
        write_char (c);
 
556
      else
 
557
        {
 
558
          char tmp[16];
 
559
          char *p;
 
560
          unsigned int format1 = 0;
 
561
          unsigned int format2 = 3;
 
562
          char zerofill = ' ';
 
563
          int rightfill = 0;
 
564
          int n;
 
565
          int longfmt = 0;
 
566
 
 
567
          if (*fmt && *fmt =='-')
 
568
            {
 
569
              rightfill = 1;
 
570
              fmt++;
 
571
            }
 
572
 
 
573
          p = (char *) fmt;
 
574
          /* Read formatting parameters.  */
 
575
          while (*p && grub_isdigit (*p))
 
576
            p++;
 
577
 
 
578
          if (p > fmt)
 
579
            {
 
580
              char s[p - fmt + 1];
 
581
              grub_strncpy (s, fmt, p - fmt);
 
582
              s[p - fmt] = 0;
 
583
              if (s[0] == '0')
 
584
                zerofill = '0';
 
585
              format1 = grub_strtoul (s, 0, 10);
 
586
              fmt = p;
 
587
              if (*p && *p == '.')
 
588
                {
 
589
                  p++;
 
590
                  fmt++;
 
591
                  while (*p && grub_isdigit (*p))
 
592
                    p++;
 
593
                  
 
594
                  if (p > fmt)
 
595
                    {
 
596
                      char fstr[p - fmt];
 
597
                      grub_strncpy (fstr, fmt, p - fmt);
 
598
                      format2 = grub_strtoul (fstr, 0, 10);
 
599
                      fmt = p;
 
600
                    }
 
601
                }
 
602
            }
 
603
 
 
604
          c = *fmt++;
 
605
          if (c == 'l')
 
606
            {
 
607
              longfmt = 1;
 
608
              c = *fmt++;
 
609
            }
 
610
 
 
611
          switch (c)
 
612
            {
 
613
            case 'p':
 
614
              write_str ("0x");
 
615
              c = 'x';
 
616
              /* fall through */
 
617
            case 'x':
 
618
            case 'u':
 
619
            case 'd':
 
620
              if (longfmt)
 
621
                n = va_arg (args, long);
 
622
              else
 
623
                n = va_arg (args, int);
 
624
              grub_itoa (tmp, c, n);
 
625
              if (!rightfill && grub_strlen (tmp) < format1)
 
626
                write_fill (zerofill, format1 - grub_strlen (tmp));
 
627
              write_str (tmp);
 
628
              if (rightfill && grub_strlen (tmp) < format1)
 
629
                write_fill (zerofill, format1 - grub_strlen (tmp));
 
630
              break;
 
631
              
 
632
            case 'c':
 
633
              n = va_arg (args, int);
 
634
              write_char (n & 0xff);
 
635
              break;
 
636
 
 
637
            case 'f':
 
638
              {
 
639
                float f;
 
640
                f = va_arg (args, double);
 
641
                grub_ftoa (tmp, f, format2);
 
642
                if (!rightfill && grub_strlen (tmp) < format1)
 
643
                  write_fill (zerofill, format1 - grub_strlen (tmp));
 
644
                write_str (tmp);
 
645
                if (rightfill && grub_strlen (tmp) < format1)
 
646
                  write_fill (zerofill, format1 - grub_strlen (tmp));
 
647
                break;
 
648
              }
 
649
              
 
650
            case 'C':
 
651
              {
 
652
                grub_uint32_t code = va_arg (args, grub_uint32_t);
 
653
                int shift;
 
654
                unsigned mask;
 
655
                
 
656
                if (code <= 0x7f)
 
657
                  {
 
658
                    shift = 0;
 
659
                    mask = 0;
 
660
                  }
 
661
                else if (code <= 0x7ff)
 
662
                  {
 
663
                    shift = 6;
 
664
                    mask = 0xc0;
 
665
                  }
 
666
                else if (code <= 0xffff)
 
667
                  {
 
668
                    shift = 12;
 
669
                    mask = 0xe0;
 
670
                  }
 
671
                else if (code <= 0x1fffff)
 
672
                  {
 
673
                    shift = 18;
 
674
                    mask = 0xf0;
 
675
                  }
 
676
                else if (code <= 0x3ffffff)
 
677
                  {
 
678
                    shift = 24;
 
679
                    mask = 0xf8;
 
680
                  }
 
681
                else if (code <= 0x7fffffff)
 
682
                  {
 
683
                    shift = 30;
 
684
                    mask = 0xfc;
 
685
                  }
 
686
                else
 
687
                  {
 
688
                    code = '?';
 
689
                    shift = 0;
 
690
                    mask = 0;
 
691
                  }
 
692
 
 
693
                write_char (mask | (code >> shift));
 
694
                
 
695
                for (shift -= 6; shift >= 0; shift -= 6)
 
696
                  write_char (0x80 | (0x3f & (code >> shift)));
 
697
              }
 
698
              break;
 
699
 
 
700
            case 's':
 
701
              p = va_arg (args, char *);
 
702
              if (p)
 
703
                {
 
704
                  if (!rightfill && grub_strlen (p) < format1)
 
705
                    write_fill (zerofill, format1 - grub_strlen (p));
 
706
                  
 
707
                  write_str (p);
 
708
                  
 
709
                  if (rightfill && grub_strlen (p) < format1)
 
710
                    write_fill (zerofill, format1 - grub_strlen (p));
 
711
                }
 
712
              else
 
713
                write_str ("(null)");
 
714
              
 
715
              break;
 
716
 
 
717
            default:
 
718
              write_char (c);
 
719
              break;
 
720
            }
 
721
        }
 
722
    }
 
723
 
 
724
  if (str)
 
725
    *str = '\0';
 
726
 
 
727
  if (count && !str)
 
728
    grub_refresh ();
 
729
  
 
730
  return count;
 
731
}
 
732
 
 
733
int
 
734
grub_sprintf (char *str, const char *fmt, ...)
 
735
{
 
736
  va_list ap;
 
737
  int ret;
 
738
  
 
739
  va_start (ap, fmt);
 
740
  ret = grub_vsprintf (str, fmt, ap);
 
741
  va_end (ap);
 
742
 
 
743
  return ret;
 
744
}
 
745
 
 
746
/* Convert UTF-16 to UTF-8.  */
 
747
grub_uint8_t *
 
748
grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src,
 
749
                    grub_size_t size)
 
750
{
 
751
  grub_uint32_t code_high = 0;
 
752
 
 
753
  while (size--)
 
754
    {
 
755
      grub_uint32_t code = *src++;
 
756
 
 
757
      if (code_high)
 
758
        {
 
759
          if (code >= 0xDC00 && code <= 0xDFFF)
 
760
            {
 
761
              /* Surrogate pair.  */
 
762
              code = ((code_high - 0xD800) << 12) + (code - 0xDC00) + 0x10000;
 
763
              
 
764
              *dest++ = (code >> 18) | 0xF0;
 
765
              *dest++ = ((code >> 12) & 0x3F) | 0x80;
 
766
              *dest++ = ((code >> 6) & 0x3F) | 0x80;
 
767
              *dest++ = (code & 0x3F) | 0x80;
 
768
            }
 
769
          else
 
770
            {
 
771
              /* Error...  */
 
772
              *dest++ = '?';
 
773
            }
 
774
 
 
775
          code_high = 0;
 
776
        }
 
777
      else
 
778
        {
 
779
          if (code <= 0x007F)
 
780
            *dest++ = code;
 
781
          else if (code <= 0x07FF)
 
782
            {
 
783
              *dest++ = (code >> 6) | 0xC0;
 
784
              *dest++ = (code & 0x3F) | 0x80;
 
785
            }
 
786
          else if (code >= 0xD800 && code <= 0xDBFF)
 
787
            {
 
788
              code_high = code;
 
789
              continue;
 
790
            }
 
791
          else if (code >= 0xDC00 && code <= 0xDFFF)
 
792
            {
 
793
              /* Error... */
 
794
              *dest++ = '?';
 
795
            }
 
796
          else
 
797
            {
 
798
              *dest++ = (code >> 16) | 0xE0;
 
799
              *dest++ = ((code >> 12) & 0x3F) | 0x80;
 
800
              *dest++ = (code & 0x3F) | 0x80;
 
801
            }
 
802
        }
 
803
    }
 
804
 
 
805
  return dest;
 
806
}
 
807
 
 
808
/* Convert an UTF-8 string to an UCS-4 string. Return the number of
 
809
   characters converted. DEST must be able to hold at least SIZE
 
810
   characters (when the input is unknown). If an invalid sequence is found,
 
811
   return -1.  */
 
812
grub_ssize_t
 
813
grub_utf8_to_ucs4 (grub_uint32_t *dest, const grub_uint8_t *src,
 
814
                   grub_size_t size)
 
815
{
 
816
  grub_uint32_t *p = dest;
 
817
  int count = 0;
 
818
  grub_uint32_t code = 0;
 
819
  
 
820
  while (size--)
 
821
    {
 
822
      grub_uint32_t c = *src++;
 
823
      
 
824
      if (count)
 
825
        {
 
826
          if ((c & 0xc0) != 0x80)
 
827
            {
 
828
              /* invalid */
 
829
              return -1;
 
830
            }
 
831
          else
 
832
            {
 
833
              code <<= 6;
 
834
              code |= (c & 0x3f);
 
835
              count--;
 
836
            }
 
837
        }
 
838
      else
 
839
        {
 
840
          if ((c & 0x80) == 0x00)
 
841
            code = c;
 
842
          else if ((c & 0xe0) == 0xc0)
 
843
            {
 
844
              count = 1;
 
845
              code = c & 0x1f;
 
846
            }
 
847
          else if ((c & 0xf0) == 0xe0)
 
848
            {
 
849
              count = 2;
 
850
              code = c & 0x0f;
 
851
            }
 
852
          else if ((c & 0xf8) == 0xf0)
 
853
            {
 
854
              count = 3;
 
855
              code = c & 0x07;
 
856
            }
 
857
          else if ((c & 0xfc) == 0xf8)
 
858
            {
 
859
              count = 4;
 
860
              code = c & 0x03;
 
861
            }
 
862
          else if ((c & 0xfe) == 0xfc)
 
863
            {
 
864
              count = 5;
 
865
              code = c & 0x01;
 
866
            }
 
867
          else
 
868
            /* invalid */
 
869
            return -1;
 
870
        }
 
871
 
 
872
      if (count == 0)
 
873
        *p++ = code;
 
874
    }
 
875
 
 
876
  return p - dest;
 
877
}