mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2024-11-23 08:26:23 -06:00
284 lines
7.5 KiB
C
284 lines
7.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
// Copyright (C) 2020-2021 Martin Whitaker.
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
#include "screen.h"
|
|
|
|
#include "string.h"
|
|
|
|
#include "print.h"
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Constants
|
|
//------------------------------------------------------------------------------
|
|
|
|
#define BUFFER_SIZE 64
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Private Functions
|
|
//------------------------------------------------------------------------------
|
|
|
|
static int int_to_dec_str(char buffer[], int value, int min_length, int max_length)
|
|
{
|
|
bool negative = (value < 0);
|
|
if (negative) {
|
|
value = -value;
|
|
if (min_length > 1) {
|
|
min_length--;
|
|
}
|
|
max_length--;
|
|
}
|
|
|
|
int length = 0;
|
|
while (length < min_length || (value > 0 && length < max_length)) {
|
|
buffer[length++] = '0' + (value % 10);
|
|
value /= 10;
|
|
}
|
|
if (negative) {
|
|
buffer[length++] = '-';
|
|
}
|
|
return length;
|
|
}
|
|
|
|
static int uint_to_dec_str(char buffer[], uintptr_t value, int min_length, int max_length)
|
|
{
|
|
int length = 0;
|
|
while (length < min_length || (value > 0 && length < max_length)) {
|
|
buffer[length++] = '0' + (value % 10);
|
|
value /= 10;
|
|
}
|
|
return length;
|
|
}
|
|
|
|
static int uint_to_hex_str(char buffer[], uintptr_t value, int min_length, int max_length)
|
|
{
|
|
int length = 0;
|
|
while (length < min_length || (value > 0 && length < max_length) ){
|
|
int digit = value % 16;
|
|
if (digit < 10) {
|
|
buffer[length++] = '0' + digit;
|
|
} else {
|
|
buffer[length++] = 'a' + digit - 10;
|
|
}
|
|
value /= 16;
|
|
}
|
|
return length;
|
|
}
|
|
|
|
static int min_str_length(int field_length, bool pad)
|
|
{
|
|
return (field_length > 0 && pad) ? field_length : 1;
|
|
}
|
|
|
|
static int print_in_field(int row, int col, const char buffer[], int buffer_length, int field_length, bool left)
|
|
{
|
|
bool reversed = false;
|
|
if (buffer_length < 0) {
|
|
buffer_length = -buffer_length;
|
|
reversed = true;
|
|
}
|
|
if (!left) {
|
|
while (field_length > buffer_length) {
|
|
print_char(row, col++, ' ');
|
|
field_length--;
|
|
}
|
|
}
|
|
if (reversed) {
|
|
for (int i = buffer_length - 1; i >= 0; i--) {
|
|
print_char(row, col++, buffer[i]);
|
|
}
|
|
} else {
|
|
for (int i = 0; i < buffer_length; i++) {
|
|
print_char(row, col++, buffer[i]);
|
|
}
|
|
}
|
|
if (left) {
|
|
while (field_length > buffer_length) {
|
|
print_char(row, col++, ' ');
|
|
field_length--;
|
|
}
|
|
}
|
|
return col;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Public Functions
|
|
//------------------------------------------------------------------------------
|
|
|
|
int printc(int row, int col, const char c)
|
|
{
|
|
print_char(row, col++, c);
|
|
return col;
|
|
}
|
|
|
|
int prints(int row, int col, const char *str)
|
|
{
|
|
while (*str) {
|
|
print_char(row, col++, *str++);
|
|
}
|
|
return col;
|
|
}
|
|
|
|
int printi(int row, int col, int value, int field_length, bool pad, bool left)
|
|
{
|
|
char buffer[BUFFER_SIZE];
|
|
|
|
int length = int_to_dec_str(buffer, value, min_str_length(field_length, pad), BUFFER_SIZE);
|
|
|
|
return print_in_field(row, col, buffer, -length, field_length, left);
|
|
}
|
|
|
|
int printu(int row, int col, uintptr_t value, int field_length, bool pad, bool left)
|
|
{
|
|
char buffer[BUFFER_SIZE];
|
|
|
|
int length = uint_to_dec_str(buffer, value, min_str_length(field_length, pad), BUFFER_SIZE);
|
|
|
|
return print_in_field(row, col, buffer, -length, field_length, left);
|
|
}
|
|
|
|
int printx(int row, int col, uintptr_t value, int field_length, bool pad, bool left)
|
|
{
|
|
char buffer[BUFFER_SIZE];
|
|
|
|
int length = uint_to_hex_str(buffer, value, min_str_length(field_length, pad), BUFFER_SIZE);
|
|
|
|
return print_in_field(row, col, buffer, -length, field_length, left);
|
|
}
|
|
|
|
int printk(int row, int col, uintptr_t value, int field_length, bool pad, bool left, bool add_space)
|
|
{
|
|
static const char suffix[4] = { 'K', 'M', 'G', 'T' };
|
|
|
|
int scale = 0;
|
|
int fract = 0;
|
|
while (value >= 1024 && scale < (int)(sizeof(suffix) - 1)) {
|
|
fract = value % 1024;
|
|
value /= 1024;
|
|
scale++;
|
|
}
|
|
int whole_length = field_length > 1 ? field_length - 1 : 0;
|
|
int fract_length = 0;
|
|
if (fract > 0) {
|
|
if (value < 10) {
|
|
whole_length = field_length > 4 ? field_length - 4 : 0;
|
|
fract = (100 * fract) / 1024;
|
|
if (fract > 0) {
|
|
if (fract % 10) {
|
|
fract_length = 2;
|
|
} else {
|
|
fract_length = 1;
|
|
fract /= 10;
|
|
}
|
|
}
|
|
} else if (value < 100) {
|
|
whole_length = field_length > 3 ? field_length - 3 : 0;
|
|
fract = (100 * fract) / (10 * 1024);
|
|
if (fract > 0) {
|
|
fract_length = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
char buffer[BUFFER_SIZE];
|
|
|
|
int length = 0;
|
|
buffer[length++] = suffix[scale];
|
|
|
|
if(add_space) {
|
|
buffer[length++] = ' ';
|
|
}
|
|
|
|
if (fract_length > 0) {
|
|
length += int_to_dec_str(&buffer[length], fract, fract_length, fract_length);
|
|
buffer[length++] = '.';
|
|
}
|
|
length += uint_to_dec_str(&buffer[length], value, min_str_length(whole_length, pad), BUFFER_SIZE - length);
|
|
|
|
return print_in_field(row, col, buffer, -length, field_length, left);
|
|
}
|
|
|
|
int printf(int row, int col, const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
int end_col = vprintf(row, col, fmt, args);
|
|
va_end(args);
|
|
|
|
return end_col;
|
|
}
|
|
|
|
int vprintf(int row, int col, const char *fmt, va_list args)
|
|
{
|
|
while (*fmt) {
|
|
if (*fmt != '%') {
|
|
print_char(row, col++, *fmt++);
|
|
continue;
|
|
}
|
|
fmt++;
|
|
if (*fmt == '%') {
|
|
print_char(row, col++, *fmt++);
|
|
continue;
|
|
}
|
|
|
|
bool pad = false;
|
|
bool left = false;
|
|
bool add_space = false;
|
|
int length = 0;
|
|
if (*fmt == '-') {
|
|
left = true;
|
|
fmt++;
|
|
}
|
|
if (*fmt == 'S') {
|
|
add_space = true;
|
|
fmt++;
|
|
}
|
|
if (*fmt == '0') {
|
|
pad = !left;
|
|
fmt++;
|
|
}
|
|
if (*fmt == '*') {
|
|
length = va_arg(args, int);
|
|
if (length < 0) {
|
|
length = -length;
|
|
left = true;
|
|
}
|
|
fmt++;
|
|
} else {
|
|
while (*fmt >= '0' && *fmt <= '9') {
|
|
length = 10 * length + *fmt - '0';
|
|
fmt++;
|
|
}
|
|
}
|
|
switch (*fmt) {
|
|
case 'c': {
|
|
char buffer[1];
|
|
buffer[0] = va_arg(args, int);
|
|
col = print_in_field(row, col, buffer, 1, length, left);
|
|
} break;
|
|
case 's': {
|
|
const char *str = va_arg(args, char *);
|
|
col = print_in_field(row, col, str, strlen(str), length, left);
|
|
} break;
|
|
case 'i':
|
|
col = printi(row, col, va_arg(args, int), length, pad, left);
|
|
break;
|
|
case 'u':
|
|
col = printu(row, col, va_arg(args, uintptr_t), length, pad, left);
|
|
break;
|
|
case 'x':
|
|
col = printx(row, col, va_arg(args, uintptr_t), length, pad, left);
|
|
break;
|
|
case 'k':
|
|
col = printk(row, col, va_arg(args, uintptr_t), length, pad, left, add_space);
|
|
break;
|
|
}
|
|
fmt++;
|
|
}
|
|
|
|
return col;
|
|
}
|