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