]>
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 | |
67 | #ifndef APPLE_CC | |
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 |
74 | void *memcpy (void *dest, const void *src, grub_size_t n) | |
75 | { | |
76 | return grub_memmove (dest, src, n); | |
77 | } | |
78 | void *memmove (void *dest, const void *src, grub_size_t n) | |
79 | { | |
80 | return grub_memmove (dest, src, n); | |
81 | } | |
82 | #endif | |
6a161fa9 | 83 | |
a5ffe966 | 84 | char * |
4b13b216 | 85 | grub_strcpy (char *dest, const char *src) |
a5ffe966 | 86 | { |
87 | char *p = dest; | |
88 | ||
89 | while ((*p++ = *src++) != '\0') | |
90 | ; | |
91 | ||
92 | return dest; | |
93 | } | |
94 | ||
a35eed7c | 95 | char * |
4b13b216 | 96 | grub_strncpy (char *dest, const char *src, int c) |
a35eed7c | 97 | { |
98 | char *p = dest; | |
b39f9d20 | 99 | |
e15199cb | 100 | while ((*p++ = *src++) != '\0' && --c) |
101 | ; | |
a35eed7c | 102 | |
103 | return dest; | |
104 | } | |
105 | ||
9a5c1ade | 106 | char * |
4b13b216 | 107 | grub_stpcpy (char *dest, const char *src) |
9a5c1ade | 108 | { |
109 | char *d = dest; | |
110 | const char *s = src; | |
111 | ||
112 | do | |
113 | *d++ = *s; | |
114 | while (*s++ != '\0'); | |
115 | ||
116 | return d - 1; | |
117 | } | |
118 | ||
6a161fa9 | 119 | int |
4b13b216 | 120 | grub_printf (const char *fmt, ...) |
6a161fa9 | 121 | { |
122 | va_list ap; | |
123 | int ret; | |
b39f9d20 | 124 | |
6a161fa9 | 125 | va_start (ap, fmt); |
4b13b216 | 126 | ret = grub_vprintf (fmt, ap); |
6a161fa9 | 127 | va_end (ap); |
128 | ||
129 | return ret; | |
b39f9d20 | 130 | } |
6a161fa9 | 131 | |
e3069ec1 CPE |
132 | int |
133 | grub_printf_ (const char *fmt, ...) | |
134 | { | |
135 | va_list ap; | |
136 | int ret; | |
137 | ||
138 | va_start (ap, fmt); | |
139 | ret = grub_vprintf (_(fmt), ap); | |
140 | va_end (ap); | |
141 | ||
142 | return ret; | |
143 | } | |
144 | ||
c4a3e41a CPE |
145 | int |
146 | grub_puts_ (const char *s) | |
147 | { | |
148 | return grub_puts (_(s)); | |
149 | } | |
150 | ||
6c688477 | 151 | #if defined (APPLE_CC) && ! defined (GRUB_UTIL) |
152 | int | |
153 | grub_err_printf (const char *fmt, ...) | |
154 | { | |
155 | va_list ap; | |
156 | int ret; | |
b39f9d20 | 157 | |
6c688477 | 158 | va_start (ap, fmt); |
159 | ret = grub_vprintf (fmt, ap); | |
160 | va_end (ap); | |
b39f9d20 | 161 | |
6c688477 | 162 | return ret; |
b39f9d20 | 163 | } |
6c688477 | 164 | #endif |
165 | ||
166 | #if ! defined (APPLE_CC) && ! defined (GRUB_UTIL) | |
b86408f8 | 167 | int grub_err_printf (const char *fmt, ...) |
168 | __attribute__ ((alias("grub_printf"))); | |
169 | #endif | |
170 | ||
708b345f | 171 | void |
9cacaa17 | 172 | grub_real_dprintf (const char *file, const int line, const char *condition, |
173 | const char *fmt, ...) | |
708b345f | 174 | { |
175 | va_list args; | |
176 | const char *debug = grub_env_get ("debug"); | |
b39f9d20 | 177 | |
708b345f | 178 | if (! debug) |
179 | return; | |
b39f9d20 | 180 | |
708b345f | 181 | if (grub_strword (debug, "all") || grub_strword (debug, condition)) |
182 | { | |
9cacaa17 | 183 | grub_printf ("%s:%d: ", file, line); |
708b345f | 184 | va_start (args, fmt); |
185 | grub_vprintf (fmt, args); | |
186 | va_end (args); | |
3626810e | 187 | grub_refresh (); |
708b345f | 188 | } |
189 | } | |
190 | ||
dfed5c6b VS |
191 | #define PREALLOC_SIZE 255 |
192 | ||
6a161fa9 | 193 | int |
4b13b216 | 194 | grub_vprintf (const char *fmt, va_list args) |
6a161fa9 | 195 | { |
dfed5c6b VS |
196 | grub_size_t s; |
197 | static char buf[PREALLOC_SIZE + 1]; | |
198 | char *curbuf = buf; | |
768ec2e2 VS |
199 | va_list ap2; |
200 | va_copy (ap2, args); | |
4d4e372e | 201 | |
dfed5c6b VS |
202 | s = grub_vsnprintf_real (buf, PREALLOC_SIZE, fmt, args); |
203 | if (s > PREALLOC_SIZE) | |
204 | { | |
205 | curbuf = grub_malloc (s + 1); | |
206 | if (!curbuf) | |
207 | { | |
208 | grub_errno = GRUB_ERR_NONE; | |
209 | buf[PREALLOC_SIZE - 3] = '.'; | |
210 | buf[PREALLOC_SIZE - 2] = '.'; | |
211 | buf[PREALLOC_SIZE - 1] = '.'; | |
212 | buf[PREALLOC_SIZE] = 0; | |
84beb0ee | 213 | curbuf = buf; |
dfed5c6b VS |
214 | } |
215 | else | |
768ec2e2 | 216 | s = grub_vsnprintf_real (curbuf, s, fmt, ap2); |
dfed5c6b VS |
217 | } |
218 | ||
c1860f87 VS |
219 | va_end (ap2); |
220 | ||
dfed5c6b VS |
221 | grub_xputs (curbuf); |
222 | ||
223 | if (curbuf != buf) | |
224 | grub_free (curbuf); | |
225 | ||
226 | return s; | |
6a161fa9 | 227 | } |
228 | ||
229 | int | |
4b13b216 | 230 | grub_memcmp (const void *s1, const void *s2, grub_size_t n) |
6a161fa9 | 231 | { |
232 | const char *t1 = s1; | |
233 | const char *t2 = s2; | |
b39f9d20 | 234 | |
6a161fa9 | 235 | while (n--) |
236 | { | |
237 | if (*t1 != *t2) | |
238 | return (int) *t1 - (int) *t2; | |
239 | ||
240 | t1++; | |
241 | t2++; | |
242 | } | |
243 | ||
244 | return 0; | |
245 | } | |
6c688477 | 246 | #ifndef APPLE_CC |
21c8cbb1 | 247 | int memcmp (const void *s1, const void *s2, grub_size_t n) |
062b24c2 | 248 | __attribute__ ((alias ("grub_memcmp"))); |
18f81dfc YB |
249 | #else |
250 | int memcmp (const void *s1, const void *s2, grub_size_t n) | |
251 | { | |
252 | return grub_memcmp (s1, s2, n); | |
253 | } | |
6c688477 | 254 | #endif |
6a161fa9 | 255 | |
256 | int | |
4b13b216 | 257 | grub_strcmp (const char *s1, const char *s2) |
6a161fa9 | 258 | { |
259 | while (*s1 && *s2) | |
260 | { | |
261 | if (*s1 != *s2) | |
1806b56e | 262 | break; |
b39f9d20 | 263 | |
6a161fa9 | 264 | s1++; |
265 | s2++; | |
266 | } | |
267 | ||
268 | return (int) *s1 - (int) *s2; | |
269 | } | |
270 | ||
a35eed7c | 271 | int |
8de3495c | 272 | grub_strncmp (const char *s1, const char *s2, grub_size_t n) |
a35eed7c | 273 | { |
8de3495c | 274 | if (n == 0) |
275 | return 0; | |
b39f9d20 | 276 | |
8de3495c | 277 | while (*s1 && *s2 && --n) |
a35eed7c | 278 | { |
279 | if (*s1 != *s2) | |
1806b56e | 280 | break; |
b39f9d20 | 281 | |
a35eed7c | 282 | s1++; |
283 | s2++; | |
a35eed7c | 284 | } |
285 | ||
286 | return (int) *s1 - (int) *s2; | |
287 | } | |
288 | ||
6a161fa9 | 289 | char * |
4b13b216 | 290 | grub_strchr (const char *s, int c) |
6a161fa9 | 291 | { |
a50569e1 | 292 | do |
6a161fa9 | 293 | { |
294 | if (*s == c) | |
295 | return (char *) s; | |
6a161fa9 | 296 | } |
a50569e1 | 297 | while (*s++); |
6a161fa9 | 298 | |
299 | return 0; | |
300 | } | |
301 | ||
302 | char * | |
4b13b216 | 303 | grub_strrchr (const char *s, int c) |
6a161fa9 | 304 | { |
a50569e1 | 305 | char *p = NULL; |
6a161fa9 | 306 | |
a50569e1 | 307 | do |
6a161fa9 | 308 | { |
309 | if (*s == c) | |
310 | p = (char *) s; | |
6a161fa9 | 311 | } |
a50569e1 | 312 | while (*s++); |
6a161fa9 | 313 | |
314 | return p; | |
315 | } | |
316 | ||
708b345f | 317 | int |
318 | grub_strword (const char *haystack, const char *needle) | |
319 | { | |
320 | const char *n_pos = needle; | |
321 | ||
322 | while (grub_iswordseparator (*haystack)) | |
323 | haystack++; | |
324 | ||
325 | while (*haystack) | |
326 | { | |
327 | /* Crawl both the needle and the haystack word we're on. */ | |
328 | while(*haystack && !grub_iswordseparator (*haystack) | |
329 | && *haystack == *n_pos) | |
330 | { | |
331 | haystack++; | |
332 | n_pos++; | |
333 | } | |
334 | ||
335 | /* If we reached the end of both words at the same time, the word | |
336 | is found. If not, eat everything in the haystack that isn't the | |
337 | next word (or the end of string) and "reset" the needle. */ | |
338 | if ( (!*haystack || grub_iswordseparator (*haystack)) | |
339 | && (!*n_pos || grub_iswordseparator (*n_pos))) | |
340 | return 1; | |
341 | else | |
342 | { | |
343 | n_pos = needle; | |
344 | while (*haystack && !grub_iswordseparator (*haystack)) | |
345 | haystack++; | |
346 | while (grub_iswordseparator (*haystack)) | |
347 | haystack++; | |
348 | } | |
349 | } | |
350 | ||
351 | return 0; | |
352 | } | |
353 | ||
6a161fa9 | 354 | int |
4b13b216 | 355 | grub_isspace (int c) |
6a161fa9 | 356 | { |
357 | return (c == '\n' || c == '\r' || c == ' ' || c == '\t'); | |
358 | } | |
359 | ||
360 | int | |
4b13b216 | 361 | grub_isprint (int c) |
6a161fa9 | 362 | { |
363 | return (c >= ' ' && c <= '~'); | |
364 | } | |
365 | ||
524a1e6a | 366 | |
6a161fa9 | 367 | unsigned long |
4b13b216 | 368 | grub_strtoul (const char *str, char **end, int base) |
6a161fa9 | 369 | { |
524a1e6a | 370 | unsigned long long num; |
371 | ||
372 | num = grub_strtoull (str, end, base); | |
373 | if (num > ~0UL) | |
374 | { | |
375 | grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow is detected"); | |
376 | return ~0UL; | |
377 | } | |
378 | ||
379 | return (unsigned long) num; | |
380 | } | |
381 | ||
382 | unsigned long long | |
383 | grub_strtoull (const char *str, char **end, int base) | |
384 | { | |
385 | unsigned long long num = 0; | |
6a161fa9 | 386 | int found = 0; |
b39f9d20 | 387 | |
6a161fa9 | 388 | /* Skip white spaces. */ |
4b13b216 | 389 | while (*str && grub_isspace (*str)) |
6a161fa9 | 390 | str++; |
b39f9d20 | 391 | |
6a161fa9 | 392 | /* Guess the base, if not specified. The prefix `0x' means 16, and |
393 | the prefix `0' means 8. */ | |
8cc50345 | 394 | if (str[0] == '0') |
6a161fa9 | 395 | { |
396 | if (str[1] == 'x') | |
397 | { | |
398 | if (base == 0 || base == 16) | |
399 | { | |
400 | base = 16; | |
401 | str += 2; | |
402 | } | |
403 | } | |
8cc50345 | 404 | else if (base == 0 && str[1] >= '0' && str[1] <= '7') |
6a161fa9 | 405 | base = 8; |
406 | } | |
b39f9d20 | 407 | |
6a161fa9 | 408 | if (base == 0) |
409 | base = 10; | |
410 | ||
411 | while (*str) | |
412 | { | |
413 | unsigned long digit; | |
414 | ||
4b13b216 | 415 | digit = grub_tolower (*str) - '0'; |
6a161fa9 | 416 | if (digit > 9) |
417 | { | |
418 | digit += '0' - 'a' + 10; | |
419 | if (digit >= (unsigned long) base) | |
420 | break; | |
421 | } | |
422 | ||
423 | found = 1; | |
524a1e6a | 424 | |
425 | /* NUM * BASE + DIGIT > ~0ULL */ | |
426 | if (num > grub_divmod64 (~0ULL - digit, base, 0)) | |
6a161fa9 | 427 | { |
4b13b216 | 428 | grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow is detected"); |
524a1e6a | 429 | return ~0ULL; |
6a161fa9 | 430 | } |
431 | ||
e15199cb | 432 | num = num * base + digit; |
6a161fa9 | 433 | str++; |
434 | } | |
435 | ||
436 | if (! found) | |
437 | { | |
4b13b216 | 438 | grub_error (GRUB_ERR_BAD_NUMBER, "unrecognized number"); |
6a161fa9 | 439 | return 0; |
440 | } | |
b39f9d20 | 441 | |
6a161fa9 | 442 | if (end) |
443 | *end = (char *) str; | |
444 | ||
445 | return num; | |
446 | } | |
447 | ||
448 | char * | |
4b13b216 | 449 | grub_strdup (const char *s) |
6a161fa9 | 450 | { |
4b13b216 | 451 | grub_size_t len; |
6a161fa9 | 452 | char *p; |
b39f9d20 | 453 | |
4b13b216 | 454 | len = grub_strlen (s) + 1; |
455 | p = (char *) grub_malloc (len); | |
5aded270 | 456 | if (! p) |
457 | return 0; | |
458 | ||
4b13b216 | 459 | return grub_memcpy (p, s, len); |
5aded270 | 460 | } |
461 | ||
462 | char * | |
4b13b216 | 463 | grub_strndup (const char *s, grub_size_t n) |
5aded270 | 464 | { |
e3741a27 | 465 | grub_size_t len; |
466 | char *p; | |
b39f9d20 | 467 | |
e3741a27 | 468 | len = grub_strlen (s); |
469 | if (len > n) | |
470 | len = n; | |
471 | p = (char *) grub_malloc (len + 1); | |
6a161fa9 | 472 | if (! p) |
473 | return 0; | |
b39f9d20 | 474 | |
e3741a27 | 475 | grub_memcpy (p, s, len); |
476 | p[len] = '\0'; | |
477 | return p; | |
6a161fa9 | 478 | } |
479 | ||
480 | void * | |
7decd202 | 481 | grub_memset (void *s, int c, grub_size_t len) |
6a161fa9 | 482 | { |
7decd202 VS |
483 | void *p = s; |
484 | grub_uint8_t pattern8 = c; | |
6a161fa9 | 485 | |
7decd202 VS |
486 | if (len >= 3 * sizeof (unsigned long)) |
487 | { | |
488 | unsigned long patternl = 0; | |
489 | grub_size_t i; | |
490 | ||
491 | for (i = 0; i < sizeof (unsigned long); i++) | |
492 | patternl |= ((unsigned long) pattern8) << (8 * i); | |
493 | ||
494 | while (len > 0 && (((grub_addr_t) p) & (sizeof (unsigned long) - 1))) | |
495 | { | |
496 | *(grub_uint8_t *) p = pattern8; | |
497 | p = (grub_uint8_t *) p + 1; | |
498 | len--; | |
499 | } | |
500 | while (len >= sizeof (unsigned long)) | |
501 | { | |
502 | *(unsigned long *) p = patternl; | |
503 | p = (unsigned long *) p + 1; | |
504 | len -= sizeof (unsigned long); | |
505 | } | |
506 | } | |
507 | ||
508 | while (len > 0) | |
509 | { | |
510 | *(grub_uint8_t *) p = pattern8; | |
511 | p = (grub_uint8_t *) p + 1; | |
512 | len--; | |
513 | } | |
6a161fa9 | 514 | |
515 | return s; | |
516 | } | |
6c688477 | 517 | #ifndef APPLE_CC |
062b24c2 | 518 | void *memset (void *s, int c, grub_size_t n) |
519 | __attribute__ ((alias ("grub_memset"))); | |
18f81dfc YB |
520 | #else |
521 | void *memset (void *s, int c, grub_size_t n) | |
522 | { | |
523 | return grub_memset (s, c, n); | |
524 | } | |
6c688477 | 525 | #endif |
6a161fa9 | 526 | |
4b13b216 | 527 | grub_size_t |
528 | grub_strlen (const char *s) | |
6a161fa9 | 529 | { |
a5ffe966 | 530 | const char *p = s; |
6a161fa9 | 531 | |
532 | while (*p) | |
533 | p++; | |
534 | ||
535 | return p - s; | |
536 | } | |
537 | ||
538 | static inline void | |
4b13b216 | 539 | grub_reverse (char *str) |
6a161fa9 | 540 | { |
4b13b216 | 541 | char *p = str + grub_strlen (str) - 1; |
6a161fa9 | 542 | |
543 | while (str < p) | |
544 | { | |
545 | char tmp; | |
546 | ||
547 | tmp = *str; | |
548 | *str = *p; | |
549 | *p = tmp; | |
550 | str++; | |
551 | p--; | |
552 | } | |
553 | } | |
554 | ||
524a1e6a | 555 | /* Divide N by D, return the quotient, and store the remainder in *R. */ |
556 | grub_uint64_t | |
bf947d36 | 557 | grub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r) |
524a1e6a | 558 | { |
559 | /* This algorithm is typically implemented by hardware. The idea | |
560 | is to get the highest bit in N, 64 times, by keeping | |
93a777e3 | 561 | upper(N * 2^i) = (Q * D + M), where upper |
524a1e6a | 562 | represents the high 64 bits in 128-bits space. */ |
563 | unsigned bits = 64; | |
93a777e3 VS |
564 | grub_uint64_t q = 0; |
565 | grub_uint64_t m = 0; | |
524a1e6a | 566 | |
cc85c3c3 | 567 | /* Skip the slow computation if 32-bit arithmetic is possible. */ |
93a777e3 | 568 | if (n < 0xffffffff && d < 0xffffffff) |
524a1e6a | 569 | { |
570 | if (r) | |
93a777e3 | 571 | *r = ((grub_uint32_t) n) % (grub_uint32_t) d; |
524a1e6a | 572 | |
93a777e3 | 573 | return ((grub_uint32_t) n) / (grub_uint32_t) d; |
524a1e6a | 574 | } |
b39f9d20 | 575 | |
524a1e6a | 576 | while (bits--) |
577 | { | |
578 | m <<= 1; | |
b39f9d20 | 579 | |
524a1e6a | 580 | if (n & (1ULL << 63)) |
581 | m |= 1; | |
b39f9d20 | 582 | |
524a1e6a | 583 | q <<= 1; |
584 | n <<= 1; | |
b39f9d20 | 585 | |
524a1e6a | 586 | if (m >= d) |
587 | { | |
588 | q |= 1; | |
589 | m -= d; | |
590 | } | |
591 | } | |
592 | ||
593 | if (r) | |
594 | *r = m; | |
b39f9d20 | 595 | |
524a1e6a | 596 | return q; |
597 | } | |
598 | ||
970d3b8a | 599 | /* Convert a long long value to a string. This function avoids 64-bit |
600 | modular arithmetic or divisions. */ | |
601 | static char * | |
602 | grub_lltoa (char *str, int c, unsigned long long n) | |
603 | { | |
604 | unsigned base = (c == 'x') ? 16 : 10; | |
605 | char *p; | |
b39f9d20 | 606 | |
970d3b8a | 607 | if ((long long) n < 0 && c == 'd') |
608 | { | |
609 | n = (unsigned long long) (-((long long) n)); | |
610 | *str++ = '-'; | |
611 | } | |
612 | ||
613 | p = str; | |
614 | ||
615 | if (base == 16) | |
616 | do | |
617 | { | |
618 | unsigned d = (unsigned) (n & 0xf); | |
619 | *p++ = (d > 9) ? d + 'a' - 10 : d + '0'; | |
620 | } | |
621 | while (n >>= 4); | |
622 | else | |
623 | /* BASE == 10 */ | |
624 | do | |
625 | { | |
bf947d36 | 626 | grub_uint64_t m; |
b39f9d20 | 627 | |
524a1e6a | 628 | n = grub_divmod64 (n, 10, &m); |
49986a9f | 629 | *p++ = m + '0'; |
970d3b8a | 630 | } |
631 | while (n); | |
b39f9d20 | 632 | |
970d3b8a | 633 | *p = 0; |
634 | ||
635 | grub_reverse (str); | |
636 | return p; | |
637 | } | |
638 | ||
8b442f3f | 639 | static int |
11c22894 | 640 | grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt, va_list args) |
6a161fa9 | 641 | { |
642 | char c; | |
8b442f3f | 643 | grub_size_t count = 0; |
18d9c7cd | 644 | auto void write_char (unsigned char ch); |
6a161fa9 | 645 | auto void write_str (const char *s); |
db1771cf | 646 | auto void write_fill (const char ch, int n); |
b39f9d20 | 647 | |
18d9c7cd | 648 | void write_char (unsigned char ch) |
6a161fa9 | 649 | { |
dfed5c6b VS |
650 | if (count < max_len) |
651 | *str++ = ch; | |
6a161fa9 | 652 | |
653 | count++; | |
654 | } | |
655 | ||
656 | void write_str (const char *s) | |
657 | { | |
658 | while (*s) | |
659 | write_char (*s++); | |
660 | } | |
db1771cf | 661 | |
662 | void write_fill (const char ch, int n) | |
663 | { | |
664 | int i; | |
665 | for (i = 0; i < n; i++) | |
666 | write_char (ch); | |
667 | } | |
b39f9d20 | 668 | |
6a161fa9 | 669 | while ((c = *fmt++) != 0) |
670 | { | |
671 | if (c != '%') | |
672 | write_char (c); | |
673 | else | |
674 | { | |
970d3b8a | 675 | char tmp[32]; |
6a161fa9 | 676 | char *p; |
db1771cf | 677 | unsigned int format1 = 0; |
d31c24f1 | 678 | unsigned int format2 = ~ 0U; |
db1771cf | 679 | char zerofill = ' '; |
680 | int rightfill = 0; | |
6a161fa9 | 681 | int n; |
e75d76e1 | 682 | int longfmt = 0; |
970d3b8a | 683 | int longlongfmt = 0; |
5999d619 | 684 | int unsig = 0; |
e75d76e1 | 685 | |
db1771cf | 686 | if (*fmt && *fmt =='-') |
687 | { | |
688 | rightfill = 1; | |
689 | fmt++; | |
690 | } | |
e75d76e1 | 691 | |
db1771cf | 692 | p = (char *) fmt; |
693 | /* Read formatting parameters. */ | |
4b13b216 | 694 | while (*p && grub_isdigit (*p)) |
db1771cf | 695 | p++; |
696 | ||
697 | if (p > fmt) | |
698 | { | |
25fe6f03 | 699 | char s[p - fmt + 1]; |
4b13b216 | 700 | grub_strncpy (s, fmt, p - fmt); |
25fe6f03 | 701 | s[p - fmt] = 0; |
db1771cf | 702 | if (s[0] == '0') |
703 | zerofill = '0'; | |
4b13b216 | 704 | format1 = grub_strtoul (s, 0, 10); |
db1771cf | 705 | fmt = p; |
d31c24f1 | 706 | } |
707 | ||
708 | if (*p && *p == '.') | |
709 | { | |
710 | p++; | |
711 | fmt++; | |
712 | while (*p && grub_isdigit (*p)) | |
713 | p++; | |
714 | ||
715 | if (p > fmt) | |
db1771cf | 716 | { |
d31c24f1 | 717 | char fstr[p - fmt + 1]; |
718 | grub_strncpy (fstr, fmt, p - fmt); | |
719 | fstr[p - fmt] = 0; | |
720 | format2 = grub_strtoul (fstr, 0, 10); | |
721 | fmt = p; | |
db1771cf | 722 | } |
723 | } | |
724 | ||
725 | c = *fmt++; | |
e75d76e1 | 726 | if (c == 'l') |
727 | { | |
728 | longfmt = 1; | |
729 | c = *fmt++; | |
970d3b8a | 730 | if (c == 'l') |
731 | { | |
732 | longlongfmt = 1; | |
733 | c = *fmt++; | |
734 | } | |
e75d76e1 | 735 | } |
db1771cf | 736 | |
6a161fa9 | 737 | switch (c) |
738 | { | |
739 | case 'p': | |
740 | write_str ("0x"); | |
741 | c = 'x'; | |
d1bc1b73 | 742 | longlongfmt |= (sizeof (void *) == sizeof (long long)); |
5999d619 | 743 | /* Fall through. */ |
6a161fa9 | 744 | case 'x': |
745 | case 'u': | |
5999d619 | 746 | unsig = 1; |
747 | /* Fall through. */ | |
6a161fa9 | 748 | case 'd': |
970d3b8a | 749 | if (longlongfmt) |
750 | { | |
751 | long long ll; | |
752 | ||
753 | ll = va_arg (args, long long); | |
754 | grub_lltoa (tmp, c, ll); | |
755 | } | |
5999d619 | 756 | else if (longfmt && unsig) |
757 | { | |
758 | unsigned long l = va_arg (args, unsigned long); | |
759 | grub_lltoa (tmp, c, l); | |
760 | } | |
ed3d2bc2 | 761 | else if (longfmt) |
762 | { | |
763 | long l = va_arg (args, long); | |
5999d619 | 764 | grub_lltoa (tmp, c, l); |
765 | } | |
766 | else if (unsig) | |
767 | { | |
768 | unsigned u = va_arg (args, unsigned); | |
769 | grub_lltoa (tmp, c, u); | |
ed3d2bc2 | 770 | } |
e75d76e1 | 771 | else |
970d3b8a | 772 | { |
ed3d2bc2 | 773 | n = va_arg (args, int); |
5999d619 | 774 | grub_lltoa (tmp, c, n); |
970d3b8a | 775 | } |
776 | if (! rightfill && grub_strlen (tmp) < format1) | |
4b13b216 | 777 | write_fill (zerofill, format1 - grub_strlen (tmp)); |
6a161fa9 | 778 | write_str (tmp); |
4b13b216 | 779 | if (rightfill && grub_strlen (tmp) < format1) |
780 | write_fill (zerofill, format1 - grub_strlen (tmp)); | |
6a161fa9 | 781 | break; |
b39f9d20 | 782 | |
6a161fa9 | 783 | case 'c': |
784 | n = va_arg (args, int); | |
18d9c7cd | 785 | write_char (n & 0xff); |
786 | break; | |
787 | ||
788 | case 'C': | |
789 | { | |
4b13b216 | 790 | grub_uint32_t code = va_arg (args, grub_uint32_t); |
18d9c7cd | 791 | int shift; |
792 | unsigned mask; | |
b39f9d20 | 793 | |
18d9c7cd | 794 | if (code <= 0x7f) |
795 | { | |
796 | shift = 0; | |
797 | mask = 0; | |
798 | } | |
799 | else if (code <= 0x7ff) | |
800 | { | |
801 | shift = 6; | |
802 | mask = 0xc0; | |
803 | } | |
804 | else if (code <= 0xffff) | |
805 | { | |
806 | shift = 12; | |
807 | mask = 0xe0; | |
808 | } | |
809 | else if (code <= 0x1fffff) | |
810 | { | |
811 | shift = 18; | |
812 | mask = 0xf0; | |
813 | } | |
814 | else if (code <= 0x3ffffff) | |
815 | { | |
816 | shift = 24; | |
817 | mask = 0xf8; | |
818 | } | |
819 | else if (code <= 0x7fffffff) | |
820 | { | |
821 | shift = 30; | |
822 | mask = 0xfc; | |
823 | } | |
824 | else | |
825 | { | |
826 | code = '?'; | |
827 | shift = 0; | |
828 | mask = 0; | |
829 | } | |
830 | ||
831 | write_char (mask | (code >> shift)); | |
b39f9d20 | 832 | |
18d9c7cd | 833 | for (shift -= 6; shift >= 0; shift -= 6) |
834 | write_char (0x80 | (0x3f & (code >> shift))); | |
835 | } | |
6a161fa9 | 836 | break; |
837 | ||
838 | case 's': | |
839 | p = va_arg (args, char *); | |
840 | if (p) | |
db1771cf | 841 | { |
d31c24f1 | 842 | grub_size_t len = 0; |
843 | while (len < format2 && p[len]) | |
844 | len++; | |
845 | ||
846 | if (!rightfill && len < format1) | |
847 | write_fill (zerofill, format1 - len); | |
848 | ||
849 | grub_size_t i; | |
850 | for (i = 0; i < len; i++) | |
851 | write_char (*p++); | |
852 | ||
853 | if (rightfill && len < format1) | |
854 | write_fill (zerofill, format1 - len); | |
db1771cf | 855 | } |
6a161fa9 | 856 | else |
857 | write_str ("(null)"); | |
b39f9d20 | 858 | |
6a161fa9 | 859 | break; |
860 | ||
861 | default: | |
862 | write_char (c); | |
863 | break; | |
864 | } | |
865 | } | |
866 | } | |
867 | ||
dfed5c6b | 868 | *str = '\0'; |
1f7315a3 | 869 | |
6a161fa9 | 870 | return count; |
871 | } | |
872 | ||
873 | int | |
8b442f3f VS |
874 | grub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list ap) |
875 | { | |
876 | grub_size_t ret; | |
877 | ||
878 | if (!n) | |
879 | return 0; | |
880 | ||
881 | n--; | |
882 | ||
883 | ret = grub_vsnprintf_real (str, n, fmt, ap); | |
884 | ||
885 | return ret < n ? ret : n; | |
886 | } | |
887 | ||
888 | int | |
889 | grub_snprintf (char *str, grub_size_t n, const char *fmt, ...) | |
6a161fa9 | 890 | { |
891 | va_list ap; | |
892 | int ret; | |
b39f9d20 | 893 | |
6a161fa9 | 894 | va_start (ap, fmt); |
8b442f3f VS |
895 | ret = grub_vsnprintf (str, n, fmt, ap); |
896 | va_end (ap); | |
897 | ||
898 | return ret; | |
899 | } | |
900 | ||
8b442f3f | 901 | char * |
61eb45ee | 902 | grub_xvasprintf (const char *fmt, va_list ap) |
8b442f3f VS |
903 | { |
904 | grub_size_t s, as = PREALLOC_SIZE; | |
905 | char *ret; | |
906 | ||
907 | while (1) | |
908 | { | |
768ec2e2 VS |
909 | va_list ap2; |
910 | va_copy (ap2, ap); | |
8b442f3f VS |
911 | ret = grub_malloc (as + 1); |
912 | if (!ret) | |
913 | return NULL; | |
914 | ||
768ec2e2 | 915 | s = grub_vsnprintf_real (ret, as, fmt, ap2); |
c1860f87 VS |
916 | |
917 | va_end (ap2); | |
918 | ||
8b442f3f VS |
919 | if (s <= as) |
920 | return ret; | |
921 | ||
922 | grub_free (ret); | |
923 | as = s; | |
924 | } | |
925 | } | |
926 | ||
927 | char * | |
61eb45ee | 928 | grub_xasprintf (const char *fmt, ...) |
8b442f3f VS |
929 | { |
930 | va_list ap; | |
931 | char *ret; | |
932 | ||
933 | va_start (ap, fmt); | |
61eb45ee | 934 | ret = grub_xvasprintf (fmt, ap); |
6a161fa9 | 935 | va_end (ap); |
936 | ||
937 | return ret; | |
938 | } | |
db1771cf | 939 | |
9cacaa17 | 940 | /* Abort GRUB. This function does not return. */ |
941 | void | |
942 | grub_abort (void) | |
943 | { | |
f4c623e1 VS |
944 | grub_printf ("\nAborted."); |
945 | ||
8eca55a6 RM |
946 | #ifndef GRUB_UTIL |
947 | if (grub_term_inputs) | |
948 | #endif | |
9cacaa17 | 949 | { |
f4c623e1 VS |
950 | grub_printf (" Press any key to exit."); |
951 | grub_getkey (); | |
9cacaa17 | 952 | } |
2965c7cc | 953 | |
9cacaa17 | 954 | grub_exit (); |
955 | } | |
6c688477 | 956 | |
dda060dd | 957 | #if ! defined (APPLE_CC) && !defined (GRUB_UTIL) |
71538dff | 958 | /* GCC emits references to abort(). */ |
959 | void abort (void) __attribute__ ((alias ("grub_abort"))); | |
6c688477 | 960 | #endif |
9035dce4 | 961 | |
742f9232 | 962 | #if NEED_ENABLE_EXECUTE_STACK && !defined(GRUB_UTIL) && !defined(GRUB_MACHINE_EMU) |
9035dce4 | 963 | /* Some gcc versions generate a call to this function |
964 | in trampolines for nested functions. */ | |
af1f4f55 | 965 | void __enable_execute_stack (void *addr __attribute__ ((unused))) |
9035dce4 | 966 | { |
967 | } | |
968 | #endif | |
969 | ||
742f9232 | 970 | #if NEED_REGISTER_FRAME_INFO && !defined(GRUB_UTIL) |
4b0cd8f8 VS |
971 | void __register_frame_info (void) |
972 | { | |
973 | } | |
974 | ||
975 | void __deregister_frame_info (void) | |
976 | { | |
977 | } | |
978 | #endif | |
fa4b8490 | 979 |