Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / qemu-palcode / printf.c
diff --git a/qemu/roms/qemu-palcode/printf.c b/qemu/roms/qemu-palcode/printf.c
new file mode 100644 (file)
index 0000000..469b82c
--- /dev/null
@@ -0,0 +1,203 @@
+/* A reduced version of the printf function.
+
+   Copyright (C) 2011 Richard Henderson
+
+   This file is part of QEMU PALcode.
+
+   This program 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 2 of the License or
+   (at your option) any later version.
+
+   This program 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 text
+   of the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include "console.h"
+
+static int print_buf_pad(char *buf, int buflen, char *p, int width, int pad)
+{
+  int len = buf + buflen - p;
+  int r = 0;
+
+  if (width > len)
+    {
+      *--p = pad;
+      len++;
+
+      while (width > buflen)
+       {
+         crb_puts(0, p, 1);
+         width--;
+         r++;
+       }
+      while (width > len)
+       *--p = pad, len++;
+    }
+
+  crb_puts(0, p, len);
+  return r + len;
+}
+
+static int print_decimal(unsigned long val, int width, int pad)
+{
+  char buf[32];
+  char *p = buf + sizeof(buf);
+
+  if (val == 0)
+    *--p = '0';
+  else
+    {
+      do
+       {
+         unsigned long d, r;
+
+         /* Compiling with -Os results in a call to the division routine.
+            Do what the compiler ought to have done.  */
+         d = __builtin_alpha_umulh(val, 0xcccccccccccccccd);
+         d >>= 3;
+         r = val - (d * 10);
+
+         *--p = r + '0';
+         val = d;
+       }
+      while (val);
+    }
+
+  return print_buf_pad(buf, sizeof(buf), p, width, pad);
+}
+
+static int print_hex(unsigned long val, int width, char pad)
+{
+  char buf[32];
+  char *p = buf + sizeof(buf);
+
+  if (val == 0)
+    *--p = '0';
+  else
+    {
+      do
+       {
+         int d = val % 16;
+         *--p = (d < 10 ? '0' : 'a' - 10) + d;
+         val /= 16;
+       }
+      while (val);
+    }
+
+  return print_buf_pad(buf, sizeof(buf), p, width, pad);
+}
+
+int printf(const char *fmt, ...)
+{
+  va_list args;
+  unsigned long val;
+  int r = 0;
+
+  va_start(args, fmt);
+
+  for (; *fmt ; fmt++)
+    if (*fmt != '%')
+      {
+        crb_puts(0, fmt, 1);
+       r++;
+      }
+    else
+      {
+        const char *percent = fmt;
+       bool is_long = false;
+        char pad = ' ';
+        int width = 0;
+
+      restart:
+        switch (*++fmt)
+         {
+         case '%':
+           crb_puts(0, "%", 1);
+           r++;
+           break;
+
+         case 'l':
+           is_long = true;
+           goto restart;
+
+         case 'd':
+           if (is_long)
+             {
+               long d = va_arg (args, long);
+               if (d < 0)
+                 {
+                   crb_puts(0, "-", 1);
+                   d = -d;
+                 }
+               val = d;
+             }
+           else
+             {
+               int d = va_arg (args, int);
+               if (d < 0)
+                 {
+                   crb_puts(0, "-", 1);
+                   d = -d;
+                   r++;
+                 }
+               val = d;
+             }
+           goto do_unsigned;
+
+         case 'u':
+           if (is_long)
+             val = va_arg (args, unsigned long);
+           else
+             val = va_arg (args, unsigned int);
+
+         do_unsigned:
+           r += print_decimal (val, width, pad);
+           break;
+
+         case 'x':
+           if (is_long)
+             val = va_arg (args, unsigned long);
+           else
+             val = va_arg (args, unsigned int);
+           r += print_hex (val, width, pad);
+           break;
+
+         case 's':
+           {
+             const char *s = va_arg (args, const char *);
+             int len = strlen(s);
+             crb_puts(0, s, len);
+             r += len;
+           }
+           break;
+
+         case '0':
+           pad = '0';
+          case '1' ... '9':
+           width = *fmt - '0';
+           while (fmt[1] >= '0' && fmt[1] <= '9')
+             width = width * 10 + *++fmt - '0';
+           goto restart;
+
+         default:
+           {
+             int len = fmt - percent;
+             crb_puts(0, percent, len);
+             r += len;
+           }
+           break;
+         }
+      }
+
+  va_end(args);
+  return r;
+}