1207753Smm///////////////////////////////////////////////////////////////////////////////
2207753Smm//
3207753Smm/// \file       util.c
4207753Smm/// \brief      Miscellaneous utility functions
5207753Smm//
6207753Smm//  Author:     Lasse Collin
7207753Smm//
8207753Smm//  This file has been put into the public domain.
9207753Smm//  You can do whatever you want with this file.
10207753Smm//
11207753Smm///////////////////////////////////////////////////////////////////////////////
12207753Smm
13207753Smm#include "private.h"
14207753Smm#include <stdarg.h>
15207753Smm
16207753Smm
17213700Smm/// Buffers for uint64_to_str() and uint64_to_nicestr()
18213700Smmstatic char bufs[4][128];
19213700Smm
20213700Smm/// Thousand separator support in uint64_to_str() and uint64_to_nicestr()
21213700Smmstatic enum { UNKNOWN, WORKS, BROKEN } thousand = UNKNOWN;
22213700Smm
23213700Smm
24207753Smmextern void *
25207753Smmxrealloc(void *ptr, size_t size)
26207753Smm{
27207753Smm	assert(size > 0);
28207753Smm
29263285Sdelphij	// Save ptr so that we can free it if realloc fails.
30263285Sdelphij	// The point is that message_fatal ends up calling stdio functions
31263285Sdelphij	// which in some libc implementations might allocate memory from
32263285Sdelphij	// the heap. Freeing ptr improves the chances that there's free
33263285Sdelphij	// memory for stdio functions if they need it.
34263285Sdelphij	void *p = ptr;
35207753Smm	ptr = realloc(ptr, size);
36207753Smm
37263285Sdelphij	if (ptr == NULL) {
38263285Sdelphij		const int saved_errno = errno;
39263285Sdelphij		free(p);
40263285Sdelphij		message_fatal("%s", strerror(saved_errno));
41263285Sdelphij	}
42263285Sdelphij
43207753Smm	return ptr;
44207753Smm}
45207753Smm
46207753Smm
47207753Smmextern char *
48207753Smmxstrdup(const char *src)
49207753Smm{
50207753Smm	assert(src != NULL);
51207753Smm	const size_t size = strlen(src) + 1;
52207753Smm	char *dest = xmalloc(size);
53207753Smm	return memcpy(dest, src, size);
54207753Smm}
55207753Smm
56207753Smm
57207753Smmextern uint64_t
58207753Smmstr_to_uint64(const char *name, const char *value, uint64_t min, uint64_t max)
59207753Smm{
60207753Smm	uint64_t result = 0;
61207753Smm
62207753Smm	// Skip blanks.
63207753Smm	while (*value == ' ' || *value == '\t')
64207753Smm		++value;
65207753Smm
66207753Smm	// Accept special value "max". Supporting "min" doesn't seem useful.
67207753Smm	if (strcmp(value, "max") == 0)
68207753Smm		return max;
69207753Smm
70207753Smm	if (*value < '0' || *value > '9')
71207753Smm		message_fatal(_("%s: Value is not a non-negative "
72207753Smm				"decimal integer"), value);
73207753Smm
74207753Smm	do {
75207753Smm		// Don't overflow.
76213700Smm		if (result > UINT64_MAX / 10)
77207753Smm			goto error;
78207753Smm
79207753Smm		result *= 10;
80213700Smm
81213700Smm		// Another overflow check
82213700Smm		const uint32_t add = *value - '0';
83213700Smm		if (UINT64_MAX - add < result)
84213700Smm			goto error;
85213700Smm
86213700Smm		result += add;
87207753Smm		++value;
88207753Smm	} while (*value >= '0' && *value <= '9');
89207753Smm
90207753Smm	if (*value != '\0') {
91207753Smm		// Look for suffix. Originally this supported both base-2
92207753Smm		// and base-10, but since there seems to be little need
93207753Smm		// for base-10 in this program, treat everything as base-2
94207753Smm		// and also be more relaxed about the case of the first
95207753Smm		// letter of the suffix.
96207753Smm		uint64_t multiplier = 0;
97207753Smm		if (*value == 'k' || *value == 'K')
98207753Smm			multiplier = UINT64_C(1) << 10;
99207753Smm		else if (*value == 'm' || *value == 'M')
100207753Smm			multiplier = UINT64_C(1) << 20;
101207753Smm		else if (*value == 'g' || *value == 'G')
102207753Smm			multiplier = UINT64_C(1) << 30;
103207753Smm
104207753Smm		++value;
105207753Smm
106207753Smm		// Allow also e.g. Ki, KiB, and KB.
107207753Smm		if (*value != '\0' && strcmp(value, "i") != 0
108207753Smm				&& strcmp(value, "iB") != 0
109207753Smm				&& strcmp(value, "B") != 0)
110207753Smm			multiplier = 0;
111207753Smm
112207753Smm		if (multiplier == 0) {
113207753Smm			message(V_ERROR, _("%s: Invalid multiplier suffix"),
114207753Smm					value - 1);
115207753Smm			message_fatal(_("Valid suffixes are `KiB' (2^10), "
116207753Smm					"`MiB' (2^20), and `GiB' (2^30)."));
117207753Smm		}
118207753Smm
119207753Smm		// Don't overflow here either.
120207753Smm		if (result > UINT64_MAX / multiplier)
121207753Smm			goto error;
122207753Smm
123207753Smm		result *= multiplier;
124207753Smm	}
125207753Smm
126207753Smm	if (result < min || result > max)
127207753Smm		goto error;
128207753Smm
129207753Smm	return result;
130207753Smm
131207753Smmerror:
132207753Smm	message_fatal(_("Value of the option `%s' must be in the range "
133207753Smm				"[%" PRIu64 ", %" PRIu64 "]"),
134207753Smm				name, min, max);
135207753Smm}
136207753Smm
137207753Smm
138207753Smmextern uint64_t
139207753Smmround_up_to_mib(uint64_t n)
140207753Smm{
141207753Smm	return (n >> 20) + ((n & ((UINT32_C(1) << 20) - 1)) != 0);
142207753Smm}
143207753Smm
144207753Smm
145213700Smm/// Check if thousand separator is supported. Run-time checking is easiest,
146213700Smm/// because it seems to be sometimes lacking even on POSIXish system.
147213700Smmstatic void
148213700Smmcheck_thousand_sep(uint32_t slot)
149207753Smm{
150207753Smm	if (thousand == UNKNOWN) {
151207753Smm		bufs[slot][0] = '\0';
152213700Smm		snprintf(bufs[slot], sizeof(bufs[slot]), "%'u", 1U);
153207753Smm		thousand = bufs[slot][0] == '1' ? WORKS : BROKEN;
154207753Smm	}
155207753Smm
156213700Smm	return;
157213700Smm}
158213700Smm
159213700Smm
160213700Smmextern const char *
161213700Smmuint64_to_str(uint64_t value, uint32_t slot)
162213700Smm{
163213700Smm	assert(slot < ARRAY_SIZE(bufs));
164213700Smm
165213700Smm	check_thousand_sep(slot);
166213700Smm
167207753Smm	if (thousand == WORKS)
168207753Smm		snprintf(bufs[slot], sizeof(bufs[slot]), "%'" PRIu64, value);
169207753Smm	else
170207753Smm		snprintf(bufs[slot], sizeof(bufs[slot]), "%" PRIu64, value);
171207753Smm
172207753Smm	return bufs[slot];
173207753Smm}
174207753Smm
175207753Smm
176207753Smmextern const char *
177207753Smmuint64_to_nicestr(uint64_t value, enum nicestr_unit unit_min,
178207753Smm		enum nicestr_unit unit_max, bool always_also_bytes,
179207753Smm		uint32_t slot)
180207753Smm{
181207753Smm	assert(unit_min <= unit_max);
182207753Smm	assert(unit_max <= NICESTR_TIB);
183213700Smm	assert(slot < ARRAY_SIZE(bufs));
184207753Smm
185213700Smm	check_thousand_sep(slot);
186213700Smm
187207753Smm	enum nicestr_unit unit = NICESTR_B;
188213700Smm	char *pos = bufs[slot];
189213700Smm	size_t left = sizeof(bufs[slot]);
190207753Smm
191207753Smm	if ((unit_min == NICESTR_B && value < 10000)
192207753Smm			|| unit_max == NICESTR_B) {
193207753Smm		// The value is shown as bytes.
194213700Smm		if (thousand == WORKS)
195213700Smm			my_snprintf(&pos, &left, "%'u", (unsigned int)value);
196213700Smm		else
197213700Smm			my_snprintf(&pos, &left, "%u", (unsigned int)value);
198207753Smm	} else {
199207753Smm		// Scale the value to a nicer unit. Unless unit_min and
200207753Smm		// unit_max limit us, we will show at most five significant
201207753Smm		// digits with one decimal place.
202207753Smm		double d = (double)(value);
203207753Smm		do {
204207753Smm			d /= 1024.0;
205207753Smm			++unit;
206207753Smm		} while (unit < unit_min || (d > 9999.9 && unit < unit_max));
207207753Smm
208213700Smm		if (thousand == WORKS)
209213700Smm			my_snprintf(&pos, &left, "%'.1f", d);
210213700Smm		else
211213700Smm			my_snprintf(&pos, &left, "%.1f", d);
212207753Smm	}
213207753Smm
214207753Smm	static const char suffix[5][4] = { "B", "KiB", "MiB", "GiB", "TiB" };
215213700Smm	my_snprintf(&pos, &left, " %s", suffix[unit]);
216207753Smm
217213700Smm	if (always_also_bytes && value >= 10000) {
218213700Smm		if (thousand == WORKS)
219213700Smm			snprintf(pos, left, " (%'" PRIu64 " B)", value);
220213700Smm		else
221213700Smm			snprintf(pos, left, " (%" PRIu64 " B)", value);
222207753Smm	}
223207753Smm
224213700Smm	return bufs[slot];
225207753Smm}
226207753Smm
227207753Smm
228207753Smmextern void
229207753Smmmy_snprintf(char **pos, size_t *left, const char *fmt, ...)
230207753Smm{
231207753Smm	va_list ap;
232207753Smm	va_start(ap, fmt);
233207753Smm	const int len = vsnprintf(*pos, *left, fmt, ap);
234207753Smm	va_end(ap);
235207753Smm
236207753Smm	// If an error occurred, we want the caller to think that the whole
237207753Smm	// buffer was used. This way no more data will be written to the
238213700Smm	// buffer. We don't need better error handling here, although it
239213700Smm	// is possible that the result looks garbage on the terminal if
240213700Smm	// e.g. an UTF-8 character gets split. That shouldn't (easily)
241213700Smm	// happen though, because the buffers used have some extra room.
242207753Smm	if (len < 0 || (size_t)(len) >= *left) {
243207753Smm		*left = 0;
244207753Smm	} else {
245207753Smm		*pos += len;
246207753Smm		*left -= len;
247207753Smm	}
248207753Smm
249207753Smm	return;
250207753Smm}
251207753Smm
252207753Smm
253207753Smmextern bool
254207753Smmis_empty_filename(const char *filename)
255207753Smm{
256207753Smm	if (filename[0] == '\0') {
257207753Smm		message_error(_("Empty filename, skipping"));
258207753Smm		return true;
259207753Smm	}
260207753Smm
261207753Smm	return false;
262207753Smm}
263207753Smm
264207753Smm
265207753Smmextern bool
266207753Smmis_tty_stdin(void)
267207753Smm{
268207753Smm	const bool ret = isatty(STDIN_FILENO);
269207753Smm
270207753Smm	if (ret)
271207753Smm		message_error(_("Compressed data cannot be read from "
272207753Smm				"a terminal"));
273207753Smm
274207753Smm	return ret;
275207753Smm}
276207753Smm
277207753Smm
278207753Smmextern bool
279207753Smmis_tty_stdout(void)
280207753Smm{
281207753Smm	const bool ret = isatty(STDOUT_FILENO);
282207753Smm
283207753Smm	if (ret)
284207753Smm		message_error(_("Compressed data cannot be written to "
285207753Smm				"a terminal"));
286207753Smm
287207753Smm	return ret;
288207753Smm}
289