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 16 typedef __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 21 static void print_str(char *s) 22 { 23 while (*s) { 24 __sys_outc(*s++); 25 } 26 } 27 28 static 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 47 void 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 '%': 123 __sys_outc(*fmt); 124 break; 125 default: 126 __sys_outc('%'); 127 __sys_outc(*fmt); 128 break; 129 } 130 } 131 132 va_end(ap); 133 } 134