2N/A/* misc.c - definitions of misc functions */
2N/A/*
2N/A * GRUB -- GRand Unified Bootloader
2N/A * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
2N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
2N/A *
2N/A * GRUB is free software: you can redistribute it and/or modify
2N/A * it under the terms of the GNU General Public License as published by
2N/A * the Free Software Foundation, either version 3 of the License, or
2N/A * (at your option) any later version.
2N/A *
2N/A * GRUB is distributed in the hope that it will be useful,
2N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
2N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2N/A * GNU General Public License for more details.
2N/A *
2N/A * You should have received a copy of the GNU General Public License
2N/A * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
2N/A */
2N/A
2N/A#include <grub/misc.h>
2N/A#include <grub/err.h>
2N/A#include <grub/mm.h>
2N/A#include <stdarg.h>
2N/A#include <grub/term.h>
2N/A#include <grub/env.h>
2N/A#include <grub/i18n.h>
2N/A#include <grub/loader.h>
2N/A
2N/Astatic int
2N/Agrub_vsnprintf_real (char *str, grub_size_t n, const char *fmt, va_list args);
2N/A
2N/Astatic int
2N/Agrub_iswordseparator (int c)
2N/A{
2N/A return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&');
2N/A}
2N/A
2N/A/* grub_gettext_dummy is not translating anything. */
2N/Astatic const char *
2N/Agrub_gettext_dummy (const char *s)
2N/A{
2N/A return s;
2N/A}
2N/A
2N/Aconst char* (*grub_gettext) (const char *s) = grub_gettext_dummy;
2N/A
2N/Avoid *
2N/Agrub_memmove (void *dest, const void *src, grub_size_t n)
2N/A{
2N/A char *d = (char *) dest;
2N/A const char *s = (const char *) src;
2N/A
2N/A if (d < s)
2N/A while (n--)
2N/A *d++ = *s++;
2N/A else
2N/A {
2N/A d += n;
2N/A s += n;
2N/A
2N/A while (n--)
2N/A *--d = *--s;
2N/A }
2N/A
2N/A return dest;
2N/A}
2N/A
2N/A#if !defined(APPLE_CC) && !defined(__sun__)
2N/Avoid *memmove (void *dest, const void *src, grub_size_t n)
2N/A __attribute__ ((alias ("grub_memmove")));
2N/A/* GCC emits references to memcpy() for struct copies etc. */
2N/Avoid *memcpy (void *dest, const void *src, grub_size_t n)
2N/A __attribute__ ((alias ("grub_memmove")));
2N/A#else
2N/Avoid *memcpy (void *dest, const void *src, grub_size_t n)
2N/A{
2N/A return grub_memmove (dest, src, n);
2N/A}
2N/Avoid *memmove (void *dest, const void *src, grub_size_t n)
2N/A{
2N/A return grub_memmove (dest, src, n);
2N/A}
2N/A#endif
2N/A
2N/Achar *
2N/Agrub_strcpy (char *dest, const char *src)
2N/A{
2N/A char *p = dest;
2N/A
2N/A while ((*p++ = *src++) != '\0')
2N/A ;
2N/A
2N/A return dest;
2N/A}
2N/A
2N/Achar *
2N/Agrub_strncpy (char *dest, const char *src, int c)
2N/A{
2N/A char *p = dest;
2N/A
2N/A while ((*p++ = *src++) != '\0' && --c)
2N/A ;
2N/A
2N/A return dest;
2N/A}
2N/A
2N/Achar *
2N/Agrub_stpcpy (char *dest, const char *src)
2N/A{
2N/A char *d = dest;
2N/A const char *s = src;
2N/A
2N/A do
2N/A *d++ = *s;
2N/A while (*s++ != '\0');
2N/A
2N/A return d - 1;
2N/A}
2N/A
2N/Aint
2N/Agrub_printf (const char *fmt, ...)
2N/A{
2N/A va_list ap;
2N/A int ret;
2N/A
2N/A va_start (ap, fmt);
2N/A ret = grub_vprintf (fmt, ap);
2N/A va_end (ap);
2N/A
2N/A return ret;
2N/A}
2N/A
2N/Aint
2N/Agrub_printf_ (const char *fmt, ...)
2N/A{
2N/A va_list ap;
2N/A int ret;
2N/A
2N/A va_start (ap, fmt);
2N/A ret = grub_vprintf (_(fmt), ap);
2N/A va_end (ap);
2N/A
2N/A return ret;
2N/A}
2N/A
2N/Aint
2N/Agrub_puts_ (const char *s)
2N/A{
2N/A return grub_puts (_(s));
2N/A}
2N/A
2N/A#if defined (APPLE_CC) && ! defined (GRUB_UTIL)
2N/Aint
2N/Agrub_err_printf (const char *fmt, ...)
2N/A{
2N/A va_list ap;
2N/A int ret;
2N/A
2N/A va_start (ap, fmt);
2N/A ret = grub_vprintf (fmt, ap);
2N/A va_end (ap);
2N/A
2N/A return ret;
2N/A}
2N/A#endif
2N/A
2N/A#if ! defined (APPLE_CC) && ! defined (GRUB_UTIL)
2N/Aint grub_err_printf (const char *fmt, ...)
2N/A__attribute__ ((alias("grub_printf")));
2N/A#endif
2N/A
2N/Avoid
2N/Agrub_real_dprintf (const char *file, const int line, const char *condition,
2N/A const char *fmt, ...)
2N/A{
2N/A va_list args;
2N/A const char *debug = grub_env_get ("debug");
2N/A
2N/A if (! debug)
2N/A return;
2N/A
2N/A if (grub_strword (debug, "all") || grub_strword (debug, condition))
2N/A {
2N/A grub_printf ("%s:%d: ", file, line);
2N/A va_start (args, fmt);
2N/A grub_vprintf (fmt, args);
2N/A va_end (args);
2N/A grub_refresh ();
2N/A }
2N/A}
2N/A
2N/A#define PREALLOC_SIZE 255
2N/A
2N/Aint
2N/Agrub_vprintf (const char *fmt, va_list args)
2N/A{
2N/A grub_size_t s;
2N/A static char buf[PREALLOC_SIZE + 1];
2N/A char *curbuf = buf;
2N/A va_list ap2;
2N/A va_copy (ap2, args);
2N/A
2N/A s = grub_vsnprintf_real (buf, PREALLOC_SIZE, fmt, args);
2N/A if (s > PREALLOC_SIZE)
2N/A {
2N/A curbuf = grub_malloc (s + 1);
2N/A if (!curbuf)
2N/A {
2N/A grub_errno = GRUB_ERR_NONE;
2N/A buf[PREALLOC_SIZE - 3] = '.';
2N/A buf[PREALLOC_SIZE - 2] = '.';
2N/A buf[PREALLOC_SIZE - 1] = '.';
2N/A buf[PREALLOC_SIZE] = 0;
2N/A curbuf = buf;
2N/A }
2N/A else
2N/A s = grub_vsnprintf_real (curbuf, s, fmt, ap2);
2N/A }
2N/A
2N/A va_end (ap2);
2N/A
2N/A grub_xputs (curbuf);
2N/A
2N/A if (curbuf != buf)
2N/A grub_free (curbuf);
2N/A
2N/A return s;
2N/A}
2N/A
2N/Aint
2N/Agrub_memcmp (const void *s1, const void *s2, grub_size_t n)
2N/A{
2N/A const char *t1 = s1;
2N/A const char *t2 = s2;
2N/A
2N/A while (n--)
2N/A {
2N/A if (*t1 != *t2)
2N/A return (int) *t1 - (int) *t2;
2N/A
2N/A t1++;
2N/A t2++;
2N/A }
2N/A
2N/A return 0;
2N/A}
2N/A#if !defined(APPLE_CC) && !defined(__sun__)
2N/Aint memcmp (const void *s1, const void *s2, grub_size_t n)
2N/A __attribute__ ((alias ("grub_memcmp")));
2N/A#else
2N/Aint memcmp (const void *s1, const void *s2, grub_size_t n)
2N/A{
2N/A return grub_memcmp (s1, s2, n);
2N/A}
2N/A#endif
2N/A
2N/Aint
2N/Agrub_strcmp (const char *s1, const char *s2)
2N/A{
2N/A while (*s1 && *s2)
2N/A {
2N/A if (*s1 != *s2)
2N/A break;
2N/A
2N/A s1++;
2N/A s2++;
2N/A }
2N/A
2N/A return (int) *s1 - (int) *s2;
2N/A}
2N/A
2N/Aint
2N/Agrub_strncmp (const char *s1, const char *s2, grub_size_t n)
2N/A{
2N/A if (n == 0)
2N/A return 0;
2N/A
2N/A while (*s1 && *s2 && --n)
2N/A {
2N/A if (*s1 != *s2)
2N/A break;
2N/A
2N/A s1++;
2N/A s2++;
2N/A }
2N/A
2N/A return (int) *s1 - (int) *s2;
2N/A}
2N/A
2N/Achar *
2N/Agrub_strchr (const char *s, int c)
2N/A{
2N/A do
2N/A {
2N/A if (*s == c)
2N/A return (char *) s;
2N/A }
2N/A while (*s++);
2N/A
2N/A return 0;
2N/A}
2N/A
2N/Achar *
2N/Agrub_strrchr (const char *s, int c)
2N/A{
2N/A char *p = NULL;
2N/A
2N/A do
2N/A {
2N/A if (*s == c)
2N/A p = (char *) s;
2N/A }
2N/A while (*s++);
2N/A
2N/A return p;
2N/A}
2N/A
2N/Aint
2N/Agrub_strword (const char *haystack, const char *needle)
2N/A{
2N/A const char *n_pos = needle;
2N/A
2N/A while (grub_iswordseparator (*haystack))
2N/A haystack++;
2N/A
2N/A while (*haystack)
2N/A {
2N/A /* Crawl both the needle and the haystack word we're on. */
2N/A while(*haystack && !grub_iswordseparator (*haystack)
2N/A && *haystack == *n_pos)
2N/A {
2N/A haystack++;
2N/A n_pos++;
2N/A }
2N/A
2N/A /* If we reached the end of both words at the same time, the word
2N/A is found. If not, eat everything in the haystack that isn't the
2N/A next word (or the end of string) and "reset" the needle. */
2N/A if ( (!*haystack || grub_iswordseparator (*haystack))
2N/A && (!*n_pos || grub_iswordseparator (*n_pos)))
2N/A return 1;
2N/A else
2N/A {
2N/A n_pos = needle;
2N/A while (*haystack && !grub_iswordseparator (*haystack))
2N/A haystack++;
2N/A while (grub_iswordseparator (*haystack))
2N/A haystack++;
2N/A }
2N/A }
2N/A
2N/A return 0;
2N/A}
2N/A
2N/Aint
2N/Agrub_isspace (int c)
2N/A{
2N/A return (c == '\n' || c == '\r' || c == ' ' || c == '\t');
2N/A}
2N/A
2N/Aint
2N/Agrub_isprint (int c)
2N/A{
2N/A return (c >= ' ' && c <= '~');
2N/A}
2N/A
2N/A
2N/Aunsigned long
2N/Agrub_strtoul (const char *str, char **end, int base)
2N/A{
2N/A unsigned long long num;
2N/A
2N/A num = grub_strtoull (str, end, base);
2N/A if (num > ~0UL)
2N/A {
2N/A grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow is detected");
2N/A return ~0UL;
2N/A }
2N/A
2N/A return (unsigned long) num;
2N/A}
2N/A
2N/Aunsigned long long
2N/Agrub_strtoull (const char *str, char **end, int base)
2N/A{
2N/A unsigned long long num = 0;
2N/A int found = 0;
2N/A
2N/A /* Skip white spaces. */
2N/A while (*str && grub_isspace (*str))
2N/A str++;
2N/A
2N/A /* Guess the base, if not specified. The prefix `0x' means 16, and
2N/A the prefix `0' means 8. */
2N/A if (str[0] == '0')
2N/A {
2N/A if (str[1] == 'x')
2N/A {
2N/A if (base == 0 || base == 16)
2N/A {
2N/A base = 16;
2N/A str += 2;
2N/A }
2N/A }
2N/A else if (base == 0 && str[1] >= '0' && str[1] <= '7')
2N/A base = 8;
2N/A }
2N/A
2N/A if (base == 0)
2N/A base = 10;
2N/A
2N/A while (*str)
2N/A {
2N/A unsigned long digit;
2N/A
2N/A digit = grub_tolower (*str) - '0';
2N/A if (digit > 9)
2N/A {
2N/A digit += '0' - 'a' + 10;
2N/A if (digit >= (unsigned long) base)
2N/A break;
2N/A }
2N/A
2N/A found = 1;
2N/A
2N/A /* NUM * BASE + DIGIT > ~0ULL */
2N/A if (num > grub_divmod64 (~0ULL - digit, base, 0))
2N/A {
2N/A grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow is detected");
2N/A return ~0ULL;
2N/A }
2N/A
2N/A num = num * base + digit;
2N/A str++;
2N/A }
2N/A
2N/A if (! found)
2N/A {
2N/A grub_error (GRUB_ERR_BAD_NUMBER, "unrecognized number");
2N/A return 0;
2N/A }
2N/A
2N/A if (end)
2N/A *end = (char *) str;
2N/A
2N/A return num;
2N/A}
2N/A
2N/Achar *
2N/Agrub_strdup (const char *s)
2N/A{
2N/A grub_size_t len;
2N/A char *p;
2N/A
2N/A len = grub_strlen (s) + 1;
2N/A p = (char *) grub_malloc (len);
2N/A if (! p)
2N/A return 0;
2N/A
2N/A return grub_memcpy (p, s, len);
2N/A}
2N/A
2N/Achar *
2N/Agrub_strndup (const char *s, grub_size_t n)
2N/A{
2N/A grub_size_t len;
2N/A char *p;
2N/A
2N/A len = grub_strlen (s);
2N/A if (len > n)
2N/A len = n;
2N/A p = (char *) grub_malloc (len + 1);
2N/A if (! p)
2N/A return 0;
2N/A
2N/A grub_memcpy (p, s, len);
2N/A p[len] = '\0';
2N/A return p;
2N/A}
2N/A
2N/Avoid *
2N/Agrub_memset (void *s, int c, grub_size_t len)
2N/A{
2N/A void *p = s;
2N/A grub_uint8_t pattern8 = c;
2N/A
2N/A if (len >= 3 * sizeof (unsigned long))
2N/A {
2N/A unsigned long patternl = 0;
2N/A grub_size_t i;
2N/A
2N/A for (i = 0; i < sizeof (unsigned long); i++)
2N/A patternl |= ((unsigned long) pattern8) << (8 * i);
2N/A
2N/A while (len > 0 && (((grub_addr_t) p) & (sizeof (unsigned long) - 1)))
2N/A {
2N/A *(grub_uint8_t *) p = pattern8;
2N/A p = (grub_uint8_t *) p + 1;
2N/A len--;
2N/A }
2N/A while (len >= sizeof (unsigned long))
2N/A {
2N/A *(unsigned long *) p = patternl;
2N/A p = (unsigned long *) p + 1;
2N/A len -= sizeof (unsigned long);
2N/A }
2N/A }
2N/A
2N/A while (len > 0)
2N/A {
2N/A *(grub_uint8_t *) p = pattern8;
2N/A p = (grub_uint8_t *) p + 1;
2N/A len--;
2N/A }
2N/A
2N/A return s;
2N/A}
2N/A#ifndef APPLE_CC
2N/A#ifdef __sun__
2N/A#pragma weak memset=grub_memset
2N/A#else
2N/Avoid *memset (void *s, int c, grub_size_t n)
2N/A __attribute__ ((alias ("grub_memset")));
2N/A#endif
2N/A#else
2N/Avoid *memset (void *s, int c, grub_size_t n)
2N/A{
2N/A return grub_memset (s, c, n);
2N/A}
2N/A#endif
2N/A
2N/Agrub_size_t
2N/Agrub_strlen (const char *s)
2N/A{
2N/A const char *p = s;
2N/A
2N/A while (*p)
2N/A p++;
2N/A
2N/A return p - s;
2N/A}
2N/A
2N/Astatic inline void
2N/Agrub_reverse (char *str)
2N/A{
2N/A char *p = str + grub_strlen (str) - 1;
2N/A
2N/A while (str < p)
2N/A {
2N/A char tmp;
2N/A
2N/A tmp = *str;
2N/A *str = *p;
2N/A *p = tmp;
2N/A str++;
2N/A p--;
2N/A }
2N/A}
2N/A
2N/A/* Divide N by D, return the quotient, and store the remainder in *R. */
2N/Agrub_uint64_t
2N/Agrub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r)
2N/A{
2N/A /* This algorithm is typically implemented by hardware. The idea
2N/A is to get the highest bit in N, 64 times, by keeping
2N/A upper(N * 2^i) = (Q * D + M), where upper
2N/A represents the high 64 bits in 128-bits space. */
2N/A unsigned bits = 64;
2N/A grub_uint64_t q = 0;
2N/A grub_uint64_t m = 0;
2N/A
2N/A /* Skip the slow computation if 32-bit arithmetic is possible. */
2N/A if (n < 0xffffffff && d < 0xffffffff)
2N/A {
2N/A if (r)
2N/A *r = ((grub_uint32_t) n) % (grub_uint32_t) d;
2N/A
2N/A return ((grub_uint32_t) n) / (grub_uint32_t) d;
2N/A }
2N/A
2N/A while (bits--)
2N/A {
2N/A m <<= 1;
2N/A
2N/A if (n & (1ULL << 63))
2N/A m |= 1;
2N/A
2N/A q <<= 1;
2N/A n <<= 1;
2N/A
2N/A if (m >= d)
2N/A {
2N/A q |= 1;
2N/A m -= d;
2N/A }
2N/A }
2N/A
2N/A if (r)
2N/A *r = m;
2N/A
2N/A return q;
2N/A}
2N/A
2N/A/* Convert a long long value to a string. This function avoids 64-bit
2N/A modular arithmetic or divisions. */
2N/Astatic char *
2N/Agrub_lltoa (char *str, int c, unsigned long long n)
2N/A{
2N/A unsigned base = (c == 'x') ? 16 : 10;
2N/A char *p;
2N/A
2N/A if ((long long) n < 0 && c == 'd')
2N/A {
2N/A n = (unsigned long long) (-((long long) n));
2N/A *str++ = '-';
2N/A }
2N/A
2N/A p = str;
2N/A
2N/A if (base == 16)
2N/A do
2N/A {
2N/A unsigned d = (unsigned) (n & 0xf);
2N/A *p++ = (d > 9) ? d + 'a' - 10 : d + '0';
2N/A }
2N/A while (n >>= 4);
2N/A else
2N/A /* BASE == 10 */
2N/A do
2N/A {
2N/A grub_uint64_t m;
2N/A
2N/A n = grub_divmod64 (n, 10, &m);
2N/A *p++ = m + '0';
2N/A }
2N/A while (n);
2N/A
2N/A *p = 0;
2N/A
2N/A grub_reverse (str);
2N/A return p;
2N/A}
2N/A
2N/Astatic int
2N/Agrub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0, va_list args_in)
2N/A{
2N/A char c;
2N/A grub_size_t n = 0;
2N/A grub_size_t count = 0;
2N/A grub_size_t count_args = 0;
2N/A const char *fmt;
2N/A auto void write_char (unsigned char ch);
2N/A auto void write_str (const char *s);
2N/A auto void write_fill (const char ch, int n);
2N/A
2N/A void write_char (unsigned char ch)
2N/A {
2N/A if (count < max_len)
2N/A *str++ = ch;
2N/A
2N/A count++;
2N/A }
2N/A
2N/A void write_str (const char *s)
2N/A {
2N/A while (*s)
2N/A write_char (*s++);
2N/A }
2N/A
2N/A void write_fill (const char ch, int count_fill)
2N/A {
2N/A int i;
2N/A for (i = 0; i < count_fill; i++)
2N/A write_char (ch);
2N/A }
2N/A
2N/A fmt = fmt0;
2N/A while ((c = *fmt++) != 0)
2N/A {
2N/A if (c != '%')
2N/A continue;
2N/A
2N/A if (*fmt && *fmt =='-')
2N/A fmt++;
2N/A
2N/A while (*fmt && grub_isdigit (*fmt))
2N/A fmt++;
2N/A
2N/A if (*fmt && *fmt == '$')
2N/A fmt++;
2N/A
2N/A if (*fmt && *fmt =='-')
2N/A fmt++;
2N/A
2N/A while (*fmt && grub_isdigit (*fmt))
2N/A fmt++;
2N/A
2N/A if (*fmt && *fmt =='.')
2N/A fmt++;
2N/A
2N/A while (*fmt && grub_isdigit (*fmt))
2N/A fmt++;
2N/A
2N/A c = *fmt++;
2N/A if (c == 'l')
2N/A {
2N/A c = *fmt++;
2N/A if (c == 'l')
2N/A c = *fmt++;
2N/A }
2N/A switch (c)
2N/A {
2N/A case 'p':
2N/A case 'x':
2N/A case 'u':
2N/A case 'd':
2N/A case 'c':
2N/A case 'C':
2N/A case 's':
2N/A count_args++;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A enum { INT, WCHAR, LONG, LONGLONG, POINTER } types[count_args];
2N/A union
2N/A {
2N/A int i;
2N/A grub_uint32_t w;
2N/A long l;
2N/A long long ll;
2N/A void *p;
2N/A } args[count_args];
2N/A
2N/A grub_memset (types, 0, sizeof (types));
2N/A
2N/A fmt = fmt0;
2N/A n = 0;
2N/A while ((c = *fmt++) != 0)
2N/A {
2N/A int longfmt = 0;
2N/A int longlongfmt = 0;
2N/A grub_size_t curn;
2N/A const char *p;
2N/A
2N/A if (c != '%')
2N/A continue;
2N/A
2N/A curn = n++;
2N/A
2N/A if (*fmt && *fmt =='-')
2N/A fmt++;
2N/A
2N/A while (*fmt && grub_isdigit (*fmt))
2N/A fmt++;
2N/A
2N/A if (*fmt && *fmt =='.')
2N/A fmt++;
2N/A
2N/A while (*fmt && grub_isdigit (*fmt))
2N/A fmt++;
2N/A
2N/A p = fmt;
2N/A
2N/A if (*fmt && *fmt == '$')
2N/A {
2N/A curn = grub_strtoull (p, 0, 10) - 1;
2N/A fmt++;
2N/A }
2N/A
2N/A while (*fmt && grub_isdigit (*fmt))
2N/A fmt++;
2N/A
2N/A c = *fmt++;
2N/A if (c == 'l')
2N/A {
2N/A c = *fmt++;
2N/A longfmt = 1;
2N/A if (c == 'l')
2N/A {
2N/A c = *fmt++;
2N/A longlongfmt = 1;
2N/A }
2N/A }
2N/A if (curn >= count_args)
2N/A continue;
2N/A switch (c)
2N/A {
2N/A case 'x':
2N/A case 'u':
2N/A case 'd':
2N/A if (longlongfmt)
2N/A types[curn] = LONGLONG;
2N/A else if (longfmt)
2N/A types[curn] = LONG;
2N/A else
2N/A types[curn] = INT;
2N/A break;
2N/A case 'p':
2N/A case 's':
2N/A types[curn] = POINTER;
2N/A break;
2N/A case 'c':
2N/A types[curn] = INT;
2N/A break;
2N/A case 'C':
2N/A types[curn] = WCHAR;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A for (n = 0; n < count_args; n++)
2N/A switch (types[n])
2N/A {
2N/A case WCHAR:
2N/A args[n].w = va_arg (args_in, grub_uint32_t);
2N/A break;
2N/A case POINTER:
2N/A args[n].p = va_arg (args_in, void *);
2N/A break;
2N/A case INT:
2N/A args[n].i = va_arg (args_in, int);
2N/A break;
2N/A case LONG:
2N/A args[n].l = va_arg (args_in, long);
2N/A break;
2N/A case LONGLONG:
2N/A args[n].ll = va_arg (args_in, long long);
2N/A break;
2N/A }
2N/A
2N/A fmt = fmt0;
2N/A
2N/A n = 0;
2N/A while ((c = *fmt++) != 0)
2N/A {
2N/A char tmp[32];
2N/A char *p;
2N/A unsigned int format1 = 0;
2N/A unsigned int format2 = ~ 0U;
2N/A char zerofill = ' ';
2N/A int rightfill = 0;
2N/A int longfmt = 0;
2N/A int longlongfmt = 0;
2N/A int unsig = 0;
2N/A grub_size_t curn;
2N/A
2N/A if (c != '%')
2N/A {
2N/A write_char (c);
2N/A continue;
2N/A }
2N/A
2N/A curn = n++;
2N/A
2N/A rescan:;
2N/A
2N/A if (*fmt && *fmt == '%')
2N/A {
2N/A write_char (*fmt);
2N/A fmt++;
2N/A continue;
2N/A }
2N/A
2N/A if (*fmt && *fmt =='-')
2N/A {
2N/A rightfill = 1;
2N/A fmt++;
2N/A }
2N/A
2N/A p = (char *) fmt;
2N/A /* Read formatting parameters. */
2N/A while (*p && grub_isdigit (*p))
2N/A p++;
2N/A
2N/A if (p > fmt)
2N/A {
2N/A char s[p - fmt + 1];
2N/A grub_strncpy (s, fmt, p - fmt);
2N/A s[p - fmt] = 0;
2N/A if (s[0] == '0')
2N/A zerofill = '0';
2N/A format1 = grub_strtoul (s, 0, 10);
2N/A fmt = p;
2N/A }
2N/A
2N/A if (*p && *p == '.')
2N/A {
2N/A p++;
2N/A fmt++;
2N/A while (*p && grub_isdigit (*p))
2N/A p++;
2N/A
2N/A if (p > fmt)
2N/A {
2N/A char fstr[p - fmt + 1];
2N/A grub_strncpy (fstr, fmt, p - fmt);
2N/A fstr[p - fmt] = 0;
2N/A format2 = grub_strtoul (fstr, 0, 10);
2N/A fmt = p;
2N/A }
2N/A }
2N/A if (*fmt == '$')
2N/A {
2N/A curn = format1 - 1;
2N/A fmt++;
2N/A format1 = 0;
2N/A format2 = ~ 0U;
2N/A zerofill = ' ';
2N/A rightfill = 0;
2N/A
2N/A goto rescan;
2N/A }
2N/A
2N/A c = *fmt++;
2N/A if (c == 'l')
2N/A {
2N/A longfmt = 1;
2N/A c = *fmt++;
2N/A if (c == 'l')
2N/A {
2N/A longlongfmt = 1;
2N/A c = *fmt++;
2N/A }
2N/A }
2N/A
2N/A if (curn >= count_args)
2N/A continue;
2N/A
2N/A switch (c)
2N/A {
2N/A case 'p':
2N/A write_str ("0x");
2N/A c = 'x';
2N/A longlongfmt |= (sizeof (void *) == sizeof (long long));
2N/A /* Fall through. */
2N/A case 'x':
2N/A case 'u':
2N/A unsig = 1;
2N/A /* Fall through. */
2N/A case 'd':
2N/A if (longlongfmt)
2N/A grub_lltoa (tmp, c, args[curn].ll);
2N/A else if (longfmt && unsig)
2N/A grub_lltoa (tmp, c, (unsigned long) args[curn].l);
2N/A else if (longfmt)
2N/A grub_lltoa (tmp, c, args[curn].l);
2N/A else if (unsig)
2N/A grub_lltoa (tmp, c, (unsigned) args[curn].i);
2N/A else
2N/A grub_lltoa (tmp, c, args[curn].i);
2N/A if (! rightfill && grub_strlen (tmp) < format1)
2N/A write_fill (zerofill, format1 - grub_strlen (tmp));
2N/A write_str (tmp);
2N/A if (rightfill && grub_strlen (tmp) < format1)
2N/A write_fill (zerofill, format1 - grub_strlen (tmp));
2N/A break;
2N/A
2N/A case 'c':
2N/A write_char (args[curn].i & 0xff);
2N/A break;
2N/A
2N/A case 'C':
2N/A {
2N/A grub_uint32_t code = args[curn].w;
2N/A int shift;
2N/A unsigned mask;
2N/A
2N/A if (code <= 0x7f)
2N/A {
2N/A shift = 0;
2N/A mask = 0;
2N/A }
2N/A else if (code <= 0x7ff)
2N/A {
2N/A shift = 6;
2N/A mask = 0xc0;
2N/A }
2N/A else if (code <= 0xffff)
2N/A {
2N/A shift = 12;
2N/A mask = 0xe0;
2N/A }
2N/A else if (code <= 0x1fffff)
2N/A {
2N/A shift = 18;
2N/A mask = 0xf0;
2N/A }
2N/A else if (code <= 0x3ffffff)
2N/A {
2N/A shift = 24;
2N/A mask = 0xf8;
2N/A }
2N/A else if (code <= 0x7fffffff)
2N/A {
2N/A shift = 30;
2N/A mask = 0xfc;
2N/A }
2N/A else
2N/A {
2N/A code = '?';
2N/A shift = 0;
2N/A mask = 0;
2N/A }
2N/A
2N/A write_char (mask | (code >> shift));
2N/A
2N/A for (shift -= 6; shift >= 0; shift -= 6)
2N/A write_char (0x80 | (0x3f & (code >> shift)));
2N/A }
2N/A break;
2N/A
2N/A case 's':
2N/A p = args[curn].p;
2N/A if (p)
2N/A {
2N/A grub_size_t len = 0;
2N/A while (len < format2 && p[len])
2N/A len++;
2N/A
2N/A if (!rightfill && len < format1)
2N/A write_fill (zerofill, format1 - len);
2N/A
2N/A grub_size_t i;
2N/A for (i = 0; i < len; i++)
2N/A write_char (*p++);
2N/A
2N/A if (rightfill && len < format1)
2N/A write_fill (zerofill, format1 - len);
2N/A }
2N/A else
2N/A write_str ("(null)");
2N/A
2N/A break;
2N/A
2N/A default:
2N/A write_char (c);
2N/A break;
2N/A }
2N/A }
2N/A
2N/A *str = '\0';
2N/A
2N/A return count;
2N/A}
2N/A
2N/Aint
2N/Agrub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list ap)
2N/A{
2N/A grub_size_t ret;
2N/A
2N/A if (!n)
2N/A return 0;
2N/A
2N/A n--;
2N/A
2N/A ret = grub_vsnprintf_real (str, n, fmt, ap);
2N/A
2N/A return ret < n ? ret : n;
2N/A}
2N/A
2N/Aint
2N/Agrub_snprintf (char *str, grub_size_t n, const char *fmt, ...)
2N/A{
2N/A va_list ap;
2N/A int ret;
2N/A
2N/A va_start (ap, fmt);
2N/A ret = grub_vsnprintf (str, n, fmt, ap);
2N/A va_end (ap);
2N/A
2N/A return ret;
2N/A}
2N/A
2N/Achar *
2N/Agrub_xvasprintf (const char *fmt, va_list ap)
2N/A{
2N/A grub_size_t s, as = PREALLOC_SIZE;
2N/A char *ret;
2N/A
2N/A while (1)
2N/A {
2N/A va_list ap2;
2N/A va_copy (ap2, ap);
2N/A ret = grub_malloc (as + 1);
2N/A if (!ret)
2N/A return NULL;
2N/A
2N/A s = grub_vsnprintf_real (ret, as, fmt, ap2);
2N/A
2N/A va_end (ap2);
2N/A
2N/A if (s <= as)
2N/A return ret;
2N/A
2N/A grub_free (ret);
2N/A as = s;
2N/A }
2N/A}
2N/A
2N/Achar *
2N/Agrub_xasprintf (const char *fmt, ...)
2N/A{
2N/A va_list ap;
2N/A char *ret;
2N/A
2N/A va_start (ap, fmt);
2N/A ret = grub_xvasprintf (fmt, ap);
2N/A va_end (ap);
2N/A
2N/A return ret;
2N/A}
2N/A
2N/A/* Abort GRUB. This function does not return. */
2N/Avoid
2N/Agrub_abort (void)
2N/A{
2N/A grub_printf ("\nAborted.");
2N/A
2N/A#ifndef GRUB_UTIL
2N/A if (grub_term_inputs)
2N/A#endif
2N/A {
2N/A grub_printf (" Press any key to exit.");
2N/A grub_getkey ();
2N/A }
2N/A
2N/A grub_execute_preboot_hooks(1);
2N/A grub_exit ();
2N/A}
2N/A
2N/A#if ! defined (APPLE_CC) && !defined (GRUB_UTIL)
2N/A/* GCC emits references to abort(). */
2N/Avoid abort (void) __attribute__ ((alias ("grub_abort")));
2N/A#endif
2N/A
2N/A#if NEED_ENABLE_EXECUTE_STACK && !defined(GRUB_UTIL) && !defined(GRUB_MACHINE_EMU)
2N/A/* Some gcc versions generate a call to this function
2N/A in trampolines for nested functions. */
2N/Avoid __enable_execute_stack (void *addr __attribute__ ((unused)))
2N/A{
2N/A}
2N/A#endif
2N/A
2N/A#if NEED_REGISTER_FRAME_INFO && !defined(GRUB_UTIL)
2N/Avoid __register_frame_info (void)
2N/A{
2N/A}
2N/A
2N/Avoid __deregister_frame_info (void)
2N/A{
2N/A}
2N/A#endif
2N/A
2N/Astruct grub_preboot
2N/A{
2N/A grub_err_t (*preboot_func) (int);
2N/A grub_err_t (*preboot_rest_func) (void);
2N/A grub_loader_preboot_hook_prio_t prio;
2N/A struct grub_preboot *next;
2N/A struct grub_preboot *prev;
2N/A};
2N/A
2N/Astatic struct grub_preboot *preboots_head = 0,
2N/A *preboots_tail = 0;
2N/A
2N/Agrub_err_t
2N/Agrub_execute_preboot_hooks(int noreturn)
2N/A{
2N/A struct grub_preboot *cur;
2N/A grub_err_t err = GRUB_ERR_NONE;
2N/A for (cur = preboots_head; cur; cur = cur->next)
2N/A {
2N/A err = cur->preboot_func (noreturn);
2N/A if (err)
2N/A {
2N/A for (cur = cur->prev; cur; cur = cur->prev)
2N/A cur->preboot_rest_func ();
2N/A return err;
2N/A }
2N/A }
2N/A return err;
2N/A}
2N/A
2N/Agrub_err_t
2N/Agrub_execute_preboot_cleanup_hooks(void)
2N/A{
2N/A grub_err_t err = GRUB_ERR_NONE;
2N/A struct grub_preboot *cur;
2N/A for (cur = preboots_tail; cur; cur = cur->prev)
2N/A if (! err)
2N/A err = cur->preboot_rest_func ();
2N/A else
2N/A cur->preboot_rest_func ();
2N/A return err;
2N/A}
2N/A
2N/A/* Register a preboot hook. */
2N/Astruct grub_preboot *
2N/Agrub_loader_register_preboot_hook (grub_err_t (*preboot_func) (int noreturn),
2N/A grub_err_t (*preboot_rest_func) (void),
2N/A grub_loader_preboot_hook_prio_t prio)
2N/A{
2N/A struct grub_preboot *cur, *new_preboot;
2N/A
2N/A if (! preboot_func && ! preboot_rest_func)
2N/A return 0;
2N/A
2N/A new_preboot = (struct grub_preboot *)
2N/A grub_malloc (sizeof (struct grub_preboot));
2N/A if (! new_preboot)
2N/A {
2N/A grub_error (GRUB_ERR_OUT_OF_MEMORY, "hook not added");
2N/A return 0;
2N/A }
2N/A
2N/A new_preboot->preboot_func = preboot_func;
2N/A new_preboot->preboot_rest_func = preboot_rest_func;
2N/A new_preboot->prio = prio;
2N/A
2N/A for (cur = preboots_head; cur && cur->prio > prio; cur = cur->next);
2N/A
2N/A if (cur)
2N/A {
2N/A new_preboot->next = cur;
2N/A new_preboot->prev = cur->prev;
2N/A cur->prev = new_preboot;
2N/A }
2N/A else
2N/A {
2N/A new_preboot->next = 0;
2N/A new_preboot->prev = preboots_tail;
2N/A preboots_tail = new_preboot;
2N/A }
2N/A if (new_preboot->prev)
2N/A new_preboot->prev->next = new_preboot;
2N/A else
2N/A preboots_head = new_preboot;
2N/A
2N/A return new_preboot;
2N/A}
2N/A
2N/Avoid
2N/Agrub_loader_unregister_preboot_hook (struct grub_preboot *hnd)
2N/A{
2N/A struct grub_preboot *preb = hnd;
2N/A
2N/A if (preb->next)
2N/A preb->next->prev = preb->prev;
2N/A else
2N/A preboots_tail = preb->prev;
2N/A if (preb->prev)
2N/A preb->prev->next = preb->next;
2N/A else
2N/A preboots_head = preb->next;
2N/A
2N/A grub_free (preb);
2N/A}
2N/A