opuntiaOS - an operating system targeting x86 and ARMv7
at master 9.8 kB view raw
1/* 2 * Copyright (C) 2020-2022 The opuntiaOS Project Authors. 3 * + Contributed by Nikita Melekhin <nimelehin@gmail.com> 4 * + Contributed by bellrise <bellrise.dev@gmail.com> 5 * 6 * Use of this source code is governed by a BSD-style license that can be 7 * found in the LICENSE file. 8 */ 9#include "_internal.h" 10#include <errno.h> 11#include <stdarg.h> 12#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15#include <sys/_structs.h> 16#include <sys/types.h> 17#include <unistd.h> 18 19static const char* HEX_alphabet = "0123456789ABCDEF"; 20static const char* hex_alphabet = "0123456789abcdef"; 21 22static int _printf_hex32_impl(unsigned int value, const char* alph, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) 23{ 24 int nxt = 0; 25 char tmp_buf[16]; 26 27 while (value > 0) { 28 tmp_buf[nxt++] = alph[(value % 16)]; 29 value /= 16; 30 } 31 32 callback('0', base_buf, written, callback_params); 33 callback('x', base_buf, written, callback_params); 34 if (nxt == 0) { 35 callback('0', base_buf, written, callback_params); 36 } 37 38 while (nxt) { 39 callback(tmp_buf[--nxt], base_buf, written, callback_params); 40 } 41 return 0; 42} 43 44static int _printf_hex64_impl(unsigned long value, const char* alph, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) 45{ 46 int nxt = 0; 47 char tmp_buf[32]; 48 49 while (value > 0) { 50 tmp_buf[nxt++] = alph[(value % 16)]; 51 value /= 16; 52 } 53 54 callback('0', base_buf, written, callback_params); 55 callback('x', base_buf, written, callback_params); 56 if (nxt == 0) { 57 callback('0', base_buf, written, callback_params); 58 } 59 60 while (nxt) { 61 callback(tmp_buf[--nxt], base_buf, written, callback_params); 62 } 63 return 0; 64} 65 66static int _printf_hex32(unsigned int value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) 67{ 68 return _printf_hex32_impl(value, hex_alphabet, base_buf, written, callback, callback_params); 69} 70 71static int _printf_HEX32(unsigned int value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) 72{ 73 return _printf_hex32_impl(value, HEX_alphabet, base_buf, written, callback, callback_params); 74} 75 76static int _printf_hex64(unsigned long value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) 77{ 78 return _printf_hex64_impl(value, hex_alphabet, base_buf, written, callback, callback_params); 79} 80 81static int _printf_HEX64(unsigned long value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) 82{ 83 return _printf_hex64_impl(value, HEX_alphabet, base_buf, written, callback, callback_params); 84} 85 86static int _printf_u32(unsigned int value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) 87{ 88 int nxt = 0; 89 char tmp_buf[16]; 90 91 while (value > 0) { 92 tmp_buf[nxt++] = (value % 10) + '0'; 93 value /= 10; 94 } 95 96 if (nxt == 0) { 97 callback('0', base_buf, written, callback_params); 98 } 99 100 while (nxt) { 101 callback(tmp_buf[--nxt], base_buf, written, callback_params); 102 } 103 return 0; 104} 105 106static int _printf_u64(unsigned long value, char* base_buf, size_t* written, _putch_callback callback, void* callback_params) 107{ 108 int nxt = 0; 109 char tmp_buf[32]; 110 111 while (value > 0) { 112 tmp_buf[nxt++] = (value % 10) + '0'; 113 value /= 10; 114 } 115 116 if (nxt == 0) { 117 callback('0', base_buf, written, callback_params); 118 } 119 120 while (nxt) { 121 callback(tmp_buf[--nxt], base_buf, written, callback_params); 122 } 123 return 0; 124} 125 126static int _printf_i32(int value, char* buf, size_t* written, _putch_callback callback, void* callback_params) 127{ 128 if (value < 0) { 129 callback('-', buf, written, callback_params); 130 value = -value; 131 } 132 return _printf_u32(value, buf, written, callback, callback_params); 133} 134 135static int _printf_i64(long value, char* buf, size_t* written, _putch_callback callback, void* callback_params) 136{ 137 if (value < 0) { 138 callback('-', buf, written, callback_params); 139 value = -value; 140 } 141 return _printf_u64(value, buf, written, callback, callback_params); 142} 143 144static int _printf_string(const char* value, char* buf, size_t* written, _putch_callback callback, void* callback_params) 145{ 146 size_t len = strlen(value); 147 for (size_t i = 0; i < len; i++) { 148 callback(value[i], buf, written, callback_params); 149 } 150 return 0; 151} 152 153static ssize_t _printf_internal(char* buf, const char* format, _putch_callback callback, void* callback_params, va_list arg) 154{ 155 const char* p = format; 156 size_t written = 0; 157 while (*p) { 158 int l_arg = 0; 159 int h_arg = 0; 160 if (*p == '%' && *(p + 1)) { 161 // Reading arguments 162 parse_args: 163 p++; 164 switch (*p) { 165 case 'l': 166 l_arg++; 167 if (*(p + 1)) { 168 goto parse_args; 169 } 170 break; 171 case 'h': 172 h_arg++; 173 if (*(p + 1)) { 174 goto parse_args; 175 } 176 break; 177 default: 178 break; 179 } 180 181 // Reading conversion specifiers 182 switch (*p) { 183 case 'i': 184 case 'd': 185 if (l_arg) { 186 long value = va_arg(arg, long); 187 _printf_i64(value, buf, &written, callback, callback_params); 188 } else { 189 int value = va_arg(arg, int); 190 _printf_i32(value, buf, &written, callback, callback_params); 191 } 192 break; 193 case 'u': 194 if (l_arg) { 195 uint64_t value = va_arg(arg, uint64_t); 196 _printf_u64(value, buf, &written, callback, callback_params); 197 } else { 198 uint32_t value = va_arg(arg, uint32_t); 199 _printf_u32(value, buf, &written, callback, callback_params); 200 } 201 break; 202 case 'x': 203 if (l_arg) { 204 uint64_t value = va_arg(arg, uint64_t); 205 _printf_hex64(value, buf, &written, callback, callback_params); 206 } else { 207 uint32_t value = va_arg(arg, uint32_t); 208 _printf_hex32(value, buf, &written, callback, callback_params); 209 } 210 break; 211 case 'X': 212 if (l_arg) { 213 uint64_t value = va_arg(arg, uint64_t); 214 _printf_HEX64(value, buf, &written, callback, callback_params); 215 } else { 216 uint32_t value = va_arg(arg, uint32_t); 217 _printf_HEX32(value, buf, &written, callback, callback_params); 218 } 219 break; 220 case 'c': { 221 char value = (char)va_arg(arg, int); 222 callback(value, buf, &written, callback_params); 223 } break; 224 case 's': { 225 const char* value = va_arg(arg, const char*); 226 _printf_string(value, buf, &written, callback, callback_params); 227 } break; 228 default: 229 break; 230 } 231 } else { 232 callback(*p, buf, &written, callback_params); 233 } 234 p++; 235 } 236 return written; 237} 238 239static int putch_callback_sized_buf(char ch, char* buf_base, size_t* written, void* callback_params) 240{ 241 if (!callback_params) { 242 return -1; 243 } 244 245 if (!written) { 246 return -1; 247 } 248 249 size_t n = *(size_t*)callback_params; 250 size_t vw = *written; 251 if (vw >= n) { 252 return -1; 253 } 254 buf_base[vw++] = ch; 255 *written = vw; 256 return 0; 257} 258 259int vsnprintf(char* s, size_t n, const char* format, va_list arg) 260{ 261 if (!s) { 262 return 0; 263 } 264 265 if (!n) { 266 return 0; 267 } 268 269 ssize_t wr = _printf_internal(s, format, putch_callback_sized_buf, &n, arg); 270 if (wr == n) { 271 s[n - 1] = '\0'; 272 } else { 273 s[wr] = '\0'; 274 } 275 return (int)wr; 276} 277 278int snprintf(char* s, size_t n, const char* format, ...) 279{ 280 va_list arg; 281 va_start(arg, format); 282 int res = vsnprintf(s, n, format, arg); 283 va_end(arg); 284 return res; 285} 286 287static int putch_callback_buf(char ch, char* buf_base, size_t* written, void* callback_params) 288{ 289 if (!written) { 290 return -1; 291 } 292 293 size_t vw = *written; 294 buf_base[vw++] = ch; 295 *written = vw; 296 return 0; 297} 298 299int vsprintf(char* s, const char* format, va_list arg) 300{ 301 if (!s) { 302 return 0; 303 } 304 ssize_t wr = _printf_internal(s, format, putch_callback_buf, NULL, arg); 305 s[wr] = '\0'; 306 return (int)wr; 307} 308 309int sprintf(char* s, const char* format, ...) 310{ 311 va_list arg; 312 va_start(arg, format); 313 int res = vsprintf(s, format, arg); 314 va_end(arg); 315 return res; 316} 317 318static int putch_callback_stream(char c, char* buf_base, size_t* written, void* callback_params) 319{ 320 FILE* stream = (FILE*)callback_params; 321 if (!stream) { 322 return -1; 323 } 324 return fputc(c, stream); 325} 326 327static int vfprintf(FILE* stream, const char* format, va_list arg) 328{ 329 return _printf_internal(NULL, format, putch_callback_stream, stream, arg); 330} 331 332int fprintf(FILE* stream, const char* format, ...) 333{ 334 va_list arg; 335 va_start(arg, format); 336 int res = vfprintf(stream, format, arg); 337 va_end(arg); 338 return res; 339} 340 341static int vprintf(const char* format, va_list arg) 342{ 343 return vfprintf(stdout, format, arg); 344} 345 346int printf(const char* format, ...) 347{ 348 va_list arg; 349 va_start(arg, format); 350 int ret = vprintf(format, arg); 351 va_end(arg); 352 return ret; 353}