]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Support %1$d syntax.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 11 Nov 2011 20:14:41 +0000 (21:14 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 11 Nov 2011 20:14:41 +0000 (21:14 +0100)
* tests/printf_unit_test.c: New file.
* Makefile.util.def (printf_test): New test.
* grub-core/kern/misc.c (grub_vsnprintf_real): Support %1$d syntax.

Makefile.util.def
grub-core/kern/misc.c
tests/printf_unit_test.c [new file with mode: 0644]

index 8742d1583283134e65f94e2d7c00b2d753004e7c..89e6144686cb5ec9ee3c7d124ae267d4cda17672 100644 (file)
@@ -660,6 +660,21 @@ program = {
   ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
 };
 
+program = {
+  testcase;
+  name = printf_test;
+  common = tests/printf_unit_test.c;
+  common = tests/lib/unit_test.c;
+  common = grub-core/kern/list.c;
+  common = grub-core/kern/misc.c;
+  common = grub-core/tests/lib/test.c;
+  ldadd = libgrubmods.a;
+  ldadd = libgrubgcry.a;
+  ldadd = libgrubkern.a;
+  ldadd = grub-core/gnulib/libgnu.a;
+  ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
+};
+
 program = {
   name = grub-menulst2cfg;
   mansection = 1;
index 8dd7f453f94c7b5117ebad6acb12c82720ff1965..128139dc82c011bdcc6270d98ab09d9437e28d87 100644 (file)
@@ -637,10 +637,13 @@ grub_lltoa (char *str, int c, unsigned long long n)
 }
 
 static int
-grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt, va_list args)
+grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0, va_list args_in)
 {
   char c;
+  grub_size_t n = 0;
   grub_size_t count = 0;
+  grub_size_t count_args = 0;
+  const char *fmt;
   auto void write_char (unsigned char ch);
   auto void write_str (const char *s);
   auto void write_fill (const char ch, int n);
@@ -659,209 +662,362 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt, va_list ar
        write_char (*s++);
     }
 
-  void write_fill (const char ch, int n)
+  void write_fill (const char ch, int count_fill)
     {
       int i;
-      for (i = 0; i < n; i++)
+      for (i = 0; i < count_fill; i++)
        write_char (ch);
     }
 
+  fmt = fmt0;
   while ((c = *fmt++) != 0)
     {
       if (c != '%')
-       write_char (c);
-      else
+       continue;
+
+      if (*fmt && *fmt =='-')
+       fmt++;
+
+      while (*fmt && grub_isdigit (*fmt))
+       fmt++;
+
+      if (*fmt && *fmt == '$')
+       fmt++;
+
+      if (*fmt && *fmt =='-')
+       fmt++;
+
+      while (*fmt && grub_isdigit (*fmt))
+       fmt++;
+
+      if (*fmt && *fmt =='.')
+       fmt++;
+
+      while (*fmt && grub_isdigit (*fmt))
+       fmt++;
+
+      c = *fmt++;
+      if (c == 'l')
+       {
+         c = *fmt++;
+         if (c == 'l')
+           c = *fmt++;
+       }
+      switch (c)
+       {
+       case 'p':
+       case 'x':
+       case 'u':
+       case 'd':
+       case 'c':
+       case 'C':
+       case 's':
+         count_args++;
+         break;
+       }
+    }
+
+  enum { INT, WCHAR, LONG, LONGLONG, POINTER } types[count_args];
+  union 
+  { 
+    int i;
+    grub_uint32_t w;
+    long l;
+    long long ll;
+    void *p;
+  } args[count_args];
+
+  grub_memset (types, 0, sizeof (types));
+
+  fmt = fmt0;
+  n = 0;
+  while ((c = *fmt++) != 0)
+    {
+      int longfmt = 0;
+      int longlongfmt = 0;
+      grub_size_t curn;
+      const char *p;
+
+      if (c != '%')
+       continue;
+
+      curn = n++;
+
+      if (*fmt && *fmt =='-')
+       fmt++;
+
+      while (*fmt && grub_isdigit (*fmt))
+       fmt++;
+
+      p = fmt;
+
+      if (*fmt && *fmt == '$')
+       {
+         curn = grub_strtoull (p, 0, 10) - 1;
+         fmt++;
+       }
+
+      while (*fmt && grub_isdigit (*fmt))
+       fmt++;
+
+      c = *fmt++;
+      if (c == 'l')
        {
-         char tmp[32];
-         char *p;
-         unsigned int format1 = 0;
-         unsigned int format2 = ~ 0U;
-         char zerofill = ' ';
-         int rightfill = 0;
-         int n;
-         int longfmt = 0;
-         int longlongfmt = 0;
-         int unsig = 0;
-
-         if (*fmt && *fmt =='-')
+         c = *fmt++;
+         longfmt = 1;
+         if (c == 'l')
            {
-             rightfill = 1;
-             fmt++;
+             c = *fmt++;
+             longlongfmt = 1;
            }
+       }
+      if (curn >= count_args)
+       continue;
+      switch (c)
+       {
+       case 'x':
+       case 'u':
+       case 'd':
+         if (longlongfmt)
+           types[curn] = LONGLONG;
+         else if (longfmt)
+           types[curn] = LONG;
+         else
+           types[curn] = INT;
+         break;
+       case 'p':
+       case 's':
+         types[curn] = POINTER;
+         break;
+       case 'c':
+         types[curn] = INT;
+         break;
+       case 'C':
+         types[curn] = WCHAR;
+         break;
+       }
+    }
+
+  for (n = 0; n < count_args; n++)
+    switch (types[n])
+      {
+      case WCHAR:
+       args[n].w = va_arg (args_in, grub_uint32_t);
+       break;
+      case POINTER:
+       args[n].p = va_arg (args_in, void *);
+       break;
+      case INT:
+       args[n].i = va_arg (args_in, int);
+       break;
+      case LONG:
+       args[n].l = va_arg (args_in, long);
+       break;
+      case LONGLONG:
+       args[n].ll = va_arg (args_in, long long);
+       break;
+      }
+
+  fmt = fmt0;
 
