summaryrefslogtreecommitdiff
path: root/lib/num2str.c
blob: 559cbeb590e4926b2d34f3b34cf6ac4cc0eadf10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/*
 * Cheesy number->string conversion, complete with carry rounding error.
 */
char *num2str(unsigned long num, int maxlen, int base, int pow2)
{
	char postfix[] = { ' ', 'K', 'M', 'G', 'P', 'E' };
	unsigned int thousand[] = { 1000, 1024 };
	unsigned int modulo, decimals;
	int post_index, carry = 0;
	char tmp[32];
	char *buf;

	buf = malloc(128);

	for (post_index = 0; base > 1; post_index++)
		base /= thousand[!!pow2];

	modulo = -1U;
	while (post_index < sizeof(postfix)) {
		sprintf(tmp, "%lu", num);
		if (strlen(tmp) <= maxlen)
			break;

		modulo = num % thousand[!!pow2];
		num /= thousand[!!pow2];
		carry = modulo >= thousand[!!pow2] / 2;
		post_index++;
	}

	if (modulo == -1U) {
done:
		sprintf(buf, "%lu%c", num, postfix[post_index]);
		return buf;
	}

	sprintf(tmp, "%lu", num);
	decimals = maxlen - strlen(tmp);
	if (decimals <= 1) {
		if (carry)
			num++;
		goto done;
	}

	do {
		sprintf(tmp, "%u", modulo);
		if (strlen(tmp) <= decimals - 1)
			break;

		modulo = (modulo + 9) / 10;
	} while (1);

	sprintf(buf, "%lu.%u%c", num, modulo, postfix[post_index]);
	return buf;
}