qemu/tests/tcg/minilib/printf.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015 Virtual Open Systems SAS
   3 * Author: Alexander Spyridakis <a.spyridakis@virtualopensystems.com>
   4 *
   5 * printf based on implementation by Kevin Wolf <kwolf@redhat.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * SPDX-License-Identifier: GPL-2.0-only
  12 */
  13
  14#include "minilib.h"
  15
  16typedef __builtin_va_list   va_list;
  17#define va_start(ap, X)     __builtin_va_start(ap, X)
  18#define va_arg(ap, type)    __builtin_va_arg(ap, type)
  19#define va_end(ap)          __builtin_va_end(ap)
  20
  21static void print_str(char *s)
  22{
  23    while (*s) {
  24        __sys_outc(*s++);
  25    }
  26}
  27
  28static void print_num(unsigned long long value, int base)
  29{
  30    char digits[] = "0123456789abcdef";
  31    char buf[32];
  32    int i = sizeof(buf) - 2, j;
  33
  34    /* Set the buffer to 0. See problem of before. */
  35    for (j = 0; j < 32; j++) {
  36        buf[j] = 0;
  37    }
  38
  39    do {
  40        buf[i--] = digits[value % base];
  41        value /= base;
  42    } while (value);
  43
  44    print_str(&buf[i + 1]);
  45}
  46
  47void ml_printf(const char *fmt, ...)
  48{
  49    va_list ap;
  50    char *str;
  51    int base;
  52    int has_long;
  53    int alt_form;
  54    unsigned long long val;
  55
  56    va_start(ap, fmt);
  57
  58    for (; *fmt; fmt++) {
  59        if (*fmt != '%') {
  60            __sys_outc(*fmt);
  61            continue;
  62        }
  63        fmt++;
  64
  65        if (*fmt == '#') {
  66            fmt++;
  67            alt_form = 1;
  68        } else {
  69            alt_form = 0;
  70        }
  71
  72        if (*fmt == 'l') {
  73            fmt++;
  74            if (*fmt == 'l') {
  75                fmt++;
  76                has_long = 2;
  77            } else {
  78                has_long = 1;
  79            }
  80        } else {
  81            has_long = 0;
  82        }
  83
  84        switch (*fmt) {
  85        case 'x':
  86        case 'p':
  87            base = 16;
  88            goto convert_number;
  89        case 'd':
  90        case 'i':
  91        case 'u':
  92            base = 10;
  93            goto convert_number;
  94        case 'o':
  95            base = 8;
  96            goto convert_number;
  97
  98        convert_number:
  99            switch (has_long) {
 100            case 0:
 101                val = va_arg(ap, unsigned int);
 102                break;
 103            case 1:
 104                val = va_arg(ap, unsigned long);
 105                break;
 106            case 2:
 107                val = va_arg(ap, unsigned long long);
 108                break;
 109            }
 110
 111            if (alt_form && base == 16) {
 112                print_str("0x");
 113            }
 114
 115            print_num(val, base);
 116            break;
 117
 118        case 's':
 119            str = va_arg(ap, char*);
 120            print_str(str);
 121            break;
 122        case 'c':
 123            __sys_outc(va_arg(ap, int));
 124            break;
 125        case '%':
 126            __sys_outc(*fmt);
 127            break;
 128        default:
 129            __sys_outc('%');
 130            __sys_outc(*fmt);
 131            break;
 132        }
 133    }
 134
 135    va_end(ap);
 136}
 137