1 /*
2  * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
3  * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
4  */
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <inttypes.h>
9 #include <ctype.h>
10 #include <errno.h>
11 #include <sys/stat.h>
12 #include <string.h>
13 #include <assert.h>
14 
15 #include "c.h"
16 #include "nls.h"
17 #include "strutils.h"
18 #include "bitops.h"
19 
do_scale_by_power(uintmax_t * x,int base,int power)20 static int do_scale_by_power (uintmax_t *x, int base, int power)
21 {
22 	while (power--) {
23 		if (UINTMAX_MAX / base < *x)
24 			return -ERANGE;
25 		*x *= base;
26 	}
27 	return 0;
28 }
29 
30 /*
31  * strtosize() - convert string to size (uintmax_t).
32  *
33  * Supported suffixes:
34  *
35  * XiB or X for 2^N
36  *     where X = {K,M,G,T,P,E,Z,Y}
37  *        or X = {k,m,g,t,p,e}  (undocumented for backward compatibility only)
38  * for example:
39  *		10KiB	= 10240
40  *		10K	= 10240
41  *
42  * XB for 10^N
43  *     where X = {K,M,G,T,P,E,Z,Y}
44  * for example:
45  *		10KB	= 10000
46  *
47  * The optinal 'power' variable returns number associated with used suffix
48  * {K,M,G,T,P,E,Z,Y}  = {1,2,3,4,5,6,7,8}.
49  *
50  * The function also supports decimal point, for example:
51  *              0.5MB   = 500000
52  *              0.5MiB  = 512000
53  *
54  * Note that the function does not accept numbers with '-' (negative sign)
55  * prefix.
56  */
parse_size(const char * str,uintmax_t * res,int * power)57 int parse_size(const char *str, uintmax_t *res, int *power)
58 {
59 	char *p;
60 	uintmax_t x, frac = 0;
61 	int base = 1024, rc = 0, pwr = 0, frac_zeros = 0;
62 
63 	static const char *suf  = "KMGTPEYZ";
64 	static const char *suf2 = "kmgtpeyz";
65 	const char *sp;
66 
67 	*res = 0;
68 
69 	if (!str || !*str) {
70 		rc = -EINVAL;
71 		goto err;
72 	}
73 
74 	/* Only positive numbers are acceptable
75 	 *
76 	 * Note that this check is not perfect, it would be better to
77 	 * use lconv->negative_sign. But coreutils use the same solution,
78 	 * so it's probably good enough...
79 	 */
80 	p = (char *) str;
81 	while (isspace((unsigned char) *p))
82 		p++;
83 	if (*p == '-') {
84 		rc = -EINVAL;
85 		goto err;
86 	}
87 	p = NULL;
88 
89 	errno = 0;
90 	x = strtoumax(str, &p, 0);
91 
92 	if (p == str ||
93 	    (errno != 0 && (x == UINTMAX_MAX || x == 0))) {
94 		rc = errno ? -errno : -1;
95 		goto err;
96 	}
97 	if (!p || !*p)
98 		goto done;			/* without suffix */
99 
100 	/*
101 	 * Check size suffixes
102 	 */
103 check_suffix:
104 	if (*(p + 1) == 'i' && *(p + 2) == 'B' && !*(p + 3))
105 		base = 1024;			/* XiB, 2^N */
106 	else if (*(p + 1) == 'B' && !*(p + 2))
107 		base = 1000;			/* XB, 10^N */
108 	else if (*(p + 1)) {
109 		struct lconv const *l = localeconv();
110 		char *dp = l ? l->decimal_point : NULL;
111 		size_t dpsz = dp ? strlen(dp) : 0;
112 
113 		if (frac == 0 && *p && dp && strncmp(dp, p, dpsz) == 0) {
114 			char *fstr = p + dpsz;
115 
116 			for (p = fstr; *p && *p == '0'; p++)
117 				frac_zeros++;
118 			errno = 0, p = NULL;
119 			frac = strtoumax(fstr, &p, 0);
120 			if (p == fstr ||
121 			    (errno != 0 && (frac == UINTMAX_MAX || frac == 0))) {
122 				rc = errno ? -errno : -1;
123 				goto err;
124 			}
125 			if (frac && (!p  || !*p)) {
126 				rc = -EINVAL;
127 				goto err;		/* without suffix, but with frac */
128 			}
129 			goto check_suffix;
130 		}
131 		rc = -EINVAL;
132 		goto err;			/* unexpected suffix */
133 	}
134 
135 	sp = strchr(suf, *p);
136 	if (sp)
137 		pwr = (sp - suf) + 1;
138 	else {
139 		sp = strchr(suf2, *p);
140 		if (sp)
141 			pwr = (sp - suf2) + 1;
142 		else {
143 			rc = -EINVAL;
144 			goto err;
145 		}
146 	}
147 
148 	rc = do_scale_by_power(&x, base, pwr);
149 	if (power)
150 		*power = pwr;
151 	if (frac && pwr) {
152 		int zeros_in_pwr = frac_zeros % 3;
153 		int frac_pwr = pwr - (frac_zeros / 3) - 1;
154 		uintmax_t y = frac * (zeros_in_pwr == 0 ? 100 :
155 				      zeros_in_pwr == 1 ?  10 : 1);
156 
157 		if (frac_pwr < 0) {
158 			rc = -EINVAL;
159 			goto err;
160 		}
161 		do_scale_by_power(&y, base, frac_pwr);
162 		x += y;
163 	}
164 done:
165 	*res = x;
166 err:
167 	return rc;
168 }
169 
strtosize(const char * str,uintmax_t * res)170 int strtosize(const char *str, uintmax_t *res)
171 {
172 	return parse_size(str, res, NULL);
173 }
174 
isdigit_string(const char * str)175 int isdigit_string(const char *str)
176 {
177 	const char *p;
178 
179 	for (p = str; p && *p && isdigit((unsigned char) *p); p++);
180 
181 	return p && p > str && !*p;
182 }
183 
184 
185 #ifndef HAVE_MEMPCPY
mempcpy(void * restrict dest,const void * restrict src,size_t n)186 void *mempcpy(void *restrict dest, const void *restrict src, size_t n)
187 {
188     return ((char *)memcpy(dest, src, n)) + n;
189 }
190 #endif
191 
192 #ifndef HAVE_STRNLEN
strnlen(const char * s,size_t maxlen)193 size_t strnlen(const char *s, size_t maxlen)
194 {
195         int i;
196 
197         for (i = 0; i < maxlen; i++) {
198                 if (s[i] == '\0')
199                         return i + 1;
200         }
201         return maxlen;
202 }
203 #endif
204 
205 #ifndef HAVE_STRNCHR
strnchr(const char * s,size_t maxlen,int c)206 char *strnchr(const char *s, size_t maxlen, int c)
207 {
208 	for (; maxlen-- && *s != '\0'; ++s)
209 		if (*s == (char)c)
210 			return (char *)s;
211 	return NULL;
212 }
213 #endif
214 
215 #ifndef HAVE_STRNDUP
strndup(const char * s,size_t n)216 char *strndup(const char *s, size_t n)
217 {
218 	size_t len = strnlen(s, n);
219 	char *new = (char *) malloc((len + 1) * sizeof(char));
220 	if (!new)
221 		return NULL;
222 	new[len] = '\0';
223 	return (char *) memcpy(new, s, len);
224 }
225 #endif
226 
strtos16_or_err(const char * str,const char * errmesg)227 int16_t strtos16_or_err(const char *str, const char *errmesg)
228 {
229 	int32_t num = strtos32_or_err(str, errmesg);
230 
231 	if (num < INT16_MIN || num > INT16_MAX)
232 		errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
233 
234 	return num;
235 }
236 
strtou16_or_err(const char * str,const char * errmesg)237 uint16_t strtou16_or_err(const char *str, const char *errmesg)
238 {
239 	uint32_t num = strtou32_or_err(str, errmesg);
240 
241 	if (num > UINT16_MAX)
242 		errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
243 
244 	return num;
245 }
246 
strtos32_or_err(const char * str,const char * errmesg)247 int32_t strtos32_or_err(const char *str, const char *errmesg)
248 {
249 	int64_t num = strtos64_or_err(str, errmesg);
250 
251 	if (num < INT32_MIN || num > INT32_MAX)
252 		errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
253 
254 	return num;
255 }
256 
strtou32_or_err(const char * str,const char * errmesg)257 uint32_t strtou32_or_err(const char *str, const char *errmesg)
258 {
259 	uint64_t num = strtou64_or_err(str, errmesg);
260 
261 	if (num > UINT32_MAX)
262 		errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
263 
264 	return num;
265 }
266 
strtos64_or_err(const char * str,const char * errmesg)267 int64_t strtos64_or_err(const char *str, const char *errmesg)
268 {
269 	int64_t num;
270 	char *end = NULL;
271 
272 	if (str == NULL || *str == '\0')
273 		goto err;
274 	errno = 0;
275 	num = strtoimax(str, &end, 10);
276 
277 	if (errno || str == end || (end && *end))
278 		goto err;
279 
280 	return num;
281 err:
282 	if (errno)
283 		err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
284 
285 	errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
286 }
287 
strtou64_or_err(const char * str,const char * errmesg)288 uint64_t strtou64_or_err(const char *str, const char *errmesg)
289 {
290 	uintmax_t num;
291 	char *end = NULL;
292 
293 	if (str == NULL || *str == '\0')
294 		goto err;
295 	errno = 0;
296 	num = strtoumax(str, &end, 10);
297 
298 	if (errno || str == end || (end && *end))
299 		goto err;
300 
301 	return num;
302 err:
303 	if (errno)
304 		err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
305 
306 	errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
307 }
308 
309 
strtod_or_err(const char * str,const char * errmesg)310 double strtod_or_err(const char *str, const char *errmesg)
311 {
312 	double num;
313 	char *end = NULL;
314 
315 	if (str == NULL || *str == '\0')
316 		goto err;
317 	errno = 0;
318 	num = strtod(str, &end);
319 
320 	if (errno || str == end || (end && *end))
321 		goto err;
322 
323 	return num;
324 err:
325 	if (errno)
326 		err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
327 
328 	errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
329 }
330 
strtol_or_err(const char * str,const char * errmesg)331 long strtol_or_err(const char *str, const char *errmesg)
332 {
333 	long num;
334 	char *end = NULL;
335 
336 	if (str == NULL || *str == '\0')
337 		goto err;
338 	errno = 0;
339 	num = strtol(str, &end, 10);
340 
341 	if (errno || str == end || (end && *end))
342 		goto err;
343 
344 	return num;
345 err:
346 	if (errno)
347 		err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
348 	errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
349 }
350 
strtoul_or_err(const char * str,const char * errmesg)351 unsigned long strtoul_or_err(const char *str, const char *errmesg)
352 {
353 	unsigned long num;
354 	char *end = NULL;
355 
356 	if (str == NULL || *str == '\0')
357 		goto err;
358 	errno = 0;
359 	num = strtoul(str, &end, 10);
360 
361 	if (errno || str == end || (end && *end))
362 		goto err;
363 
364 	return num;
365 err:
366 	if (errno)
367 		err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
368 
369 	errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
370 }
371 
strtosize_or_err(const char * str,const char * errmesg)372 uintmax_t strtosize_or_err(const char *str, const char *errmesg)
373 {
374 	uintmax_t num;
375 
376 	if (strtosize(str, &num) == 0)
377 		return num;
378 
379 	if (errno)
380 		err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
381 
382 	errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
383 }
384 
385 
strtotimeval_or_err(const char * str,struct timeval * tv,const char * errmesg)386 void strtotimeval_or_err(const char *str, struct timeval *tv, const char *errmesg)
387 {
388 	double user_input;
389 
390 	user_input = strtod_or_err(str, errmesg);
391 	tv->tv_sec = (time_t) user_input;
392 	tv->tv_usec = (long)((user_input - tv->tv_sec) * 1000000);
393 }
394 
395 /*
396  * Converts stat->st_mode to ls(1)-like mode string. The size of "str" must
397  * be 11 bytes.
398  */
strmode(mode_t mode,char * str)399 void strmode(mode_t mode, char *str)
400 {
401 	if (S_ISDIR(mode))
402 		str[0] = 'd';
403 	else if (S_ISLNK(mode))
404 		str[0] = 'l';
405 	else if (S_ISCHR(mode))
406 		str[0] = 'c';
407 	else if (S_ISBLK(mode))
408 		str[0] = 'b';
409 	else if (S_ISSOCK(mode))
410 		str[0] = 's';
411 	else if (S_ISFIFO(mode))
412 		str[0] = 'p';
413 	else if (S_ISREG(mode))
414 		str[0] = '-';
415 
416 	str[1] = mode & S_IRUSR ? 'r' : '-';
417 	str[2] = mode & S_IWUSR ? 'w' : '-';
418 	str[3] = (mode & S_ISUID
419 		? (mode & S_IXUSR ? 's' : 'S')
420 		: (mode & S_IXUSR ? 'x' : '-'));
421 	str[4] = mode & S_IRGRP ? 'r' : '-';
422 	str[5] = mode & S_IWGRP ? 'w' : '-';
423 	str[6] = (mode & S_ISGID
424 		? (mode & S_IXGRP ? 's' : 'S')
425 		: (mode & S_IXGRP ? 'x' : '-'));
426 	str[7] = mode & S_IROTH ? 'r' : '-';
427 	str[8] = mode & S_IWOTH ? 'w' : '-';
428 	str[9] = (mode & S_ISVTX
429 		? (mode & S_IXOTH ? 't' : 'T')
430 		: (mode & S_IXOTH ? 'x' : '-'));
431 	str[10] = '\0';
432 }
433 
434 /*
435  * returns exponent (2^x=n) in range KiB..PiB
436  */
get_exp(uint64_t n)437 static int get_exp(uint64_t n)
438 {
439 	int shft;
440 
441 	for (shft = 10; shft <= 60; shft += 10) {
442 		if (n < (1ULL << shft))
443 			break;
444 	}
445 	return shft - 10;
446 }
447 
size_to_human_string(int options,uint64_t bytes)448 char *size_to_human_string(int options, uint64_t bytes)
449 {
450 	char buf[32];
451 	int dec, exp;
452 	uint64_t frac;
453 	const char *letters = "BKMGTPE";
454 	char suffix[sizeof(" KiB")], *psuf = suffix;
455 	char c;
456 
457 	if (options & SIZE_SUFFIX_SPACE)
458 		*psuf++ = ' ';
459 
460 	exp  = get_exp(bytes);
461 	c    = *(letters + (exp ? exp / 10 : 0));
462 	dec  = exp ? bytes / (1ULL << exp) : bytes;
463 	frac = exp ? bytes % (1ULL << exp) : 0;
464 
465 	*psuf++ = c;
466 
467 	if ((options & SIZE_SUFFIX_3LETTER) && (c != 'B')) {
468 		*psuf++ = 'i';
469 		*psuf++ = 'B';
470 	}
471 
472 	*psuf = '\0';
473 
474 	/* fprintf(stderr, "exp: %d, unit: %c, dec: %d, frac: %jd\n",
475 	 *                 exp, suffix[0], dec, frac);
476 	 */
477 
478 	if (frac) {
479 		/* round */
480 		frac = (frac / (1ULL << (exp - 10)) + 50) / 100;
481 		if (frac == 10)
482 			dec++, frac = 0;
483 	}
484 
485 	if (frac) {
486 		struct lconv const *l = localeconv();
487 		char *dp = l ? l->decimal_point : NULL;
488 
489 		if (!dp || !*dp)
490 			dp = ".";
491 		snprintf(buf, sizeof(buf), "%d%s%jd%s", dec, dp, frac, suffix);
492 	} else
493 		snprintf(buf, sizeof(buf), "%d%s", dec, suffix);
494 
495 	return strdup(buf);
496 }
497 
498 /*
499  * Parses comma delimited list to array with IDs, for example:
500  *
501  * "aaa,bbb,ccc" --> ary[0] = FOO_AAA;
502  *                   ary[1] = FOO_BBB;
503  *                   ary[3] = FOO_CCC;
504  *
505  * The function name2id() provides conversion from string to ID.
506  *
507  * Returns: >= 0  : number of items added to ary[]
508  *            -1  : parse error or unknown item
509  *            -2  : arysz reached
510  */
string_to_idarray(const char * list,int ary[],size_t arysz,int (name2id)(const char *,size_t))511 int string_to_idarray(const char *list, int ary[], size_t arysz,
512 			int (name2id)(const char *, size_t))
513 {
514 	const char *begin = NULL, *p;
515 	size_t n = 0;
516 
517 	if (!list || !*list || !ary || !arysz || !name2id)
518 		return -1;
519 
520 	for (p = list; p && *p; p++) {
521 		const char *end = NULL;
522 		int id;
523 
524 		if (n >= arysz)
525 			return -2;
526 		if (!begin)
527 			begin = p;		/* begin of the column name */
528 		if (*p == ',')
529 			end = p;		/* terminate the name */
530 		if (*(p + 1) == '\0')
531 			end = p + 1;		/* end of string */
532 		if (!begin || !end)
533 			continue;
534 		if (end <= begin)
535 			return -1;
536 
537 		id = name2id(begin, end - begin);
538 		if (id == -1)
539 			return -1;
540 		ary[ n++ ] = id;
541 		begin = NULL;
542 		if (end && !*end)
543 			break;
544 	}
545 	return n;
546 }
547 
548 /*
549  * Parses the array like string_to_idarray but if format is "+aaa,bbb"
550  * it adds fields to array instead of replacing them.
551  */
string_add_to_idarray(const char * list,int ary[],size_t arysz,int * ary_pos,int (name2id)(const char *,size_t))552 int string_add_to_idarray(const char *list, int ary[], size_t arysz,
553 			int *ary_pos, int (name2id)(const char *, size_t))
554 {
555 	const char *list_add;
556 	int r;
557 
558 	if (!list || !*list || !ary_pos ||
559 	    *ary_pos < 0 || (size_t) *ary_pos > arysz)
560 		return -1;
561 
562 	if (list[0] == '+')
563 		list_add = &list[1];
564 	else {
565 		list_add = list;
566 		*ary_pos = 0;
567 	}
568 
569 	r = string_to_idarray(list_add, &ary[*ary_pos], arysz - *ary_pos, name2id);
570 	if (r > 0)
571 		*ary_pos += r;
572 	return r;
573 }
574 
575 /*
576  * LIST ::= <item> [, <item>]
577  *
578  * The <item> is translated to 'id' by name2id() function and the 'id' is used
579  * as a position in the 'ary' bit array. It means that the 'id' has to be in
580  * range <0..N> where N < sizeof(ary) * NBBY.
581  *
582  * Returns: 0 on success, <0 on error.
583  */
string_to_bitarray(const char * list,char * ary,int (* name2bit)(const char *,size_t))584 int string_to_bitarray(const char *list,
585 		     char *ary,
586 		     int (*name2bit)(const char *, size_t))
587 {
588 	const char *begin = NULL, *p;
589 
590 	if (!list || !name2bit || !ary)
591 		return -EINVAL;
592 
593 	for (p = list; p && *p; p++) {
594 		const char *end = NULL;
595 		int bit;
596 
597 		if (!begin)
598 			begin = p;		/* begin of the level name */
599 		if (*p == ',')
600 			end = p;		/* terminate the name */
601 		if (*(p + 1) == '\0')
602 			end = p + 1;		/* end of string */
603 		if (!begin || !end)
604 			continue;
605 		if (end <= begin)
606 			return -1;
607 
608 		bit = name2bit(begin, end - begin);
609 		if (bit < 0)
610 			return bit;
611 		setbit(ary, bit);
612 		begin = NULL;
613 		if (end && !*end)
614 			break;
615 	}
616 	return 0;
617 }
618 
619 /*
620  * LIST ::= <item> [, <item>]
621  *
622  * The <item> is translated to 'id' by name2flag() function and the flags is
623  * set to the 'mask'
624 *
625  * Returns: 0 on success, <0 on error.
626  */
string_to_bitmask(const char * list,unsigned long * mask,long (* name2flag)(const char *,size_t))627 int string_to_bitmask(const char *list,
628 		     unsigned long *mask,
629 		     long (*name2flag)(const char *, size_t))
630 {
631 	const char *begin = NULL, *p;
632 
633 	if (!list || !name2flag || !mask)
634 		return -EINVAL;
635 
636 	for (p = list; p && *p; p++) {
637 		const char *end = NULL;
638 		long flag;
639 
640 		if (!begin)
641 			begin = p;		/* begin of the level name */
642 		if (*p == ',')
643 			end = p;		/* terminate the name */
644 		if (*(p + 1) == '\0')
645 			end = p + 1;		/* end of string */
646 		if (!begin || !end)
647 			continue;
648 		if (end <= begin)
649 			return -1;
650 
651 		flag = name2flag(begin, end - begin);
652 		if (flag < 0)
653 			return flag;	/* error */
654 		*mask |= flag;
655 		begin = NULL;
656 		if (end && !*end)
657 			break;
658 	}
659 	return 0;
660 }
661 
662 /*
663  * Parse the lower and higher values in a string containing
664  * "lower:higher" or "lower-higher" format. Note that either
665  * the lower or the higher values may be missing, and the def
666  * value will be assigned to it by default.
667  *
668  * Returns: 0 on success, <0 on error.
669  */
parse_range(const char * str,int * lower,int * upper,int def)670 int parse_range(const char *str, int *lower, int *upper, int def)
671 {
672 	char *end = NULL;
673 
674 	if (!str)
675 		return 0;
676 
677 	*upper = *lower = def;
678 	errno = 0;
679 
680 	if (*str == ':') {				/* <:N> */
681 		str++;
682 		*upper = strtol(str, &end, 10);
683 		if (errno || !end || *end || end == str)
684 			return -1;
685 	} else {
686 		*upper = *lower = strtol(str, &end, 10);
687 		if (errno || !end || end == str)
688 			return -1;
689 
690 		if (*end == ':' && !*(end + 1))		/* <M:> */
691 			*upper = 0;
692 		else if (*end == '-' || *end == ':') {	/* <M:N> <M-N> */
693 			str = end + 1;
694 			end = NULL;
695 			errno = 0;
696 			*upper = strtol(str, &end, 10);
697 
698 			if (errno || !end || *end || end == str)
699 				return -1;
700 		}
701 	}
702 	return 0;
703 }
704 
705 /*
706  * Compare two strings for equality, ignoring at most one trailing
707  * slash.
708  */
streq_except_trailing_slash(const char * s1,const char * s2)709 int streq_except_trailing_slash(const char *s1, const char *s2)
710 {
711 	int equal;
712 
713 	if (!s1 && !s2)
714 		return 1;
715 	if (!s1 || !s2)
716 		return 0;
717 
718 	equal = !strcmp(s1, s2);
719 
720 	if (!equal) {
721 		size_t len1 = strlen(s1);
722 		size_t len2 = strlen(s2);
723 
724 		if (len1 && *(s1 + len1 - 1) == '/')
725 			len1--;
726 		if (len2 && *(s2 + len2 - 1) == '/')
727 			len2--;
728 		if (len1 != len2)
729 			return 0;
730 
731 		equal = !strncmp(s1, s2, len1);
732 	}
733 
734 	return equal;
735 }
736 
737 
738 #ifdef TEST_PROGRAM
739 
main(int argc,char * argv[])740 int main(int argc, char *argv[])
741 {
742 	uintmax_t size = 0;
743 	char *hum, *hum2;
744 
745 	if (argc < 2) {
746 		fprintf(stderr, "usage: %s <number>[suffix]\n",	argv[0]);
747 		exit(EXIT_FAILURE);
748 	}
749 
750 	if (strtosize(argv[1], &size))
751 		errx(EXIT_FAILURE, "invalid size '%s' value", argv[1]);
752 
753 	hum = size_to_human_string(SIZE_SUFFIX_1LETTER, size);
754 	hum2 = size_to_human_string(SIZE_SUFFIX_3LETTER |
755 				    SIZE_SUFFIX_SPACE, size);
756 
757 	printf("%25s : %20ju : %8s : %12s\n", argv[1], size, hum, hum2);
758 	free(hum);
759 	free(hum2);
760 
761 	return EXIT_SUCCESS;
762 }
763 #endif /* TEST_PROGRAM */
764