]>
Commit | Line | Data |
---|---|---|
6a161fa9 | 1 | /* misc.c - definitions of misc functions */ |
2 | /* | |
4b13b216 | 3 | * GRUB -- GRand Unified Bootloader |
8c8cc205 | 4 | * Copyright (C) 1999,2000,2001,2002,2003,2004 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 | |
28 | void * | |
4b13b216 | 29 | grub_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 | 48 | void *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 | 51 | void *memcpy (void *dest, const void *src, grub_size_t n) |
52 | __attribute__ ((alias ("grub_memmove"))); | |
6a161fa9 | 53 | |
a5ffe966 | 54 | char * |
4b13b216 | 55 | grub_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 | 65 | char * |
4b13b216 | 66 | grub_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 | 76 | char * |
4b13b216 | 77 | grub_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 | 89 | char * |
4b13b216 | 90 | grub_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 | 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 | ||
6a161fa9 | 118 | int |
4b13b216 | 119 | grub_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 | ||
131 | int | |
4b13b216 | 132 | grub_vprintf (const char *fmt, va_list args) |
6a161fa9 | 133 | { |
4b13b216 | 134 | return grub_vsprintf (0, fmt, args); |
6a161fa9 | 135 | } |
136 | ||
137 | int | |
4b13b216 | 138 | grub_memcmp (const void *s1, const void *s2, grub_size_t n) |
6a161fa9 | 139 | { |
140 | const char *t1 = s1; | |
141 | const char *t2 = s2; | |
142 | ||
143 | while (n--) | |
144 | { | |
145 | if (*t1 != *t2) | |
146 | return (int) *t1 - (int) *t2; | |
147 | ||
148 | t1++; | |
149 | t2++; | |
150 | } | |
151 | ||
152 | return 0; | |
153 | } | |
062b24c2 | 154 | void *memcmp (const void *s1, const void *s2, grub_size_t n) |
155 | __attribute__ ((alias ("grub_memcmp"))); | |
6a161fa9 | 156 | |
157 | int | |
4b13b216 | 158 | grub_strcmp (const char *s1, const char *s2) |
6a161fa9 | 159 | { |
160 | while (*s1 && *s2) | |
161 | { | |
162 | if (*s1 != *s2) | |
163 | return (int) *s1 - (int) *s2; | |
164 | ||
165 | s1++; | |
166 | s2++; | |
167 | } | |
168 | ||
169 | return (int) *s1 - (int) *s2; | |
170 | } | |
171 | ||
a35eed7c | 172 | int |
4b13b216 | 173 | grub_strncmp (const char *s1, const char *s2, int c) |
a35eed7c | 174 | { |
175 | int p = 1; | |
176 | ||
177 | while (*s1 && *s2 && p < c) | |
178 | { | |
179 | if (*s1 != *s2) | |
180 | return (int) *s1 - (int) *s2; | |
181 | ||
182 | s1++; | |
183 | s2++; | |
184 | p++; | |
185 | } | |
186 | ||
187 | return (int) *s1 - (int) *s2; | |
188 | } | |
189 | ||
64372eb4 | 190 | int |
191 | grub_strncasecmp (const char *s1, const char *s2, int c) | |
192 | { | |
193 | int p = 1; | |
194 | ||
195 | while (grub_tolower (*s1) && grub_tolower (*s2) && p < c) | |
196 | { | |
197 | if (grub_tolower (*s1) != grub_tolower (*s2)) | |
198 | return (int) grub_tolower (*s1) - (int) grub_tolower (*s2); | |
199 | ||
200 | s1++; | |
201 | s2++; | |
202 | p++; | |
203 | } | |
204 | ||
205 | return (int) *s1 - (int) *s2; | |
206 | } | |
207 | ||
6a161fa9 | 208 | char * |
4b13b216 | 209 | grub_strchr (const char *s, int c) |
6a161fa9 | 210 | { |
211 | while (*s) | |
212 | { | |
213 | if (*s == c) | |
214 | return (char *) s; | |
215 | s++; | |
216 | } | |
217 | ||
218 | return 0; | |
219 | } | |
220 | ||
221 | char * | |
4b13b216 | 222 | grub_strrchr (const char *s, int c) |
6a161fa9 | 223 | { |
224 | char *p = 0; | |
225 | ||
226 | while (*s) | |
227 | { | |
228 | if (*s == c) | |
229 | p = (char *) s; | |
230 | s++; | |
231 | } | |
232 | ||
233 | return p; | |
234 | } | |
235 | ||
236 | int | |
4b13b216 | 237 | grub_isspace (int c) |
6a161fa9 | 238 | { |
239 | return (c == '\n' || c == '\r' || c == ' ' || c == '\t'); | |
240 | } | |
241 | ||
242 | int | |
4b13b216 | 243 | grub_isprint (int c) |
6a161fa9 | 244 | { |
245 | return (c >= ' ' && c <= '~'); | |
246 | } | |
247 | ||
248 | int | |
4b13b216 | 249 | grub_isalpha (int c) |
6a161fa9 | 250 | { |
251 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); | |
252 | } | |
253 | ||
db1771cf | 254 | int |
4b13b216 | 255 | grub_isdigit (int c) |
db1771cf | 256 | { |
257 | return (c >= '0' && c <= '9'); | |
258 | } | |
259 | ||
260 | int | |
4b13b216 | 261 | grub_isgraph (int c) |
db1771cf | 262 | { |
263 | return (c >= '!' && c <= '~'); | |
264 | } | |
265 | ||
6a161fa9 | 266 | int |
4b13b216 | 267 | grub_tolower (int c) |
6a161fa9 | 268 | { |
269 | if (c >= 'A' && c <= 'Z') | |
270 | return c - 'A' + 'a'; | |
271 | ||
272 | return c; | |
273 | } | |
274 | ||
275 | unsigned long | |
4b13b216 | 276 | grub_strtoul (const char *str, char **end, int base) |
6a161fa9 | 277 | { |
278 | unsigned long num = 0; | |
279 | int found = 0; | |
280 | ||
281 | /* Skip white spaces. */ | |
4b13b216 | 282 | while (*str && grub_isspace (*str)) |
6a161fa9 | 283 | str++; |
284 | ||
285 | /* Guess the base, if not specified. The prefix `0x' means 16, and | |
286 | the prefix `0' means 8. */ | |
287 | if (str[0] == '0') | |
288 | { | |
289 | if (str[1] == 'x') | |
290 | { | |
291 | if (base == 0 || base == 16) | |
292 | { | |
293 | base = 16; | |
294 | str += 2; | |
295 | } | |
296 | } | |
297 | else if (str[1] >= '0' && str[1] <= '7') | |
298 | base = 8; | |
299 | } | |
300 | ||
301 | if (base == 0) | |
302 | base = 10; | |
303 | ||
304 | while (*str) | |
305 | { | |
306 | unsigned long digit; | |
307 | ||
4b13b216 | 308 | digit = grub_tolower (*str) - '0'; |
6a161fa9 | 309 | if (digit > 9) |
310 | { | |
311 | digit += '0' - 'a' + 10; | |
312 | if (digit >= (unsigned long) base) | |
313 | break; | |
314 | } | |
315 | ||
316 | found = 1; | |
317 | ||
318 | if (num > (~0UL - digit) / base) | |
319 | { | |
4b13b216 | 320 | grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow is detected"); |
6a161fa9 | 321 | return 0; |
322 | } | |
323 | ||
e15199cb | 324 | num = num * base + digit; |
6a161fa9 | 325 | str++; |
326 | } | |
327 | ||
328 | if (! found) | |
329 | { | |
4b13b216 | 330 | grub_error (GRUB_ERR_BAD_NUMBER, "unrecognized number"); |
6a161fa9 | 331 | return 0; |
332 | } | |
333 | ||
334 | if (end) | |
335 | *end = (char *) str; | |
336 | ||
337 | return num; | |
338 | } | |
339 | ||
340 | char * | |
4b13b216 | 341 | grub_strdup (const char *s) |
6a161fa9 | 342 | { |
4b13b216 | 343 | grub_size_t len; |
6a161fa9 | 344 | char *p; |
345 | ||
4b13b216 | 346 | len = grub_strlen (s) + 1; |
347 | p = (char *) grub_malloc (len); | |
5aded270 | 348 | if (! p) |
349 | return 0; | |
350 | ||
4b13b216 | 351 | return grub_memcpy (p, s, len); |
5aded270 | 352 | } |
353 | ||
354 | char * | |
4b13b216 | 355 | grub_strndup (const char *s, grub_size_t n) |
5aded270 | 356 | { |
4b13b216 | 357 | grub_size_t len = 0; |
5aded270 | 358 | char *p = (char *) s; |
359 | ||
360 | while (*(p++) && len < n) | |
361 | len++; | |
362 | ||
4b13b216 | 363 | len = grub_strlen (s) + 1; |
364 | p = (char *) grub_malloc (len); | |
6a161fa9 | 365 | if (! p) |
366 | return 0; | |
367 | ||
4b13b216 | 368 | return grub_memcpy (p, s, len); |
6a161fa9 | 369 | } |
370 | ||
371 | void * | |
4b13b216 | 372 | grub_memset (void *s, int c, grub_size_t n) |
6a161fa9 | 373 | { |
374 | unsigned char *p = (unsigned char *) s; | |
375 | ||
376 | while (n--) | |
377 | *p++ = (unsigned char) c; | |
378 | ||
379 | return s; | |
380 | } | |
062b24c2 | 381 | void *memset (void *s, int c, grub_size_t n) |
382 | __attribute__ ((alias ("grub_memset"))); | |
6a161fa9 | 383 | |
4b13b216 | 384 | grub_size_t |
385 | grub_strlen (const char *s) | |
6a161fa9 | 386 | { |
a5ffe966 | 387 | const char *p = s; |
6a161fa9 | 388 | |
389 | while (*p) | |
390 | p++; | |
391 | ||
392 | return p - s; | |
393 | } | |
394 | ||
395 | static inline void | |
4b13b216 | 396 | grub_reverse (char *str) |
6a161fa9 | 397 | { |
4b13b216 | 398 | char *p = str + grub_strlen (str) - 1; |
6a161fa9 | 399 | |
400 | while (str < p) | |
401 | { | |
402 | char tmp; | |
403 | ||
404 | tmp = *str; | |
405 | *str = *p; | |
406 | *p = tmp; | |
407 | str++; | |
408 | p--; | |
409 | } | |
410 | } | |
411 | ||
a5ffe966 | 412 | static char * |
4b13b216 | 413 | grub_itoa (char *str, int c, unsigned n) |
6a161fa9 | 414 | { |
415 | unsigned base = (c == 'x') ? 16 : 10; | |
416 | char *p; | |
417 | ||
418 | if ((int) n < 0 && c == 'd') | |
419 | { | |
420 | n = (unsigned) (-((int) n)); | |
421 | *str++ = '-'; | |
422 | } | |
423 | ||
424 | p = str; | |
425 | do | |
426 | { | |
427 | unsigned d = n % base; | |
428 | *p++ = (d > 9) ? d + 'a' - 10 : d + '0'; | |
429 | } | |
430 | while (n /= base); | |
431 | *p = 0; | |
432 | ||
4b13b216 | 433 | grub_reverse (str); |
6a161fa9 | 434 | return p; |
435 | } | |
436 | ||
db1771cf | 437 | static char * |
4b13b216 | 438 | grub_ftoa (char *str, double f, int round) |
db1771cf | 439 | { |
440 | unsigned int intp; | |
441 | unsigned int fractp; | |
442 | unsigned int power = 1; | |
443 | int i; | |
444 | ||
445 | for (i = 0; i < round; i++) | |
446 | power *= 10; | |
447 | ||
448 | intp = f; | |
449 | fractp = (f - (float) intp) * power; | |
450 | ||
4b13b216 | 451 | grub_sprintf (str, "%d.%d", intp, fractp); |
db1771cf | 452 | return str; |
453 | } | |
454 | ||
6a161fa9 | 455 | int |
4b13b216 | 456 | grub_vsprintf (char *str, const char *fmt, va_list args) |
6a161fa9 | 457 | { |
458 | char c; | |
459 | int count = 0; | |
18d9c7cd | 460 | auto void write_char (unsigned char ch); |
6a161fa9 | 461 | auto void write_str (const char *s); |
db1771cf | 462 | auto void write_fill (const char ch, int n); |
6a161fa9 | 463 | |
18d9c7cd | 464 | void write_char (unsigned char ch) |
6a161fa9 | 465 | { |
466 | if (str) | |
a5ffe966 | 467 | *str++ = ch; |
6a161fa9 | 468 | else |
4b13b216 | 469 | grub_putchar (ch); |
6a161fa9 | 470 | |
471 | count++; | |
472 | } | |
473 | ||
474 | void write_str (const char *s) | |
475 | { | |
476 | while (*s) | |
477 | write_char (*s++); | |
478 | } | |
db1771cf | 479 | |
480 | void write_fill (const char ch, int n) | |
481 | { | |
482 | int i; | |
483 | for (i = 0; i < n; i++) | |
484 | write_char (ch); | |
485 | } | |
6a161fa9 | 486 | |
487 | while ((c = *fmt++) != 0) | |
488 | { | |
489 | if (c != '%') | |
490 | write_char (c); | |
491 | else | |
492 | { | |
493 | char tmp[16]; | |
494 | char *p; | |
db1771cf | 495 | unsigned int format1 = 0; |
496 | unsigned int format2 = 3; | |
497 | char zerofill = ' '; | |
498 | int rightfill = 0; | |
6a161fa9 | 499 | int n; |
500 | ||
db1771cf | 501 | if (*fmt && *fmt =='-') |
502 | { | |
503 | rightfill = 1; | |
504 | fmt++; | |
505 | } | |
6a161fa9 | 506 | |
db1771cf | 507 | p = (char *) fmt; |
508 | /* Read formatting parameters. */ | |
4b13b216 | 509 | while (*p && grub_isdigit (*p)) |
db1771cf | 510 | p++; |
511 | ||
512 | if (p > fmt) | |
513 | { | |
514 | char s[p - fmt]; | |
4b13b216 | 515 | grub_strncpy (s, fmt, p - fmt); |
db1771cf | 516 | if (s[0] == '0') |
517 | zerofill = '0'; | |
4b13b216 | 518 | format1 = grub_strtoul (s, 0, 10); |
db1771cf | 519 | fmt = p; |
520 | if (*p && *p == '.') | |
521 | { | |
522 | p++; | |
523 | fmt++; | |
4b13b216 | 524 | while (*p && grub_isdigit (*p)) |
db1771cf | 525 | p++; |
526 | ||
527 | if (p > fmt) | |
528 | { | |
529 | char fstr[p - fmt]; | |
4b13b216 | 530 | grub_strncpy (fstr, fmt, p - fmt); |
531 | format2 = grub_strtoul (fstr, 0, 10); | |
db1771cf | 532 | fmt = p; |
533 | } | |
534 | } | |
535 | } | |
536 | ||
537 | c = *fmt++; | |
538 | ||
6a161fa9 | 539 | switch (c) |
540 | { | |
541 | case 'p': | |
542 | write_str ("0x"); | |
543 | c = 'x'; | |
544 | /* fall through */ | |
545 | case 'x': | |
546 | case 'u': | |
547 | case 'd': | |
548 | n = va_arg (args, int); | |
4b13b216 | 549 | grub_itoa (tmp, c, n); |
550 | if (!rightfill && grub_strlen (tmp) < format1) | |
551 | write_fill (zerofill, format1 - grub_strlen (tmp)); | |
6a161fa9 | 552 | write_str (tmp); |
4b13b216 | 553 | if (rightfill && grub_strlen (tmp) < format1) |
554 | write_fill (zerofill, format1 - grub_strlen (tmp)); | |
6a161fa9 | 555 | break; |
db1771cf | 556 | |
6a161fa9 | 557 | case 'c': |
558 | n = va_arg (args, int); | |
18d9c7cd | 559 | write_char (n & 0xff); |
560 | break; | |
561 | ||
db1771cf | 562 | case 'f': |
563 | { | |
564 | float f; | |
565 | f = va_arg (args, double); | |
4b13b216 | 566 | grub_ftoa (tmp, f, format2); |
567 | if (!rightfill && grub_strlen (tmp) < format1) | |
568 | write_fill (zerofill, format1 - grub_strlen (tmp)); | |
db1771cf | 569 | write_str (tmp); |
4b13b216 | 570 | if (rightfill && grub_strlen (tmp) < format1) |
571 | write_fill (zerofill, format1 - grub_strlen (tmp)); | |
db1771cf | 572 | break; |
573 | } | |
574 | ||
18d9c7cd | 575 | case 'C': |
576 | { | |
4b13b216 | 577 | grub_uint32_t code = va_arg (args, grub_uint32_t); |
18d9c7cd | 578 | int shift; |
579 | unsigned mask; | |
580 | ||
581 | if (code <= 0x7f) | |
582 | { | |
583 | shift = 0; | |
584 | mask = 0; | |
585 | } | |
586 | else if (code <= 0x7ff) | |
587 | { | |
588 | shift = 6; | |
589 | mask = 0xc0; | |
590 | } | |
591 | else if (code <= 0xffff) | |
592 | { | |
593 | shift = 12; | |
594 | mask = 0xe0; | |
595 | } | |
596 | else if (code <= 0x1fffff) | |
597 | { | |
598 | shift = 18; | |
599 | mask = 0xf0; | |
600 | } | |
601 | else if (code <= 0x3ffffff) | |
602 | { | |
603 | shift = 24; | |
604 | mask = 0xf8; | |
605 | } | |
606 | else if (code <= 0x7fffffff) | |
607 | { | |
608 | shift = 30; | |
609 | mask = 0xfc; | |
610 | } | |
611 | else | |
612 | { | |
613 | code = '?'; | |
614 | shift = 0; | |
615 | mask = 0; | |
616 | } | |
617 | ||
618 | write_char (mask | (code >> shift)); | |
619 | ||
620 | for (shift -= 6; shift >= 0; shift -= 6) | |
621 | write_char (0x80 | (0x3f & (code >> shift))); | |
622 | } | |
6a161fa9 | 623 | break; |
624 | ||
625 | case 's': | |
626 | p = va_arg (args, char *); | |
627 | if (p) | |
db1771cf | 628 | { |
4b13b216 | 629 | if (!rightfill && grub_strlen (p) < format1) |
630 | write_fill (zerofill, format1 - grub_strlen (p)); | |
db1771cf | 631 | |
632 | write_str (p); | |
633 | ||
4b13b216 | 634 | if (rightfill && grub_strlen (p) < format1) |
635 | write_fill (zerofill, format1 - grub_strlen (p)); | |
db1771cf | 636 | } |
6a161fa9 | 637 | else |
638 | write_str ("(null)"); | |
db1771cf | 639 | |
6a161fa9 | 640 | break; |
641 | ||
642 | default: | |
643 | write_char (c); | |
644 | break; | |
645 | } | |
646 | } | |
647 | } | |
648 | ||
649 | if (str) | |
650 | *str = '\0'; | |
1f7315a3 | 651 | |
652 | if (count && !str) | |
4b13b216 | 653 | grub_refresh (); |
6a161fa9 | 654 | |
655 | return count; | |
656 | } | |
657 | ||
658 | int | |
4b13b216 | 659 | grub_sprintf (char *str, const char *fmt, ...) |
6a161fa9 | 660 | { |
661 | va_list ap; | |
662 | int ret; | |
663 | ||
664 | va_start (ap, fmt); | |
4b13b216 | 665 | ret = grub_vsprintf (str, fmt, ap); |
6a161fa9 | 666 | va_end (ap); |
667 | ||
668 | return ret; | |
669 | } | |
db1771cf | 670 | |
aa033560 | 671 | /* Convert UTF-16 to UTF8. */ |
672 | grub_uint8_t * | |
673 | grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src, | |
674 | grub_size_t size) | |
675 | { | |
676 | grub_uint32_t code_high = 0; | |
677 | ||
678 | while (size--) | |
679 | { | |
680 | grub_uint32_t code = *src++; | |
681 | ||
682 | if (code_high) | |
683 | { | |
684 | if (code >= 0xDC00 && code <= 0xDFFF) | |
685 | { | |
686 | /* Surrogate pair. */ | |
687 | code = ((code_high - 0xD800) << 12) + (code - 0xDC00) + 0x10000; | |
688 | ||
689 | *dest++ = (code >> 18) | 0xF0; | |
690 | *dest++ = ((code >> 12) & 0x3F) | 0x80; | |
691 | *dest++ = ((code >> 6) & 0x3F) | 0x80; | |
692 | *dest++ = (code & 0x3F) | 0x80; | |
693 | } | |
694 | else | |
695 | { | |
696 | /* Error... */ | |
697 | *dest++ = '?'; | |
698 | } | |
699 | ||
700 | code_high = 0; | |
701 | } | |
702 | else | |
703 | { | |
704 | if (code <= 0x007F) | |
705 | *dest++ = code; | |
706 | else if (code <= 0x07FF) | |
707 | { | |
708 | *dest++ = (code >> 6) | 0xC0; | |
709 | *dest++ = (code & 0x3F) | 0x80; | |
710 | } | |
711 | else if (code >= 0xD800 && code <= 0xDBFF) | |
712 | { | |
713 | code_high = code; | |
714 | continue; | |
715 | } | |
716 | else if (code >= 0xDC00 && code <= 0xDFFF) | |
717 | { | |
718 | /* Error... */ | |
719 | *dest++ = '?'; | |
720 | } | |
721 | else | |
722 | { | |
723 | *dest++ = (code >> 16) | 0xE0; | |
724 | *dest++ = ((code >> 12) & 0x3F) | 0x80; | |
725 | *dest++ = (code & 0x3F) | 0x80; | |
726 | } | |
727 | } | |
728 | } | |
729 | ||
730 | return dest; | |
731 | } | |
732 | ||
4b13b216 | 733 | grub_err_t |
734 | grub_split_cmdline (const char *cmdline, grub_err_t (* getline) (char **), int *argc, char ***argv) | |
db1771cf | 735 | { |
736 | /* XXX: Fixed size buffer, perhaps this buffer should be dynamically | |
737 | allocated. */ | |
738 | char buffer[1024]; | |
739 | char *bp = buffer; | |
740 | char *rd = (char *) cmdline; | |
741 | char unputbuf; | |
742 | int unput = 0; | |
743 | char *args; | |
744 | int i; | |
745 | ||
746 | auto char getchar (void); | |
747 | auto void unputc (char c); | |
748 | auto void getenvvar (void); | |
749 | auto int getarg (void); | |
750 | ||
751 | /* Get one character from the commandline. If the caller reads | |
752 | beyond the end of the string a new line will be read. This | |
753 | function will not chech for errors, the caller has to check for | |
4b13b216 | 754 | grub_errno. */ |
db1771cf | 755 | char getchar (void) |
756 | { | |
757 | int c; | |
758 | if (unput) | |
759 | { | |
760 | unput = 0; | |
761 | return unputbuf; | |
762 | } | |
763 | ||
764 | if (! rd) | |
765 | { | |
766 | getline (&rd); | |
767 | /* Error is ignored here, the caller will check for this | |
768 | when it reads beyond the EOL. */ | |
769 | c = *(rd)++; | |
770 | return c; | |
771 | } | |
772 | ||
773 | c = *(rd)++; | |
774 | if (! c) | |
775 | { | |
776 | rd = 0; | |
777 | return '\n'; | |
778 | } | |
779 | ||
780 | return c; | |
781 | } | |
782 | ||
783 | void unputc (char c) | |
784 | { | |
785 | unputbuf = c; | |
786 | unput = 1; | |
787 | } | |
788 | ||
789 | /* Read a variable name from the commandline and insert its content | |
790 | into the buffer. */ | |
791 | void getenvvar (void) | |
792 | { | |
793 | char varname[100]; | |
794 | char *p = varname; | |
795 | char *val; | |
796 | char c; | |
797 | ||
798 | c = getchar (); | |
799 | if (c == '{') | |
800 | while ((c = getchar ()) != '}') | |
801 | *(p++) = c; | |
802 | else | |
803 | { | |
804 | /* XXX: An env. variable can have characters and digits in | |
805 | its name, are more characters allowed here? */ | |
4b13b216 | 806 | while (c && (grub_isalpha (c) || grub_isdigit (c))) |
db1771cf | 807 | { |
808 | *(p++) = c; | |
809 | c = getchar (); | |
810 | } | |
811 | unputc (c); | |
812 | } | |
813 | *p = '\0'; | |
814 | ||
815 | /* The variable does not exist. */ | |
4b13b216 | 816 | val = grub_env_get (varname); |
db1771cf | 817 | if (! val) |
818 | return; | |
819 | ||
820 | /* Copy the contents of the variable into the buffer. */ | |
821 | for (p = val; *p; p++) | |
822 | *(bp++) = *p; | |
823 | } | |
824 | ||
825 | /* Read one argument. Return 1 if no variables can be read anymore, | |
826 | otherwise return 0. If there is an error, return 1, the caller | |
4b13b216 | 827 | has to check grub_errno. */ |
db1771cf | 828 | int getarg (void) |
829 | { | |
830 | char c; | |
831 | ||
832 | /* Skip all whitespaces before an argument. */ | |
833 | do { | |
834 | c = getchar (); | |
835 | } while (c == ' ' || c == '\t'); | |
836 | ||
837 | do { | |
838 | switch (c) | |
839 | { | |
840 | case '"': | |
841 | /* Double quote. */ | |
842 | while ((c = getchar ())) | |
843 | { | |
4b13b216 | 844 | if (grub_errno) |
db1771cf | 845 | return 1; |
846 | /* Read in an escaped character. */ | |
847 | if (c == '\\') | |
848 | { | |
849 | c = getchar (); | |
850 | *(bp++) = c; | |
851 | continue; | |
852 | } | |
853 | else if (c == '"') | |
854 | break; | |
855 | /* Read a variable. */ | |
856 | if (c == '$') | |
857 | { | |
858 | getenvvar (); | |
859 | continue; | |
860 | } | |
861 | *(bp++) = c; | |
862 | } | |
863 | break; | |
864 | ||
865 | case '\'': | |
866 | /* Single quote. */ | |
867 | while ((c = getchar ()) != '\'') | |
868 | { | |
4b13b216 | 869 | if (grub_errno) |
db1771cf | 870 | return 1; |
871 | ||
872 | *(bp++) = c; | |
873 | } | |
874 | break; | |
875 | ||
876 | case '\n': | |
877 | /* This was not a argument afterall. */ | |
878 | return 1; | |
879 | ||
880 | default: | |
881 | /* A normal option. */ | |
4b13b216 | 882 | while (c && (grub_isalpha (c) |
883 | || grub_isdigit (c) || grub_isgraph (c))) | |
db1771cf | 884 | { |
885 | /* Read in an escaped character. */ | |
886 | if (c == '\\') | |
887 | { | |
888 | c = getchar (); | |
889 | *(bp++) = c; | |
890 | c = getchar (); | |
891 | continue; | |
892 | } | |
893 | /* Read a variable. */ | |
894 | if (c == '$') | |
895 | { | |
896 | getenvvar (); | |
897 | c = getchar (); | |
898 | continue; | |
899 | } | |
900 | *(bp++) = c; | |
901 | c = getchar (); | |
902 | } | |
903 | unputc (c); | |
904 | ||
905 | break; | |
906 | } | |
4b13b216 | 907 | } while (! grub_isspace (c) && c != '\'' && c != '"'); |
db1771cf | 908 | |
909 | return 0; | |
910 | } | |
911 | ||
912 | /* Read in all arguments and count them. */ | |
913 | *argc = 0; | |
914 | while (1) | |
915 | { | |
916 | if (getarg ()) | |
917 | break; | |
918 | *(bp++) = '\0'; | |
919 | (*argc)++; | |
920 | } | |
921 | ||
922 | /* Check if there were no errors. */ | |
4b13b216 | 923 | if (grub_errno) |
924 | return grub_errno; | |
db1771cf | 925 | |
926 | /* Reserve memory for the return values. */ | |
4b13b216 | 927 | args = grub_malloc (bp - buffer); |
db1771cf | 928 | if (! args) |
4b13b216 | 929 | return grub_errno; |
930 | grub_memcpy (args, buffer, bp - buffer); | |
db1771cf | 931 | |
4b13b216 | 932 | *argv = grub_malloc (sizeof (char *) * (*argc + 1)); |
db1771cf | 933 | if (! *argv) |
934 | { | |
4b13b216 | 935 | grub_free (args); |
936 | return grub_errno; | |
db1771cf | 937 | } |
938 | ||
939 | /* The arguments are separated with 0's, setup argv so it points to | |
940 | the right values. */ | |
941 | bp = args; | |
942 | for (i = 0; i < *argc; i++) | |
943 | { | |
944 | (*argv)[i] = bp; | |
945 | while (*bp) | |
946 | bp++; | |
947 | bp++; | |
948 | } | |
949 | ||
950 | (*argc)--; | |
951 | return 0; | |
952 | } |