]>
Commit | Line | Data |
---|---|---|
6a161fa9 | 1 | /* misc.c - definitions of misc functions */ |
2 | /* | |
4b13b216 | 3 | * GRUB -- GRand Unified Bootloader |
18f81dfc | 4 | * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 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> | |
4a8572e9 | 26 | #include <grub/i18n.h> |
6a161fa9 | 27 | |
8b442f3f VS |
28 | static int |
29 | grub_vsnprintf_real (char *str, grub_size_t n, const char *fmt, va_list args); | |
30 | ||
70f1161d | 31 | static int |
32 | grub_iswordseparator (int c) | |
33 | { | |
34 | return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&'); | |
35 | } | |
36 | ||
4a8572e9 | 37 | /* grub_gettext_dummy is not translating anything. */ |
007d0695 | 38 | static const char * |
4a8572e9 CPE |
39 | grub_gettext_dummy (const char *s) |
40 | { | |
41 | return s; | |
42 | } | |
43 | ||
203ffbfa CPE |
44 | const char* (*grub_gettext) (const char *s) = grub_gettext_dummy; |
45 | ||
6a161fa9 | 46 | void * |
4b13b216 | 47 | grub_memmove (void *dest, const void *src, grub_size_t n) |
6a161fa9 | 48 | { |
49 | char *d = (char *) dest; | |
a5ffe966 | 50 | const char *s = (const char *) src; |
51 | ||
52 | if (d < s) | |
53 | while (n--) | |
54 | *d++ = *s++; | |
55 | else | |
56 | { | |
57 | d += n; | |
58 | s += n; | |
b39f9d20 | 59 | |
a5ffe966 | 60 | while (n--) |
61 | *--d = *--s; | |
62 | } | |
b39f9d20 | 63 | |
6a161fa9 | 64 | return dest; |
65 | } | |
6c688477 | 66 | |
f7194551 | 67 | #ifndef __APPLE__ |
062b24c2 | 68 | void *memmove (void *dest, const void *src, grub_size_t n) |
69 | __attribute__ ((alias ("grub_memmove"))); | |
8c8cc205 | 70 | /* GCC emits references to memcpy() for struct copies etc. */ |
4b13b216 | 71 | void *memcpy (void *dest, const void *src, grub_size_t n) |
72 | __attribute__ ((alias ("grub_memmove"))); | |
6c688477 | 73 | #else |
f7194551 VS |
74 | void * __attribute__ ((regparm(0))) |
75 | memcpy (void *dest, const void *src, grub_size_t n) | |
6c688477 | 76 | { |
77 | return grub_memmove (dest, src, n); | |
78 | } | |
f7194551 VS |
79 | void * __attribute__ ((regparm(0))) |
80 | memmove (void *dest, const void *src, grub_size_t n) | |
6c688477 | 81 | { |
82 | return grub_memmove (dest, src, n); | |
83 | } | |
84 | #endif | |
6a161fa9 | 85 | |
a5ffe966 | 86 | char * |
4b13b216 | 87 | grub_strcpy (char *dest, const char *src) |
a5ffe966 | 88 | { |
89 | char *p = dest; | |
90 | ||
91 | while ((*p++ = *src++) != '\0') | |
92 | ; | |
93 | ||
94 | return dest; | |
95 | } | |
96 | ||
a35eed7c | 97 | char * |
4b13b216 | 98 | grub_strncpy (char *dest, const char *src, int c) |
a35eed7c | 99 | { |
100 | char *p = dest; | |
b39f9d20 | 101 | |
e15199cb | 102 | while ((*p++ = *src++) != '\0' && --c) |
103 | ; | |
a35eed7c | 104 | |
105 | return dest; | |
106 | } | |
107 | ||
6a161fa9 | 108 | int |
4b13b216 | 109 | grub_printf (const char *fmt, ...) |
6a161fa9 | 110 | { |
111 | va_list ap; | |
112 | int ret; | |
b39f9d20 | 113 | |
6a161fa9 | 114 | va_start (ap, fmt); |
4b13b216 | 115 | ret = grub_vprintf (fmt, ap); |
6a161fa9 | 116 | va_end (ap); |
117 | ||
118 | return ret; | |
b39f9d20 | 119 | } |
6a161fa9 | 120 | |
e3069ec1 CPE |
121 | int |
122 | grub_printf_ (const char *fmt, ...) | |
123 | { | |
124 | va_list ap; | |
125 | int ret; | |
126 | ||
127 | va_start (ap, fmt); | |
128 | ret = grub_vprintf (_(fmt), ap); | |
129 | va_end (ap); | |
130 | ||
131 | return ret; | |
132 | } | |
133 | ||
c4a3e41a CPE |
134 | int |
135 | grub_puts_ (const char *s) | |
136 | { | |
137 | return grub_puts (_(s)); | |
138 | } | |
139 | ||
e6ad0555 | 140 | #if defined (__APPLE__) && ! defined (GRUB_UTIL) |
6c688477 | 141 | int |
142 | grub_err_printf (const char *fmt, ...) | |
143 | { | |
144 | va_list ap; | |
145 | int ret; | |
b39f9d20 | 146 | |
6c688477 | 147 | va_start (ap, fmt); |
148 | ret = grub_vprintf (fmt, ap); | |
149 | va_end (ap); | |
b39f9d20 | 150 | |
6c688477 | 151 | return ret; |
b39f9d20 | 152 | } |
6c688477 | 153 | #endif |
154 | ||
e6ad0555 | 155 | #if ! defined (__APPLE__) && ! defined (GRUB_UTIL) |
b86408f8 | 156 | int grub_err_printf (const char *fmt, ...) |
157 | __attribute__ ((alias("grub_printf"))); | |
158 | #endif | |
159 | ||
708b345f | 160 | void |
9cacaa17 | 161 | grub_real_dprintf (const char *file, const int line, const char *condition, |
162 | const char *fmt, ...) | |
708b345f | 163 | { |
164 | va_list args; | |
165 | const char *debug = grub_env_get ("debug"); | |
b39f9d20 | 166 | |
708b345f | 167 | if (! debug) |
168 | return; | |
b39f9d20 | 169 | |
708b345f | 170 | if (grub_strword (debug, "all") || grub_strword (debug, condition)) |
171 | { | |
9cacaa17 | 172 | grub_printf ("%s:%d: ", file, line); |
708b345f | 173 | va_start (args, fmt); |
174 | grub_vprintf (fmt, args); | |
175 | va_end (args); | |
3626810e | 176 | grub_refresh (); |
708b345f | 177 | } |
178 | } | |
179 | ||
dfed5c6b VS |
180 | #define PREALLOC_SIZE 255 |
181 | ||
6a161fa9 | 182 | int |
4b13b216 | 183 | grub_vprintf (const char *fmt, va_list args) |
6a161fa9 | 184 | { |
dfed5c6b VS |
185 | grub_size_t s; |
186 | static char buf[PREALLOC_SIZE + 1]; | |
187 | char *curbuf = buf; | |
768ec2e2 VS |
188 | va_list ap2; |
189 | va_copy (ap2, args); | |
4d4e372e | 190 | |
dfed5c6b VS |
191 | s = grub_vsnprintf_real (buf, PREALLOC_SIZE, fmt, args); |
192 | if (s > PREALLOC_SIZE) | |
193 | { | |
194 | curbuf = grub_malloc (s + 1); | |
195 | if (!curbuf) | |
196 | { | |
197 | grub_errno = GRUB_ERR_NONE; | |
198 | buf[PREALLOC_SIZE - 3] = '.'; | |
199 | buf[PREALLOC_SIZE - 2] = '.'; | |
200 | buf[PREALLOC_SIZE - 1] = '.'; | |
201 | buf[PREALLOC_SIZE] = 0; | |
84beb0ee | 202 | curbuf = buf; |
dfed5c6b VS |
203 | } |
204 | else | |
768ec2e2 | 205 | s = grub_vsnprintf_real (curbuf, s, fmt, ap2); |
dfed5c6b VS |
206 | } |
207 | ||
c1860f87 VS |
208 | va_end (ap2); |
209 | ||
dfed5c6b VS |
210 | grub_xputs (curbuf); |
211 | ||
212 | if (curbuf != buf) | |
213 | grub_free (curbuf); | |
214 | ||
215 | return s; | |
6a161fa9 | 216 | } |
217 | ||
218 | int | |
4b13b216 | 219 | grub_memcmp (const void *s1, const void *s2, grub_size_t n) |
6a161fa9 | 220 | { |
ce41ab7a VS |
221 | const grub_uint8_t *t1 = s1; |
222 | const grub_uint8_t *t2 = s2; | |
b39f9d20 | 223 | |
6a161fa9 | 224 | while (n--) |
225 | { | |
226 | if (*t1 != *t2) | |
227 | return (int) *t1 - (int) *t2; | |
228 | ||
229 | t1++; | |
230 | t2++; | |
231 | } | |
232 | ||
233 | return 0; | |
234 | } | |
f7194551 | 235 | #ifndef __APPLE__ |
21c8cbb1 | 236 | int memcmp (const void *s1, const void *s2, grub_size_t n) |
062b24c2 | 237 | __attribute__ ((alias ("grub_memcmp"))); |
18f81dfc | 238 | #else |
f7194551 VS |
239 | int __attribute__ ((regparm(0))) |
240 | memcmp (const void *s1, const void *s2, grub_size_t n) | |
18f81dfc YB |
241 | { |
242 | return grub_memcmp (s1, s2, n); | |
243 | } | |
6c688477 | 244 | #endif |
6a161fa9 | 245 | |
246 | int | |
4b13b216 | 247 | grub_strcmp (const char *s1, const char *s2) |
6a161fa9 | 248 | { |
249 | while (*s1 && *s2) | |
250 | { | |
251 | if (*s1 != *s2) | |
1806b56e | 252 | break; |
b39f9d20 | 253 | |
6a161fa9 | 254 | s1++; |
255 | s2++; | |
256 | } | |
257 | ||
ce41ab7a | 258 | return (int) (grub_uint8_t) *s1 - (int) (grub_uint8_t) *s2; |
6a161fa9 | 259 | } |
260 | ||
a35eed7c | 261 | int |
8de3495c | 262 | grub_strncmp (const char *s1, const char *s2, grub_size_t n) |
a35eed7c | 263 | { |
8de3495c | 264 | if (n == 0) |
265 | return 0; | |
b39f9d20 | 266 | |
8de3495c | 267 | while (*s1 && *s2 && --n) |
a35eed7c | 268 | { |
269 | if (*s1 != *s2) | |
1806b56e | 270 | break; |
b39f9d20 | 271 | |
a35eed7c | 272 | s1++; |
273 | s2++; | |
a35eed7c | 274 | } |
275 | ||
ce41ab7a | 276 | return (int) (grub_uint8_t) *s1 - (int) (grub_uint8_t) *s2; |
a35eed7c | 277 | } |
278 | ||
6a161fa9 | 279 | char * |
4b13b216 | 280 | grub_strchr (const char *s, int c) |
6a161fa9 | 281 | { |
a50569e1 | 282 | do |
6a161fa9 | 283 | { |
284 | if (*s == c) | |
285 | return (char *) s; | |
6a161fa9 | 286 | } |
a50569e1 | 287 | while (*s++); |
6a161fa9 | 288 | |
289 | return 0; | |
290 | } | |
291 | ||
292 | char * | |
4b13b216 | 293 | grub_strrchr (const char *s, int c) |
6a161fa9 | 294 | { |
a50569e1 | 295 | char *p = NULL; |
6a161fa9 | 296 | |
a50569e1 | 297 | do |
6a161fa9 | 298 | { |
299 | if (*s == c) | |
300 | p = (char *) s; | |
6a161fa9 | 301 | } |
a50569e1 | 302 | while (*s++); |
6a161fa9 | 303 | |
304 | return p; | |
305 | } | |
306 | ||
708b345f | 307 | int |
308 | grub_strword (const char *haystack, const char *needle) | |
309 | { | |
310 | const char *n_pos = needle; | |
311 | ||
312 | while (grub_iswordseparator (*haystack)) | |
313 | haystack++; | |
314 | ||
315 | while (*haystack) | |
316 | { | |
317 | /* Crawl both the needle and the haystack word we're on. */ | |
318 | while(*haystack && !grub_iswordseparator (*haystack) | |
319 | && *haystack == *n_pos) | |
320 | { | |
321 | haystack++; | |
322 | n_pos++; | |
323 | } | |
324 | ||
325 | /* If we reached the end of both words at the same time, the word | |
326 | is found. If not, eat everything in the haystack that isn't the | |
327 | next word (or the end of string) and "reset" the needle. */ | |
328 | if ( (!*haystack || grub_iswordseparator (*haystack)) | |
329 | && (!*n_pos || grub_iswordseparator (*n_pos))) | |
330 | return 1; | |
331 | else | |
332 | { | |
333 | n_pos = needle; | |
334 | while (*haystack && !grub_iswordseparator (*haystack)) | |
335 | haystack++; | |
336 | while (grub_iswordseparator (*haystack)) | |
337 | haystack++; | |
338 | } | |
339 | } | |
340 | ||
341 | return 0; | |
342 | } | |
343 | ||
6a161fa9 | 344 | int |
4b13b216 | 345 | grub_isspace (int c) |
6a161fa9 | 346 | { |
347 | return (c == '\n' || c == '\r' || c == ' ' || c == '\t'); | |
348 | } | |
349 | ||
350 | int | |
4b13b216 | 351 | grub_isprint (int c) |
6a161fa9 | 352 | { |
353 | return (c >= ' ' && c <= '~'); | |
354 | } | |
355 | ||
524a1e6a | 356 | |
6a161fa9 | 357 | unsigned long |
4b13b216 | 358 | grub_strtoul (const char *str, char **end, int base) |
6a161fa9 | 359 | { |
524a1e6a | 360 | unsigned long long num; |
361 | ||
362 | num = grub_strtoull (str, end, base); | |
a4ea2dff | 363 | #if GRUB_CPU_SIZEOF_LONG != 8 |
524a1e6a | 364 | if (num > ~0UL) |
365 | { | |
d61386e2 | 366 | grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); |
524a1e6a | 367 | return ~0UL; |
368 | } | |
a4ea2dff | 369 | #endif |
524a1e6a | 370 | |
371 | return (unsigned long) num; | |
372 | } | |
373 | ||
374 | unsigned long long | |
375 | grub_strtoull (const char *str, char **end, int base) | |
376 | { | |
377 | unsigned long long num = 0; | |
6a161fa9 | 378 | int found = 0; |
b39f9d20 | 379 | |
6a161fa9 | 380 | /* Skip white spaces. */ |
4b13b216 | 381 | while (*str && grub_isspace (*str)) |
6a161fa9 | 382 | str++; |
b39f9d20 | 383 | |
6a161fa9 | 384 | /* Guess the base, if not specified. The prefix `0x' means 16, and |
385 | the prefix `0' means 8. */ | |
8cc50345 | 386 | if (str[0] == '0') |
6a161fa9 | 387 | { |
388 | if (str[1] == 'x') | |
389 | { | |
390 | if (base == 0 || base == 16) | |
391 | { | |
392 | base = 16; | |
393 | str += 2; | |
394 | } | |
395 | } | |
8cc50345 | 396 | else if (base == 0 && str[1] >= '0' && str[1] <= '7') |
6a161fa9 | 397 | base = 8; |
398 | } | |
b39f9d20 | 399 | |
6a161fa9 | 400 | if (base == 0) |
401 | base = 10; | |
402 | ||
403 | while (*str) | |
404 | { | |
405 | unsigned long digit; | |
406 | ||
4b13b216 | 407 | digit = grub_tolower (*str) - '0'; |
6a161fa9 | 408 | if (digit > 9) |
409 | { | |
410 | digit += '0' - 'a' + 10; | |
411 | if (digit >= (unsigned long) base) | |
412 | break; | |
413 | } | |
414 | ||
415 | found = 1; | |
524a1e6a | 416 | |
417 | /* NUM * BASE + DIGIT > ~0ULL */ | |
418 | if (num > grub_divmod64 (~0ULL - digit, base, 0)) | |
6a161fa9 | 419 | { |
d61386e2 VS |
420 | grub_error (GRUB_ERR_OUT_OF_RANGE, |
421 | N_("overflow is detected")); | |
524a1e6a | 422 | return ~0ULL; |
6a161fa9 | 423 | } |
424 | ||
e15199cb | 425 | num = num * base + digit; |
6a161fa9 | 426 | str++; |
427 | } | |
428 | ||
429 | if (! found) | |
430 | { | |
d61386e2 VS |
431 | grub_error (GRUB_ERR_BAD_NUMBER, |
432 | N_("unrecognized number")); | |
6a161fa9 | 433 | return 0; |
434 | } | |
b39f9d20 | 435 | |
6a161fa9 | 436 | if (end) |
437 | *end = (char *) str; | |
438 | ||
439 | return num; | |
440 | } | |
441 | ||
442 | char * | |
4b13b216 | 443 | grub_strdup (const char *s) |
6a161fa9 | 444 | { |
4b13b216 | 445 | grub_size_t len; |
6a161fa9 | 446 | char *p; |
b39f9d20 | 447 | |
4b13b216 | 448 | len = grub_strlen (s) + 1; |
449 | p = (char *) grub_malloc (len); | |
5aded270 | 450 | if (! p) |
451 | return 0; | |
452 | ||
4b13b216 | 453 | return grub_memcpy (p, s, len); |
5aded270 | 454 | } |
455 | ||
456 | char * | |
4b13b216 | 457 | grub_strndup (const char *s, grub_size_t n) |
5aded270 | 458 | { |
e3741a27 | 459 | grub_size_t len; |
460 | char *p; | |
b39f9d20 | 461 | |
e3741a27 | 462 | len = grub_strlen (s); |
463 | if (len > n) | |
464 | len = n; | |
465 | p = (char *) grub_malloc (len + 1); | |
6a161fa9 | 466 | if (! p) |
467 | return 0; | |
b39f9d20 | 468 | |
e3741a27 | 469 | grub_memcpy (p, s, len); |
470 | p[len] = '\0'; | |
471 | return p; | |
6a161fa9 | 472 | } |
473 | ||
474 | void * | |
7decd202 | 475 | grub_memset (void *s, int c, grub_size_t len) |
6a161fa9 | 476 | { |
7decd202 VS |
477 | void *p = s; |
478 | grub_uint8_t pattern8 = c; | |
6a161fa9 | 479 | |
7decd202 VS |
480 | if (len >= 3 * sizeof (unsigned long)) |
481 | { | |
482 | unsigned long patternl = 0; | |
483 | grub_size_t i; | |
484 | ||
485 | for (i = 0; i < sizeof (unsigned long); i++) | |
486 | patternl |= ((unsigned long) pattern8) << (8 * i); | |
487 | ||
488 | while (len > 0 && (((grub_addr_t) p) & (sizeof (unsigned long) - 1))) | |
489 | { | |
490 | *(grub_uint8_t *) p = pattern8; | |
491 | p = (grub_uint8_t *) p + 1; | |
492 | len--; | |
493 | } | |
494 | while (len >= sizeof (unsigned long)) | |
495 | { | |
496 | *(unsigned long *) p = patternl; | |
497 | p = (unsigned long *) p + 1; | |
498 | len -= sizeof (unsigned long); | |
499 | } | |
500 | } | |
501 | ||
502 | while (len > 0) | |
503 | { | |
504 | *(grub_uint8_t *) p = pattern8; | |
505 | p = (grub_uint8_t *) p + 1; | |
506 | len--; | |
507 | } | |
6a161fa9 | 508 | |
509 | return s; | |
510 | } | |
f7194551 | 511 | #ifndef __APPLE__ |
062b24c2 | 512 | void *memset (void *s, int c, grub_size_t n) |
513 | __attribute__ ((alias ("grub_memset"))); | |
18f81dfc | 514 | #else |
f7194551 VS |
515 | void * __attribute__ ((regparm(0))) |
516 | memset (void *s, int c, grub_size_t n) | |
18f81dfc YB |
517 | { |
518 | return grub_memset (s, c, n); | |
519 | } | |
6c688477 | 520 | #endif |
6a161fa9 | 521 | |
4b13b216 | 522 | grub_size_t |
523 | grub_strlen (const char *s) | |
6a161fa9 | 524 | { |
a5ffe966 | 525 | const char *p = s; |
6a161fa9 | 526 | |
527 | while (*p) | |
528 | p++; | |
529 | ||
530 | return p - s; | |
531 | } | |
532 | ||
533 | static inline void | |
4b13b216 | 534 | grub_reverse (char *str) |
6a161fa9 | 535 | { |
4b13b216 | 536 | char *p = str + grub_strlen (str) - 1; |
6a161fa9 | 537 | |
538 | while (str < p) | |
539 | { | |
540 | char tmp; | |
541 | ||
542 | tmp = *str; | |
543 | *str = *p; | |
544 | *p = tmp; | |
545 | str++; | |
546 | p--; | |
547 | } | |
548 | } | |
549 | ||
524a1e6a | 550 | /* Divide N by D, return the quotient, and store the remainder in *R. */ |
551 | grub_uint64_t | |
bf947d36 | 552 | grub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r) |
524a1e6a | 553 | { |
554 | /* This algorithm is typically implemented by hardware. The idea | |
555 | is to get the highest bit in N, 64 times, by keeping | |
93a777e3 | 556 | upper(N * 2^i) = (Q * D + M), where upper |
524a1e6a | 557 | represents the high 64 bits in 128-bits space. */ |
558 | unsigned bits = 64; | |
93a777e3 VS |
559 | grub_uint64_t q = 0; |
560 | grub_uint64_t m = 0; | |
524a1e6a | 561 | |
cc85c3c3 | 562 | /* Skip the slow computation if 32-bit arithmetic is possible. */ |
93a777e3 | 563 | if (n < 0xffffffff && d < 0xffffffff) |
524a1e6a | 564 | { |
565 | if (r) | |
93a777e3 | 566 | *r = ((grub_uint32_t) n) % (grub_uint32_t) d; |
524a1e6a | 567 | |
93a777e3 | 568 | return ((grub_uint32_t) n) / (grub_uint32_t) d; |
524a1e6a | 569 | } |
b39f9d20 | 570 | |
524a1e6a | 571 | while (bits--) |
572 | { | |
573 | m <<= 1; | |
b39f9d20 | 574 | |
524a1e6a | 575 | if (n & (1ULL << 63)) |
576 | m |= 1; | |
b39f9d20 | 577 | |
524a1e6a | 578 | q <<= 1; |
579 | n <<= 1; | |
b39f9d20 | 580 | |
524a1e6a | 581 | if (m >= d) |
582 | { | |
583 | q |= 1; | |
584 | m -= d; | |
585 | } | |
586 | } | |
587 | ||
588 | if (r) | |
589 | *r = m; | |
b39f9d20 | 590 | |
524a1e6a | 591 | return q; |
592 | } | |
593 | ||
970d3b8a | 594 | /* Convert a long long value to a string. This function avoids 64-bit |
595 | modular arithmetic or divisions. */ | |
596 | static char * | |
597 | grub_lltoa (char *str, int c, unsigned long long n) | |
598 | { | |
599 | unsigned base = (c == 'x') ? 16 : 10; | |
600 | char *p; | |
b39f9d20 | 601 | |
970d3b8a | 602 | if ((long long) n < 0 && c == 'd') |
603 | { | |
604 | n = (unsigned long long) (-((long long) n)); | |
605 | *str++ = '-'; | |
606 | } | |
607 | ||
608 | p = str; | |
609 | ||
610 | if (base == 16) | |
611 | do | |
612 | { | |
613 | unsigned d = (unsigned) (n & 0xf); | |
614 | *p++ = (d > 9) ? d + 'a' - 10 : d + '0'; | |
615 | } | |
616 | while (n >>= 4); | |
617 | else | |
618 | /* BASE == 10 */ | |
619 | do | |
620 | { | |
bf947d36 | 621 | grub_uint64_t m; |
b39f9d20 | 622 | |
524a1e6a | 623 | n = grub_divmod64 (n, 10, &m); |
49986a9f | 624 | *p++ = m + '0'; |
970d3b8a | 625 | } |
626 | while (n); | |
b39f9d20 | 627 | |
970d3b8a | 628 | *p = 0; |
629 | ||
630 | grub_reverse (str); | |
631 | return p; | |
632 | } | |
633 | ||
8b442f3f | 634 | static int |
12d4f965 | 635 | grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0, va_list args_in) |
6a161fa9 | 636 | { |
637 | char c; | |
12d4f965 | 638 | grub_size_t n = 0; |
8b442f3f | 639 | grub_size_t count = 0; |
12d4f965 VS |
640 | grub_size_t count_args = 0; |
641 | const char *fmt; | |
18d9c7cd | 642 | auto void write_char (unsigned char ch); |
6a161fa9 | 643 | auto void write_str (const char *s); |
db1771cf | 644 | auto void write_fill (const char ch, int n); |
b39f9d20 | 645 | |
18d9c7cd | 646 | void write_char (unsigned char ch) |
6a161fa9 | 647 | { |
dfed5c6b VS |
648 | if (count < max_len) |
649 | *str++ = ch; | |
6a161fa9 | 650 | |
651 | count++; | |
652 | } | |
653 | ||
654 | void write_str (const char *s) | |
655 | { | |
656 | while (*s) | |
657 | write_char (*s++); | |
658 | } | |
db1771cf | 659 | |
12d4f965 | 660 | void write_fill (const char ch, int count_fill) |
db1771cf | 661 | { |
662 | int i; | |
12d4f965 | 663 | for (i = 0; i < count_fill; i++) |
db1771cf | 664 | write_char (ch); |
665 | } | |
b39f9d20 | 666 | |
12d4f965 | 667 | fmt = fmt0; |
6a161fa9 | 668 | while ((c = *fmt++) != 0) |
669 | { | |
670 | if (c != '%') | |
12d4f965 VS |
671 | continue; |
672 | ||
673 | if (*fmt && *fmt =='-') | |
674 | fmt++; | |
675 | ||
676 | while (*fmt && grub_isdigit (*fmt)) | |
677 | fmt++; | |
678 | ||
679 | if (*fmt && *fmt == '$') | |
680 | fmt++; | |
681 | ||
682 | if (*fmt && *fmt =='-') | |
683 | fmt++; | |
684 | ||
685 | while (*fmt && grub_isdigit (*fmt)) | |
686 | fmt++; | |
687 | ||
688 | if (*fmt && *fmt =='.') | |
689 | fmt++; | |
690 | ||
691 | while (*fmt && grub_isdigit (*fmt)) | |
692 | fmt++; | |
693 | ||
694 | c = *fmt++; | |
695 | if (c == 'l') | |
696 | { | |
697 | c = *fmt++; | |
698 | if (c == 'l') | |
699 | c = *fmt++; | |
700 | } | |
701 | switch (c) | |
702 | { | |
703 | case 'p': | |
704 | case 'x': | |
705 | case 'u': | |
706 | case 'd': | |
707 | case 'c': | |
708 | case 'C': | |
709 | case 's': | |
710 | count_args++; | |
711 | break; | |
712 | } | |
713 | } | |
714 | ||
715 | enum { INT, WCHAR, LONG, LONGLONG, POINTER } types[count_args]; | |
716 | union | |
717 | { | |
718 | int i; | |
719 | grub_uint32_t w; | |
720 | long l; | |
721 | long long ll; | |
722 | void *p; | |
723 | } args[count_args]; | |
724 | ||
725 | grub_memset (types, 0, sizeof (types)); | |
726 | ||
727 | fmt = fmt0; | |
728 | n = 0; | |
729 | while ((c = *fmt++) != 0) | |
730 | { | |
731 | int longfmt = 0; | |
732 | int longlongfmt = 0; | |
733 | grub_size_t curn; | |
734 | const char *p; | |
735 | ||
736 | if (c != '%') | |
737 | continue; | |
738 | ||
739 | curn = n++; | |
740 | ||
741 | if (*fmt && *fmt =='-') | |
742 | fmt++; | |
743 | ||
45d26abb | 744 | p = fmt; |
fd261d73 VS |
745 | |
746 | while (*fmt && grub_isdigit (*fmt)) | |
747 | fmt++; | |
748 | ||
12d4f965 VS |
749 | if (*fmt && *fmt == '$') |
750 | { | |
751 | curn = grub_strtoull (p, 0, 10) - 1; | |
752 | fmt++; | |
753 | } | |
754 | ||
45d26abb CW |
755 | if (*fmt && *fmt =='-') |
756 | fmt++; | |
757 | ||
758 | while (*fmt && grub_isdigit (*fmt)) | |
759 | fmt++; | |
760 | ||
761 | if (*fmt && *fmt =='.') | |
762 | fmt++; | |
763 | ||
12d4f965 VS |
764 | while (*fmt && grub_isdigit (*fmt)) |
765 | fmt++; | |
766 | ||
767 | c = *fmt++; | |
768 | if (c == 'l') | |
6a161fa9 | 769 | { |
12d4f965 VS |
770 | c = *fmt++; |
771 | longfmt = 1; | |
772 | if (c == 'l') | |
db1771cf | 773 | { |
12d4f965 VS |
774 | c = *fmt++; |
775 | longlongfmt = 1; | |
db1771cf | 776 | } |
12d4f965 VS |
777 | } |
778 | if (curn >= count_args) | |
779 | continue; | |
780 | switch (c) | |
781 | { | |
782 | case 'x': | |
783 | case 'u': | |
784 | case 'd': | |
785 | if (longlongfmt) | |
786 | types[curn] = LONGLONG; | |
787 | else if (longfmt) | |
788 | types[curn] = LONG; | |
789 | else | |
790 | types[curn] = INT; | |
791 | break; | |
792 | case 'p': | |
793 | case 's': | |
794 | types[curn] = POINTER; | |
795 | break; | |
796 | case 'c': | |
797 | types[curn] = INT; | |
798 | break; | |
799 | case 'C': | |
800 | types[curn] = WCHAR; | |
801 | break; | |
802 | } | |
803 | } | |
804 | ||
805 | for (n = 0; n < count_args; n++) | |
806 | switch (types[n]) | |
807 | { | |
808 | case WCHAR: | |
809 | args[n].w = va_arg (args_in, grub_uint32_t); | |
810 | break; | |
811 | case POINTER: | |
812 | args[n].p = va_arg (args_in, void *); | |
813 | break; | |
814 | case INT: | |
815 | args[n].i = va_arg (args_in, int); | |
816 | break; | |
817 | case LONG: | |
818 | args[n].l = va_arg (args_in, long); | |
819 | break; | |
820 | case LONGLONG: | |
821 | args[n].ll = va_arg (args_in, long long); | |
822 | break; | |
823 | } | |
824 | ||
825 | fmt = fmt0; | |
e75d76e1 | 826 | |
12d4f965 VS |
827 | n = 0; |
828 | while ((c = *fmt++) != 0) | |
829 | { | |
830 | char tmp[32]; | |
831 | char *p; | |
832 | unsigned int format1 = 0; | |
833 | unsigned int format2 = ~ 0U; | |
834 | char zerofill = ' '; | |
835 | int rightfill = 0; | |
836 | int longfmt = 0; | |
837 | int longlongfmt = 0; | |
838 | int unsig = 0; | |
839 | grub_size_t curn; | |
840 | ||
841 | if (c != '%') | |
842 | { | |
843 | write_char (c); | |
844 | continue; | |
845 | } | |
846 | ||
847 | curn = n++; | |
848 | ||
849 | rescan:; | |
850 | ||
851 | if (*fmt && *fmt =='-') | |
852 | { | |
853 | rightfill = 1; | |
854 | fmt++; | |
855 | } | |
856 | ||
857 | p = (char *) fmt; | |
858 | /* Read formatting parameters. */ | |
859 | while (*p && grub_isdigit (*p)) | |
860 | p++; | |
861 | ||
862 | if (p > fmt) | |
863 | { | |
864 | char s[p - fmt + 1]; | |
865 | grub_strncpy (s, fmt, p - fmt); | |
866 | s[p - fmt] = 0; | |
867 | if (s[0] == '0') | |
868 | zerofill = '0'; | |
869 | format1 = grub_strtoul (s, 0, 10); | |
870 | fmt = p; | |
871 | } | |
872 | ||
873 | if (*p && *p == '.') | |
874 | { | |
875 | p++; | |
876 | fmt++; | |
4b13b216 | 877 | while (*p && grub_isdigit (*p)) |
db1771cf | 878 | p++; |
879 | ||
880 | if (p > fmt) | |
881 | { | |
12d4f965 VS |
882 | char fstr[p - fmt + 1]; |
883 | grub_strncpy (fstr, fmt, p - fmt); | |
884 | fstr[p - fmt] = 0; | |
885 | format2 = grub_strtoul (fstr, 0, 10); | |
db1771cf | 886 | fmt = p; |
d31c24f1 | 887 | } |
12d4f965 VS |
888 | } |
889 | if (*fmt == '$') | |
890 | { | |
891 | curn = format1 - 1; | |
892 | fmt++; | |
893 | format1 = 0; | |
894 | format2 = ~ 0U; | |
895 | zerofill = ' '; | |
896 | rightfill = 0; | |
897 | ||
898 | goto rescan; | |
899 | } | |
d31c24f1 | 900 | |
12d4f965 VS |
901 | c = *fmt++; |
902 | if (c == 'l') | |
903 | { | |
904 | longfmt = 1; | |
db1771cf | 905 | c = *fmt++; |
e75d76e1 | 906 | if (c == 'l') |
907 | { | |
12d4f965 | 908 | longlongfmt = 1; |
e75d76e1 | 909 | c = *fmt++; |
910 | } | |
12d4f965 | 911 | } |
db1771cf | 912 | |
12d4f965 VS |
913 | if (curn >= count_args) |
914 | continue; | |
915 | ||
916 | switch (c) | |
917 | { | |
918 | case 'p': | |
919 | write_str ("0x"); | |
920 | c = 'x'; | |
921 | longlongfmt |= (sizeof (void *) == sizeof (long long)); | |
922 | /* Fall through. */ | |
923 | case 'x': | |
924 | case 'u': | |
925 | unsig = 1; | |
926 | /* Fall through. */ | |
927 | case 'd': | |
928 | if (longlongfmt) | |
929 | grub_lltoa (tmp, c, args[curn].ll); | |
930 | else if (longfmt && unsig) | |
931 | grub_lltoa (tmp, c, (unsigned long) args[curn].l); | |
932 | else if (longfmt) | |
933 | grub_lltoa (tmp, c, args[curn].l); | |
934 | else if (unsig) | |
935 | grub_lltoa (tmp, c, (unsigned) args[curn].i); | |
936 | else | |
937 | grub_lltoa (tmp, c, args[curn].i); | |
938 | if (! rightfill && grub_strlen (tmp) < format1) | |
939 | write_fill (zerofill, format1 - grub_strlen (tmp)); | |
940 | write_str (tmp); | |
941 | if (rightfill && grub_strlen (tmp) < format1) | |
942 | write_fill (zerofill, format1 - grub_strlen (tmp)); | |
943 | break; | |
944 | ||
945 | case 'c': | |
946 | write_char (args[curn].i & 0xff); | |
947 | break; | |
948 | ||
949 | case 'C': | |
950 | { | |
951 | grub_uint32_t code = args[curn].w; | |
952 | int shift; | |
953 | unsigned mask; | |
954 | ||
955 | if (code <= 0x7f) | |
956 | { | |
957 | shift = 0; | |
958 | mask = 0; | |
959 | } | |
960 | else if (code <= 0x7ff) | |
961 | { | |
962 | shift = 6; | |
963 | mask = 0xc0; | |
964 | } | |
965 | else if (code <= 0xffff) | |
966 | { | |
967 | shift = 12; | |
968 | mask = 0xe0; | |
969 | } | |
970 | else if (code <= 0x1fffff) | |
971 | { | |
972 | shift = 18; | |
973 | mask = 0xf0; | |
974 | } | |
975 | else if (code <= 0x3ffffff) | |
976 | { | |
977 | shift = 24; | |
978 | mask = 0xf8; | |
979 | } | |
980 | else if (code <= 0x7fffffff) | |
981 | { | |
982 | shift = 30; | |
983 | mask = 0xfc; | |
984 | } | |
985 | else | |
18d9c7cd | 986 | { |
12d4f965 VS |
987 | code = '?'; |
988 | shift = 0; | |
989 | mask = 0; | |
18d9c7cd | 990 | } |
12d4f965 VS |
991 | |
992 | write_char (mask | (code >> shift)); | |
993 | ||
994 | for (shift -= 6; shift >= 0; shift -= 6) | |
995 | write_char (0x80 | (0x3f & (code >> shift))); | |
996 | } | |
997 | break; | |
998 | ||
999 | case 's': | |
1000 | p = args[curn].p; | |
1001 | if (p) | |
1002 | { | |
1003 | grub_size_t len = 0; | |
1004 | while (len < format2 && p[len]) | |
1005 | len++; | |
1006 | ||
1007 | if (!rightfill && len < format1) | |
1008 | write_fill (zerofill, format1 - len); | |
1009 | ||
1010 | grub_size_t i; | |
1011 | for (i = 0; i < len; i++) | |
1012 | write_char (*p++); | |
1013 | ||
1014 | if (rightfill && len < format1) | |
1015 | write_fill (zerofill, format1 - len); | |
6a161fa9 | 1016 | } |
12d4f965 VS |
1017 | else |
1018 | write_str ("(null)"); | |
1019 | ||
1020 | break; | |
1021 | ||
1022 | default: | |
1023 | write_char (c); | |
1024 | break; | |
6a161fa9 | 1025 | } |
1026 | } | |
1027 | ||
dfed5c6b | 1028 | *str = '\0'; |
1f7315a3 | 1029 | |
6a161fa9 | 1030 | return count; |
1031 | } | |
1032 | ||
1033 | int | |
8b442f3f VS |
1034 | grub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list ap) |
1035 | { | |
1036 | grub_size_t ret; | |
1037 | ||
1038 | if (!n) | |
1039 | return 0; | |
1040 | ||
1041 | n--; | |
1042 | ||
1043 | ret = grub_vsnprintf_real (str, n, fmt, ap); | |
1044 | ||
1045 | return ret < n ? ret : n; | |
1046 | } | |
1047 | ||
1048 | int | |
1049 | grub_snprintf (char *str, grub_size_t n, const char *fmt, ...) | |
6a161fa9 | 1050 | { |
1051 | va_list ap; | |
1052 | int ret; | |
b39f9d20 | 1053 | |
6a161fa9 | 1054 | va_start (ap, fmt); |
8b442f3f VS |
1055 | ret = grub_vsnprintf (str, n, fmt, ap); |
1056 | va_end (ap); | |
1057 | ||
1058 | return ret; | |
1059 | } | |
1060 | ||
8b442f3f | 1061 | char * |
61eb45ee | 1062 | grub_xvasprintf (const char *fmt, va_list ap) |
8b442f3f VS |
1063 | { |
1064 | grub_size_t s, as = PREALLOC_SIZE; | |
1065 | char *ret; | |
1066 | ||
1067 | while (1) | |
1068 | { | |
768ec2e2 | 1069 | va_list ap2; |
8b442f3f VS |
1070 | ret = grub_malloc (as + 1); |
1071 | if (!ret) | |
1072 | return NULL; | |
1073 | ||
3809cb41 AV |
1074 | va_copy (ap2, ap); |
1075 | ||
768ec2e2 | 1076 | s = grub_vsnprintf_real (ret, as, fmt, ap2); |
c1860f87 VS |
1077 | |
1078 | va_end (ap2); | |
1079 | ||
8b442f3f VS |
1080 | if (s <= as) |
1081 | return ret; | |
1082 | ||
1083 | grub_free (ret); | |
1084 | as = s; | |
1085 | } | |
1086 | } | |
1087 | ||
1088 | char * | |
61eb45ee | 1089 | grub_xasprintf (const char *fmt, ...) |
8b442f3f VS |
1090 | { |
1091 | va_list ap; | |
1092 | char *ret; | |
1093 | ||
1094 | va_start (ap, fmt); | |
61eb45ee | 1095 | ret = grub_xvasprintf (fmt, ap); |
6a161fa9 | 1096 | va_end (ap); |
1097 | ||
1098 | return ret; | |
1099 | } | |
db1771cf | 1100 | |
9cacaa17 | 1101 | /* Abort GRUB. This function does not return. */ |
1102 | void | |
1103 | grub_abort (void) | |
1104 | { | |
f4c623e1 VS |
1105 | grub_printf ("\nAborted."); |
1106 | ||
8eca55a6 RM |
1107 | #ifndef GRUB_UTIL |
1108 | if (grub_term_inputs) | |
1109 | #endif | |
9cacaa17 | 1110 | { |
f4c623e1 VS |
1111 | grub_printf (" Press any key to exit."); |
1112 | grub_getkey (); | |
9cacaa17 | 1113 | } |
2965c7cc | 1114 | |
9cacaa17 | 1115 | grub_exit (); |
1116 | } | |
6c688477 | 1117 | |
e6ad0555 | 1118 | #if ! defined (__APPLE__) && !defined (GRUB_UTIL) |
71538dff | 1119 | /* GCC emits references to abort(). */ |
1120 | void abort (void) __attribute__ ((alias ("grub_abort"))); | |
6c688477 | 1121 | #endif |
9035dce4 | 1122 | |
742f9232 | 1123 | #if NEED_REGISTER_FRAME_INFO && !defined(GRUB_UTIL) |
4b0cd8f8 VS |
1124 | void __register_frame_info (void) |
1125 | { | |
1126 | } | |
1127 | ||
1128 | void __deregister_frame_info (void) | |
1129 | { | |
1130 | } | |
1131 | #endif | |
fa4b8490 | 1132 | |
e744219b VS |
1133 | #if BOOT_TIME_STATS |
1134 | ||
1135 | #include <grub/time.h> | |
1136 | ||
1137 | struct grub_boot_time *grub_boot_time_head; | |
1138 | static struct grub_boot_time **boot_time_last = &grub_boot_time_head; | |
1139 | ||
1140 | void | |
1141 | grub_real_boot_time (const char *file, | |
1142 | const int line, | |
1143 | const char *fmt, ...) | |
1144 | { | |
1145 | struct grub_boot_time *n; | |
1146 | va_list args; | |
1147 | ||
1148 | grub_error_push (); | |
1149 | n = grub_malloc (sizeof (*n)); | |
1150 | if (!n) | |
1151 | { | |
1152 | grub_errno = 0; | |
1153 | grub_error_pop (); | |
1154 | return; | |
1155 | } | |
1156 | n->file = file; | |
1157 | n->line = line; | |
1158 | n->tp = grub_get_time_ms (); | |
1159 | n->next = 0; | |
1160 | ||
1161 | va_start (args, fmt); | |
1162 | n->msg = grub_xvasprintf (fmt, args); | |
1163 | va_end (args); | |
1164 | ||
1165 | *boot_time_last = n; | |
1166 | boot_time_last = &n->next; | |
1167 | ||
1168 | grub_errno = 0; | |
1169 | grub_error_pop (); | |
1170 | } | |
1171 | #endif |