-         p = (char *) fmt;
-         /* Read formatting parameters.  */
+  n = 0;
+  while ((c = *fmt++) != 0)
+    {
+      char tmp[32];
+      char *p;
+      unsigned int format1 = 0;
+      unsigned int format2 = ~ 0U;
+      char zerofill = ' ';
+      int rightfill = 0;
+      int longfmt = 0;
+      int longlongfmt = 0;
+      int unsig = 0;
+      grub_size_t curn;
+      
+      if (c != '%')
+       {
+         write_char (c);
+         continue;
+       }
+
+      curn = n++;
+
+    rescan:;
+
+      if (*fmt && *fmt =='-')
+       {
+         rightfill = 1;
+         fmt++;
+       }
+
+      p = (char *) fmt;
+      /* Read formatting parameters.  */
+      while (*p && grub_isdigit (*p))
+       p++;
+
+      if (p > fmt)
+       {
+         char s[p - fmt + 1];
+         grub_strncpy (s, fmt, p - fmt);
+         s[p - fmt] = 0;
+         if (s[0] == '0')
+           zerofill = '0';
+         format1 = grub_strtoul (s, 0, 10);
+         fmt = p;
+       }
+
+      if (*p && *p == '.')
+       {
+         p++;
+         fmt++;
          while (*p && grub_isdigit (*p))
            p++;
 
          if (p > fmt)
            {
-             char s[p - fmt + 1];
-             grub_strncpy (s, fmt, p - fmt);
-             s[p - fmt] = 0;
-             if (s[0] == '0')
-               zerofill = '0';
-             format1 = grub_strtoul (s, 0, 10);
+             char fstr[p - fmt + 1];
+             grub_strncpy (fstr, fmt, p - fmt);
+             fstr[p - fmt] = 0;
+             format2 = grub_strtoul (fstr, 0, 10);
              fmt = p;
            }
+       }
+      if (*fmt == '$')
+       {
+         curn = format1 - 1;
+         fmt++;
+         format1 = 0;
+         format2 = ~ 0U;
+         zerofill = ' ';
+         rightfill = 0;
+
+         goto rescan;
+       }
 
-         if (*p && *p == '.')
-           {
-             p++;
-             fmt++;
-             while (*p && grub_isdigit (*p))
-               p++;
-
-             if (p > fmt)
-               {
-                 char fstr[p - fmt + 1];
-                 grub_strncpy (fstr, fmt, p - fmt);
-                 fstr[p - fmt] = 0;
-                 format2 = grub_strtoul (fstr, 0, 10);
-                 fmt = p;
-               }
-           }
-
+      c = *fmt++;
+      if (c == 'l')
+       {
+         longfmt = 1;
          c = *fmt++;
          if (c == 'l')
            {
-             longfmt = 1;
+             longlongfmt = 1;
              c = *fmt++;
-             if (c == 'l')
-               {
-                 longlongfmt = 1;
-                 c = *fmt++;
-               }
            }
+       }
 
-         switch (c)
-           {
-           case 'p':
-             write_str ("0x");
-             c = 'x';
-             longlongfmt |= (sizeof (void *) == sizeof (long long));
-             /* Fall through. */
-           case 'x':
-           case 'u':
-             unsig = 1;
-             /* Fall through. */
-           case 'd':
-             if (longlongfmt)
-               {
-                 long long ll;
-
-                 ll = va_arg (args, long long);
-                 grub_lltoa (tmp, c, ll);
-               }
-             else if (longfmt && unsig)
-               {
-                 unsigned long l = va_arg (args, unsigned long);
-                 grub_lltoa (tmp, c, l);
-               }
-             else if (longfmt)
-               {
-                 long l = va_arg (args, long);
-                 grub_lltoa (tmp, c, l);
-               }
-             else if (unsig)
-               {
-                 unsigned u = va_arg (args, unsigned);
-                 grub_lltoa (tmp, c, u);
-               }
-             else
-               {
-                 n = va_arg (args, int);
-                 grub_lltoa (tmp, c, n);
-               }
-             if (! rightfill && grub_strlen (tmp) < format1)
-               write_fill (zerofill, format1 - grub_strlen (tmp));
-             write_str (tmp);
-             if (rightfill && grub_strlen (tmp) < format1)
-               write_fill (zerofill, format1 - grub_strlen (tmp));
-             break;
-
-           case 'c':
-             n = va_arg (args, int);
-             write_char (n & 0xff);
-             break;
-
-           case 'C':
+      if (curn >= count_args)
+       continue;
+
+      switch (c)
+       {
+       case 'p':
+         write_str ("0x");
+         c = 'x';
+         longlongfmt |= (sizeof (void *) == sizeof (long long));
+         /* Fall through. */
+       case 'x':
+       case 'u':
+         unsig = 1;
+         /* Fall through. */
+       case 'd':
+         if (longlongfmt)
+           grub_lltoa (tmp, c, args[curn].ll);
+         else if (longfmt && unsig)
+           grub_lltoa (tmp, c, (unsigned long) args[curn].l);
+         else if (longfmt)
+           grub_lltoa (tmp, c, args[curn].l);
+         else if (unsig)
+           grub_lltoa (tmp, c, (unsigned) args[curn].i);
+         else
+           grub_lltoa (tmp, c, args[curn].i);
+         if (! rightfill && grub_strlen (tmp) < format1)
+           write_fill (zerofill, format1 - grub_strlen (tmp));
+         write_str (tmp);
+         if (rightfill && grub_strlen (tmp) < format1)
+           write_fill (zerofill, format1 - grub_strlen (tmp));
+         break;
+
+       case 'c':
+         write_char (args[curn].i & 0xff);
+         break;
+
+       case 'C':
+         {
+           grub_uint32_t code = args[curn].w;
+           int shift;
+           unsigned mask;
+
+           if (code <= 0x7f)
+             {
+               shift = 0;
+               mask = 0;
+             }
+           else if (code <= 0x7ff)
+             {
+               shift = 6;
+               mask = 0xc0;
+             }
+           else if (code <= 0xffff)
+             {
+               shift = 12;
+               mask = 0xe0;
+             }
+           else if (code <= 0x1fffff)
+             {
+               shift = 18;
+               mask = 0xf0;
+             }
+           else if (code <= 0x3ffffff)
+             {
+               shift = 24;
+               mask = 0xf8;
+             }
+           else if (code <= 0x7fffffff)
+             {
+               shift = 30;
+               mask = 0xfc;
+             }
+           else
              {
-               grub_uint32_t code = va_arg (args, grub_uint32_t);
-               int shift;
-               unsigned mask;
-
-               if (code <= 0x7f)
-                 {
-                   shift = 0;
-                   mask = 0;
-                 }
-               else if (code <= 0x7ff)
-                 {
-                   shift = 6;
-                   mask = 0xc0;
-                 }
-               else if (code <= 0xffff)
-                 {
-                   shift = 12;
-                   mask = 0xe0;
-                 }
-               else if (code <= 0x1fffff)
-                 {
-                   shift = 18;
-                   mask = 0xf0;
-                 }
-               else if (code <= 0x3ffffff)
-                 {
-                   shift = 24;
-                   mask = 0xf8;
-                 }
-               else if (code <= 0x7fffffff)
-                 {
-                   shift = 30;
-                   mask = 0xfc;
-                 }
-               else
-                 {
-                   code = '?';
-                   shift = 0;
-                   mask = 0;
-                 }
-
-               write_char (mask | (code >> shift));
-
-               for (shift -= 6; shift >= 0; shift -= 6)
-                 write_char (0x80 | (0x3f & (code >> shift)));
+               code = '?';
+               shift = 0;
+               mask = 0;
              }
-             break;
-
-           case 's':
-             p = va_arg (args, char *);
-             if (p)
-               {
-                 grub_size_t len = 0;
-                 while (len < format2 && p[len])
-                   len++;
-
-                 if (!rightfill && len < format1)
-                   write_fill (zerofill, format1 - len);
-
-                 grub_size_t i;
-                 for (i = 0; i < len; i++)
-                   write_char (*p++);
-
-                 if (rightfill && len < format1)
-                   write_fill (zerofill, format1 - len);
-               }
-             else
-               write_str ("(null)");
-
-             break;
-
-           default:
-             write_char (c);
-             break;
+
+           write_char (mask | (code >> shift));
+
+           for (shift -= 6; shift >= 0; shift -= 6)
+             write_char (0x80 | (0x3f & (code >> shift)));
+         }
+         break;
+
+       case 's':
+         p = args[curn].p;
+         if (p)
+           {
+             grub_size_t len = 0;
+             while (len < format2 && p[len])
+               len++;
+
+             if (!rightfill && len < format1)
+               write_fill (zerofill, format1 - len);
+
+             grub_size_t i;
+             for (i = 0; i < len; i++)
+               write_char (*p++);
+
+             if (rightfill && len < format1)
+               write_fill (zerofill, format1 - len);
            }
+         else
+           write_str ("(null)");
+
+         break;
+
+       default:
+         write_char (c);
+         break;
        }
     }
 
diff --git a/tests/printf_unit_test.c b/tests/printf_unit_test.c
new file mode 100644 (file)
index 0000000..6e601b4
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <grub/test.h>
+#include <grub/misc.h>
+
+static void
+printf_test (void)
+{
+  char real[512];
+  char expected[512];
+  grub_snprintf (real, sizeof (real), "%d %d %d", 1, 2, 3);
+  snprintf (expected, sizeof (expected), "%d %d %d", 1, 2, 3);
+  grub_test_assert (strcmp (real, expected) == 0);
+  grub_snprintf (real, sizeof (real), "%3$d %2$d %1$d", 1, 2, 3);
+  snprintf (expected, sizeof (expected), "%3$d %2$d %1$d", 1, 2, 3);
+  grub_test_assert (strcmp (real, expected) == 0);
+  grub_snprintf (real, sizeof (real), "%d %lld %d", 1, 2LL, 3);
+  snprintf (expected, sizeof (expected), "%d %lld %d", 1, 2LL, 3);
+  grub_test_assert (strcmp (real, expected) == 0);
+  grub_snprintf (real, sizeof (real), "%3$d %2$lld %1$d", 1, 2LL, 3);
+  snprintf (expected, sizeof (expected), "%3$d %2$lld %1$d", 1, 2LL, 3);
+  grub_test_assert (strcmp (real, expected) == 0);
+}
+
+GRUB_UNIT_TEST ("printf_unit_test", printf_test);