]> git.ipfire.org Git - thirdparty/util-linux.git/blame - lib/strutils.c
build-sys: provide alternatives for err, errx, warn and warnx
[thirdparty/util-linux.git] / lib / strutils.c
CommitLineData
8abcf290
DB
1/*
2 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
3 * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
4 */
5
c4ecaf21 6#include <stdio.h>
8abcf290
DB
7#include <stdlib.h>
8#include <inttypes.h>
9#include <ctype.h>
10#include <errno.h>
ce877f2d 11#include <sys/stat.h>
c4ecaf21
DB
12#include <locale.h>
13#include <string.h>
eb76ca98 14#include "c.h"
8abcf290
DB
15
16static int do_scale_by_power (uintmax_t *x, int base, int power)
17{
18 while (power--) {
19 if (UINTMAX_MAX / base < *x)
20 return -2;
21 *x *= base;
22 }
23 return 0;
24}
25
cf8de26a
KZ
26/*
27 * strtosize() - convert string to size (uintmax_t).
28 *
29 * Supported suffixes:
30 *
31 * XiB or X for 2^N
32 * where X = {K,M,G,T,P,E,Y,Z}
33 * or X = {k,m,g,t,p,e} (undocumented for backward compatibility only)
34 * for example:
35 * 10KiB = 10240
36 * 10K = 10240
37 *
38 * XB for 10^N
39 * where X = {K,M,G,T,P,E,Y,Z}
40 * for example:
41 * 10KB = 10000
42 *
43 * Note that the function does not accept numbers with '-' (negative sign)
44 * prefix.
cf8de26a 45 */
cf8de26a
KZ
46int strtosize(const char *str, uintmax_t *res)
47{
48 char *p;
49 uintmax_t x;
50 int base = 1024, rc = 0;
51
52 *res = 0;
53
54 if (!str || !*str)
55 goto err;
56
57 /* Only positive numbers are acceptable
58 *
59 * Note that this check is not perfect, it would be better to
60 * use lconv->negative_sign. But coreutils use the same solution,
61 * so it's probably good enough...
62 */
63 p = (char *) str;
64 while (isspace((unsigned char) *p))
65 p++;
66 if (*p == '-')
67 goto err;
68 p = NULL;
69
70 errno = 0;
71 x = strtoumax(str, &p, 0);
72
73 if (p == str ||
74 (errno != 0 && (x == UINTMAX_MAX || x == 0)))
75 goto err;
76
77 if (!p || !*p)
78 goto done; /* without suffix */
79
80 /*
81 * Check size suffixes
82 */
83 if (*(p + 1) == 'i' && *(p + 2) == 'B' && !*(p + 3))
84 base = 1024; /* XiB, 2^N */
85 else if (*(p + 1) == 'B' && !*(p + 2))
86 base = 1000; /* XB, 10^N */
87 else if (*(p + 1))
88 goto err; /* unexpected suffix */
89
90 switch(*p) {
91 case 'K':
92 case 'k':
93 rc = do_scale_by_power(&x, base, 1);
94 break;
95 case 'M':
96 case 'm':
97 rc = do_scale_by_power(&x, base, 2);
98 break;
99 case 'G':
100 case 'g':
101 rc = do_scale_by_power(&x, base, 3);
102 break;
103 case 'T':
104 case 't':
105 rc = do_scale_by_power(&x, base, 4);
106 break;
107 case 'P':
108 case 'p':
109 rc = do_scale_by_power(&x, base, 5);
110 break;
111 case 'E':
112 case 'e':
113 rc = do_scale_by_power(&x, base, 6);
114 break;
115 case 'Z':
116 rc = do_scale_by_power(&x, base, 7);
117 break;
118 case 'Y':
119 rc = do_scale_by_power(&x, base, 8);
120 break;
121 default:
122 goto err;
123 }
124
125done:
126 *res = x;
127 return rc;
128err:
129 return -1;
130}
131
8abcf290
DB
132#ifndef HAVE_STRNLEN
133size_t strnlen(const char *s, size_t maxlen)
134{
135 int i;
cf8de26a 136
8abcf290
DB
137 for (i = 0; i < maxlen; i++) {
138 if (s[i] == '\0')
139 return i + 1;
140 }
141 return maxlen;
142}
143#endif
cf8de26a 144
8abcf290
DB
145#ifndef HAVE_STRNCHR
146char *strnchr(const char *s, size_t maxlen, int c)
cf8de26a 147{
8abcf290
DB
148 for (; maxlen-- && *s != '\0'; ++s)
149 if (*s == (char)c)
150 return (char *)s;
151 return NULL;
152}
153#endif
cf8de26a 154
8abcf290
DB
155#ifndef HAVE_STRNDUP
156char *strndup(const char *s, size_t n)
157{
158 size_t len = strnlen(s, n);
159 char *new = (char *) malloc((len + 1) * sizeof(char));
160 if (!new)
161 return NULL;
162 new[len] = '\0';
163 return (char *) memcpy(new, s, len);
164}
165#endif
cf8de26a 166
8abcf290
DB
167/*
168 * same as strtol(3) but exit on failure instead of returning crap
169 */
170long strtol_or_err(const char *str, const char *errmesg)
171{
172 long num;
173 char *end = NULL;
cf8de26a 174
8abcf290
DB
175 if (str == NULL || *str == '\0')
176 goto err;
177 errno = 0;
178 num = strtol(str, &end, 10);
cf8de26a 179
8abcf290
DB
180 if (errno || (end && *end))
181 goto err;
182
183 return num;
184err:
185 if (errno)
186 err(EXIT_FAILURE, "%s: '%s'", errmesg, str);
187 else
188 errx(EXIT_FAILURE, "%s: '%s'", errmesg, str);
189 return 0;
190}
ce877f2d
KZ
191
192/*
193 * Converts stat->st_mode to ls(1)-like mode string. The size of "str" must
194 * be 10 bytes.
195 */
196void strmode(mode_t mode, char *str)
197{
198 if (S_ISDIR(mode))
199 str[0] = 'd';
200 else if (S_ISLNK(mode))
201 str[0] = 'l';
202 else if (S_ISCHR(mode))
203 str[0] = 'c';
204 else if (S_ISBLK(mode))
205 str[0] = 'b';
206 else if (S_ISSOCK(mode))
207 str[0] = 's';
208 else if (S_ISFIFO(mode))
209 str[0] = 'p';
210 else if (S_ISREG(mode))
211 str[0] = '-';
212
213 str[1] = mode & S_IRUSR ? 'r' : '-';
214 str[2] = mode & S_IWUSR ? 'w' : '-';
215 str[3] = (mode & S_ISUID
216 ? (mode & S_IXUSR ? 's' : 'S')
217 : (mode & S_IXUSR ? 'x' : '-'));
218 str[4] = mode & S_IRGRP ? 'r' : '-';
219 str[5] = mode & S_IWGRP ? 'w' : '-';
220 str[6] = (mode & S_ISGID
221 ? (mode & S_IXGRP ? 's' : 'S')
222 : (mode & S_IXGRP ? 'x' : '-'));
223 str[7] = mode & S_IROTH ? 'r' : '-';
224 str[8] = mode & S_IWOTH ? 'w' : '-';
225 str[9] = (mode & S_ISVTX
226 ? (mode & S_IXOTH ? 't' : 'T')
227 : (mode & S_IXOTH ? 'x' : '-'));
228 str[10] = '\0';
229}
c4ecaf21
DB
230
231/*
232 * returns exponent (2^x=n) in range KiB..PiB
233 */
234static int get_exp(uint64_t n)
235{
236 int shft;
237
238 for (shft = 10; shft <= 60; shft += 10) {
239 if (n < (1ULL << shft))
240 break;
241 }
242 return shft - 10;
243}
244
245char *size_to_human_string(uint64_t bytes)
246{
247 char buf[32];
248 int dec, frac, exp;
249 const char *letters = "BKMGTP";
250 char c;
251
252 exp = get_exp(bytes);
253 c = *(letters + (exp ? exp / 10 : 0));
254 dec = exp ? bytes / (1ULL << exp) : bytes;
255 frac = exp ? bytes % (1ULL << exp) : 0;
256
257 if (frac) {
258 /* round */
259 frac = (frac / (1ULL << (exp - 10)) + 50) / 100;
260 if (frac == 10)
261 dec++, frac = 0;
262 }
263
264 if (frac) {
265 struct lconv const *l = localeconv();
266 char *dp = l ? l->decimal_point : NULL;
267
268 if (!dp || !*dp)
269 dp = ".";
270 snprintf(buf, sizeof(buf), "%d%s%d%c", dec, dp, frac, c);
271 } else
272 snprintf(buf, sizeof(buf), "%d%c", dec, c);
273
274 return strdup(buf);
275}
013bff51
KZ
276
277
278#ifdef TEST_PROGRAM
279
013bff51
KZ
280int main(int argc, char *argv[])
281{
282 uintmax_t size = 0;
283
284 if (argc < 2) {
285 fprintf(stderr, "usage: %s <number>[suffix]\n", argv[0]);
286 exit(EXIT_FAILURE);
287 }
288
289 if (strtosize(argv[1], &size))
290 errx(EXIT_FAILURE, "invalid size '%s' value", argv[1]);
291
292 printf("%25s : %20ju\n", argv[1], size);
293 return EXIT_FAILURE;
294}
295#endif /* TEST_PROGRAM */