]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxcmd/input.c
xfs_io: refactor numlen into a library function
[thirdparty/xfsprogs-dev.git] / libxcmd / input.c
1 /*
2 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "platform_defs.h"
20 #include "input.h"
21 #include <ctype.h>
22 #include <stdbool.h>
23
24 #if defined(ENABLE_READLINE)
25 # include <readline/history.h>
26 # include <readline/readline.h>
27 #elif defined(ENABLE_EDITLINE)
28 # include <histedit.h>
29 #endif
30
31 extern char *progname;
32
33 static char *
34 get_prompt(void)
35 {
36 static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];
37
38 if (!prompt[0])
39 snprintf(prompt, sizeof(prompt), "%s> ", progname);
40 return prompt;
41 }
42
43 #if defined(ENABLE_READLINE)
44 char *
45 fetchline(void)
46 {
47 char *line;
48
49 line = readline(get_prompt());
50 if (line && *line)
51 add_history(line);
52 return line;
53 }
54 #elif defined(ENABLE_EDITLINE)
55 static char *el_get_prompt(EditLine *e) { return get_prompt(); }
56 char *
57 fetchline(void)
58 {
59 static EditLine *el;
60 static History *hist;
61 HistEvent hevent;
62 char *line;
63 int count;
64
65 if (!el) {
66 hist = history_init();
67 history(hist, &hevent, H_SETSIZE, 100);
68 el = el_init(progname, stdin, stdout, stderr);
69 el_source(el, NULL);
70 el_set(el, EL_SIGNAL, 1);
71 el_set(el, EL_PROMPT, el_get_prompt);
72 el_set(el, EL_HIST, history, (const char *)hist);
73 }
74 line = strdup(el_gets(el, &count));
75 if (line) {
76 if (count > 0)
77 line[count-1] = '\0';
78 if (*line)
79 history(hist, &hevent, H_ENTER, line);
80 }
81 return line;
82 }
83 #else
84 # define MAXREADLINESZ 1024
85 char *
86 fetchline(void)
87 {
88 char *p, *line = malloc(MAXREADLINESZ);
89
90 if (!line)
91 return NULL;
92 printf("%s", get_prompt());
93 fflush(stdout);
94 if (!fgets(line, MAXREADLINESZ, stdin)) {
95 free(line);
96 return NULL;
97 }
98 p = line + strlen(line);
99 if (p != line && p[-1] == '\n')
100 p[-1] = '\0';
101 return line;
102 }
103 #endif
104
105 char **
106 breakline(
107 char *input,
108 int *count)
109 {
110 int c = 0;
111 char *p;
112 char **rval = calloc(sizeof(char *), 1);
113
114 while (rval && (p = strsep(&input, " ")) != NULL) {
115 if (!*p)
116 continue;
117 c++;
118 rval = realloc(rval, sizeof(*rval) * (c + 1));
119 if (!rval) {
120 c = 0;
121 break;
122 }
123 rval[c - 1] = p;
124 rval[c] = NULL;
125 }
126 *count = c;
127 return rval;
128 }
129
130 void
131 doneline(
132 char *input,
133 char **vec)
134 {
135 free(input);
136 free(vec);
137 }
138
139 size_t
140 numlen(
141 uint64_t val,
142 size_t base)
143 {
144 uint64_t tmp;
145 size_t len;
146
147 for (len = 0, tmp = val; tmp > 0; tmp = tmp / base)
148 len++;
149 return len == 0 ? 1 : len;
150 }
151
152 #define EXABYTES(x) ((long long)(x) << 60)
153 #define PETABYTES(x) ((long long)(x) << 50)
154 #define TERABYTES(x) ((long long)(x) << 40)
155 #define GIGABYTES(x) ((long long)(x) << 30)
156 #define MEGABYTES(x) ((long long)(x) << 20)
157 #define KILOBYTES(x) ((long long)(x) << 10)
158
159 long long
160 cvtnum(
161 size_t blocksize,
162 size_t sectorsize,
163 char *s)
164 {
165 long long i;
166 char *sp;
167 int c;
168
169 i = strtoll(s, &sp, 0);
170 if (i == 0 && sp == s)
171 return -1LL;
172 if (*sp == '\0')
173 return i;
174
175 if (sp[1] != '\0')
176 return -1LL;
177
178 c = tolower(*sp);
179 switch (c) {
180 case 'b':
181 return i * blocksize;
182 case 's':
183 return i * sectorsize;
184 case 'k':
185 return KILOBYTES(i);
186 case 'm':
187 return MEGABYTES(i);
188 case 'g':
189 return GIGABYTES(i);
190 case 't':
191 return TERABYTES(i);
192 case 'p':
193 return PETABYTES(i);
194 case 'e':
195 return EXABYTES(i);
196 }
197 return -1LL;
198 }
199
200 #define TO_EXABYTES(x) ((x) / EXABYTES(1))
201 #define TO_PETABYTES(x) ((x) / PETABYTES(1))
202 #define TO_TERABYTES(x) ((x) / TERABYTES(1))
203 #define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
204 #define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
205 #define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
206
207 void
208 cvtstr(
209 double value,
210 char *str,
211 size_t size)
212 {
213 char *fmt;
214 int precise;
215
216 precise = ((double)value * 1000 == (double)(int)value * 1000);
217
218 if (value >= EXABYTES(1)) {
219 fmt = precise ? "%.f EiB" : "%.3f EiB";
220 snprintf(str, size, fmt, TO_EXABYTES(value));
221 } else if (value >= PETABYTES(1)) {
222 fmt = precise ? "%.f PiB" : "%.3f PiB";
223 snprintf(str, size, fmt, TO_PETABYTES(value));
224 } else if (value >= TERABYTES(1)) {
225 fmt = precise ? "%.f TiB" : "%.3f TiB";
226 snprintf(str, size, fmt, TO_TERABYTES(value));
227 } else if (value >= GIGABYTES(1)) {
228 fmt = precise ? "%.f GiB" : "%.3f GiB";
229 snprintf(str, size, fmt, TO_GIGABYTES(value));
230 } else if (value >= MEGABYTES(1)) {
231 fmt = precise ? "%.f MiB" : "%.3f MiB";
232 snprintf(str, size, fmt, TO_MEGABYTES(value));
233 } else if (value >= KILOBYTES(1)) {
234 fmt = precise ? "%.f KiB" : "%.3f KiB";
235 snprintf(str, size, fmt, TO_KILOBYTES(value));
236 } else {
237 snprintf(str, size, "%f bytes", value);
238 }
239 }
240
241 #define MINUTES_TO_SECONDS(m) ((m) * 60)
242 #define HOURS_TO_SECONDS(h) ((h) * MINUTES_TO_SECONDS(60))
243 #define DAYS_TO_SECONDS(d) ((d) * HOURS_TO_SECONDS(24))
244 #define WEEKS_TO_SECONDS(w) ((w) * DAYS_TO_SECONDS(7))
245
246 unsigned long
247 cvttime(
248 char *s)
249 {
250 unsigned long i;
251 char *sp;
252
253 i = strtoul(s, &sp, 0);
254 if (i == 0 && sp == s)
255 return 0;
256 if (*sp == '\0')
257 return i;
258 if ((*sp == 'm' && sp[1] == '\0') ||
259 (strcmp(sp, "minutes") == 0) ||
260 (strcmp(sp, "minute") == 0))
261 return MINUTES_TO_SECONDS(i);
262 if ((*sp == 'h' && sp[1] == '\0') ||
263 (strcmp(sp, "hours") == 0) ||
264 (strcmp(sp, "hour") == 0))
265 return HOURS_TO_SECONDS(i);
266 if ((*sp == 'd' && sp[1] == '\0') ||
267 (strcmp(sp, "days") == 0) ||
268 (strcmp(sp, "day") == 0))
269 return DAYS_TO_SECONDS(i);
270 if ((*sp == 'w' && sp[1] == '\0') ||
271 (strcmp(sp, "weeks") == 0) ||
272 (strcmp(sp, "week") == 0))
273 return WEEKS_TO_SECONDS(i);
274 return 0;
275 }
276
277 struct timeval
278 tadd(struct timeval t1, struct timeval t2)
279 {
280 t1.tv_usec += t2.tv_usec;
281 if (t1.tv_usec > 1000000) {
282 t1.tv_usec -= 1000000;
283 t1.tv_sec++;
284 }
285 t1.tv_sec += t2.tv_sec;
286 return t1;
287 }
288
289 struct timeval
290 tsub(struct timeval t1, struct timeval t2)
291 {
292 t1.tv_usec -= t2.tv_usec;
293 if (t1.tv_usec < 0) {
294 t1.tv_usec += 1000000;
295 t1.tv_sec--;
296 }
297 t1.tv_sec -= t2.tv_sec;
298 return t1;
299 }
300
301 double
302 tdiv(double value, struct timeval tv)
303 {
304 return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
305 }
306
307 #define HOURS(sec) ((sec) / (60 * 60))
308 #define MINUTES(sec) (((sec) % (60 * 60)) / 60)
309 #define SECONDS(sec) ((sec) % 60)
310
311 void
312 timestr(
313 struct timeval *tv,
314 char *ts,
315 size_t size,
316 int format)
317 {
318 double usec = (double)tv->tv_usec / 1000000.0;
319
320 if (format & TERSE_FIXED_TIME) {
321 if (!HOURS(tv->tv_sec)) {
322 snprintf(ts, size, "%u:%02u.%02u",
323 (unsigned int) MINUTES(tv->tv_sec),
324 (unsigned int) SECONDS(tv->tv_sec),
325 (unsigned int) usec * 100);
326 return;
327 }
328 format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
329 }
330
331 if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
332 snprintf(ts, size, "%u:%02u:%02u.%02u",
333 (unsigned int) HOURS(tv->tv_sec),
334 (unsigned int) MINUTES(tv->tv_sec),
335 (unsigned int) SECONDS(tv->tv_sec),
336 (unsigned int) usec * 100);
337 } else {
338 snprintf(ts, size, "0.%04u sec", (unsigned int) usec * 10000);
339 }
340 }
341
342 /*
343 * Convert from a pair of arbitrary user strings into a timespec.
344 */
345
346 int
347 timespec_from_string(
348 const char * secs,
349 const char * nsecs,
350 struct timespec * ts)
351 {
352 char* p;
353 if (!secs || !nsecs || !ts)
354 return 1;
355 ts->tv_sec = strtoull(secs, &p, 0);
356 if (*p)
357 return 1;
358 ts->tv_nsec = strtoull(nsecs, &p, 0);
359 if (*p)
360 return 1;
361 return 0;
362 }
363
364 /*
365 * Convert from arbitrary user strings into a numeric ID.
366 * If it's all numeric, we convert that inplace, else we do
367 * the name lookup, and return the found identifier.
368 */
369
370 prid_t
371 prid_from_string(
372 char *project)
373 {
374 fs_project_t *prj;
375 unsigned long prid_long;
376 char *sp;
377
378 /*
379 * Allow either a full numeric or a valid projectname, even
380 * if it starts with a digit.
381 */
382 prid_long = strtoul(project, &sp, 10);
383 if (*project != '\0' && *sp == '\0') {
384 if ((prid_long == ULONG_MAX && errno == ERANGE)
385 || (prid_long > (prid_t)-1))
386 return -1;
387 return (prid_t)prid_long;
388 }
389 prj = getprnam(project);
390 if (prj)
391 return prj->pr_prid;
392 return -1;
393 }
394
395 uid_t
396 uid_from_string(
397 char *user)
398 {
399 struct passwd *pwd;
400 unsigned long uid_long;
401 char *sp;
402
403 uid_long = strtoul(user, &sp, 10);
404 if (sp != user && *sp == '\0') {
405 if ((uid_long == ULONG_MAX && errno == ERANGE)
406 || (uid_long > (uid_t)-1))
407 return -1;
408 return (uid_t)uid_long;
409 }
410 pwd = getpwnam(user);
411 if (pwd)
412 return pwd->pw_uid;
413 return -1;
414 }
415
416 gid_t
417 gid_from_string(
418 char *group)
419 {
420 struct group *grp;
421 unsigned long gid_long;
422 char *sp;
423
424 gid_long = strtoul(group, &sp, 10);
425 if (sp != group && *sp == '\0') {
426 if ((gid_long == ULONG_MAX && errno == ERANGE)
427 || (gid_long > (gid_t)-1))
428 return -1;
429 return (gid_t)gid_long;
430 }
431 grp = getgrnam(group);
432 if (grp)
433 return grp->gr_gid;
434 return -1;
435 }
436
437 bool isdigits_only(
438 const char *str)
439 {
440 int i;
441
442 for (i = 0; i < strlen(str); i++) {
443 if (!isdigit(str[i]))
444 return false;
445 }
446 return true;
447 }
448
449 #define HAVE_FTW_H 1 /* TODO: configure me */
450
451 #ifndef HAVE_FTW_H
452 int
453 nftw(
454 char *dir,
455 int (*fn)(const char *, const struct stat *, int, struct FTW *),
456 int depth,
457 int flags)
458 {
459 fprintf(stderr, "%s: not implemented, no recursion available\n",
460 __FUNCTION__);
461 return 0;
462 }
463 #endif