]>
Commit | Line | Data |
---|---|---|
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 | |
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 | ||
9fe86034 | 97 | while ((*p = *src) != '\0') |
98 | { | |
99 | p++; | |
100 | src++; | |
101 | } | |
a5ffe966 | 102 | |
103 | return dest; | |
104 | } | |
a5ffe966 | 105 | |
ad0bd20b | 106 | char * |
107 | grub_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 | 125 | int |
4b13b216 | 126 | grub_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 | 138 | void |
9cacaa17 | 139 | grub_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 | 157 | int |
4b13b216 | 158 | grub_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 | ||
167 | int | |
4b13b216 | 168 | grub_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 | 184 | int memcmp (const void *s1, const void *s2, grub_size_t n) |
062b24c2 | 185 | __attribute__ ((alias ("grub_memcmp"))); |
6a161fa9 | 186 | |
187 | int | |
4b13b216 | 188 | grub_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 | 202 | int |
8de3495c | 203 | grub_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 | 220 | int |
221 | grub_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 | 238 | char * |
4b13b216 | 239 | grub_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 | ||
251 | char * | |
4b13b216 | 252 | grub_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. */ | |
268 | char * | |
269 | grub_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 | 312 | int |
313 | grub_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 | ||
349 | int | |
350 | grub_iswordseparator (int c) | |
351 | { | |
352 | return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&'); | |
353 | } | |
354 | ||
6a161fa9 | 355 | int |
4b13b216 | 356 | grub_isspace (int c) |
6a161fa9 | 357 | { |
358 | return (c == '\n' || c == '\r' || c == ' ' || c == '\t'); | |
359 | } | |
360 | ||
361 | int | |
4b13b216 | 362 | grub_isprint (int c) |
6a161fa9 | 363 | { |
364 | return (c >= ' ' && c <= '~'); | |
365 | } | |
366 | ||
367 | int | |
4b13b216 | 368 | grub_isalpha (int c) |
6a161fa9 | 369 | { |
370 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); | |
371 | } | |
372 | ||
db1771cf | 373 | int |
4b13b216 | 374 | grub_isdigit (int c) |
db1771cf | 375 | { |
376 | return (c >= '0' && c <= '9'); | |
377 | } | |
378 | ||
379 | int | |
4b13b216 | 380 | grub_isgraph (int c) |
db1771cf | 381 | { |
382 | return (c >= '!' && c <= '~'); | |
383 | } | |
384 | ||
6a161fa9 | 385 | int |
4b13b216 | 386 | grub_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 | 395 | unsigned long |
4b13b216 | 396 | grub_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 | ||
410 | unsigned long long | |
411 | grub_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 | ||
476 | char * | |
4b13b216 | 477 | grub_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 | ||
490 | char * | |
4b13b216 | 491 | grub_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 | ||
508 | void * | |
4b13b216 | 509 | grub_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 | 518 | void *memset (void *s, int c, grub_size_t n) |
519 | __attribute__ ((alias ("grub_memset"))); | |
6a161fa9 | 520 | |
4b13b216 | 521 | grub_size_t |
522 | grub_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 | ||
532 | static inline void | |
4b13b216 | 533 | grub_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 | 549 | static char * |
4b13b216 | 550 | grub_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. */ |
575 | grub_uint64_t | |
576 | grub_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. */ | |
620 | static char * | |
621 | grub_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 | 658 | static char * |
4b13b216 | 659 | grub_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 | 676 | int |
4b13b216 | 677 | grub_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 | ||
906 | int | |
4b13b216 | 907 | grub_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 | 920 | grub_uint8_t * |
921 | grub_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. */ | |
985 | grub_ssize_t | |
385c6a92 | 986 | grub_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 | 1052 | void |
1053 | grub_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. */ |
1064 | void | |
1065 | grub_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(). */ |
1076 | void abort (void) __attribute__ ((alias ("grub_abort"))); |