]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxcmd/input.c
libxcmd: add cvt{int, long} to convert strings to int and long
[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 /*
153 * Convert string to int64_t, set errno if the conversion fails or
154 * doesn't fit. Does not allow unit specifiers. Sets errno to zero
155 * prior to conversion so you can check for bad inputs by examining
156 * errno immediately after the call.
157 */
158 int64_t
159 cvt_s64(
160 char *s,
161 int base)
162 {
163 long long i;
164 char *sp;
165
166 errno = 0;
167 i = strtoll(s, &sp, base);
168 /*
169 * If the input would over or underflow, return the clamped
170 * value and let the user check errno. If we went all the
171 * way to the end of the input, return the converted value;
172 * errno will be zero.
173 */
174 if (errno || (*sp == '\0' && sp != s))
175 return i;
176
177 /* Not all the input was consumed, return error. */
178 errno = -ERANGE;
179 return INT64_MIN;
180 }
181
182 /*
183 * Convert string to int32_t, set errno if the conversion fails or
184 * doesn't fit. Does not allow unit specifiers. Sets errno to zero
185 * prior to conversion so you can check for bad inputs by examining
186 * errno immediately after the call.
187 */
188 int32_t
189 cvt_s32(
190 char *s,
191 int base)
192 {
193 int64_t i;
194
195 i = cvt_s64(s, base);
196 if (errno)
197 return i;
198 if (i > INT32_MAX || i < INT32_MIN) {
199 errno = -ERANGE;
200 return INT32_MIN;
201 }
202 return i;
203 }
204
205 /*
206 * Convert string to int16_t, set errno if the conversion fails or
207 * doesn't fit. Does not allow unit specifiers. Sets errno to zero
208 * prior to conversion so you can check for bad inputs by examining
209 * errno immediately after the call.
210 */
211 int16_t
212 cvt_s16(
213 char *s,
214 int base)
215 {
216 int64_t i;
217
218 i = cvt_s64(s, base);
219 if (errno)
220 return i;
221 if (i > INT16_MAX || i < INT16_MIN) {
222 errno = -ERANGE;
223 return INT16_MIN;
224 }
225 return i;
226 }
227
228 /*
229 * Convert string to uint64_t, set errno if the conversion fails or
230 * doesn't fit. Does not allow unit specifiers. Sets errno to zero
231 * prior to conversion so you can check for bad inputs by examining
232 * errno immediately after the call.
233 */
234 uint64_t
235 cvt_u64(
236 char *s,
237 int base)
238 {
239 long long i;
240 char *sp;
241
242 errno = 0;
243 i = strtoll(s, &sp, base);
244 /*
245 * If the input would over or underflow, return the clamped
246 * value and let the user check errno. If we went all the
247 * way to the end of the input, return the converted value;
248 * errno will be zero.
249 */
250 if (errno || (*sp == '\0' && sp != s))
251 return i;
252
253 /* Not all the input was consumed, return error. */
254 errno = -ERANGE;
255 return UINT64_MAX;
256 }
257
258 /*
259 * Convert string to uint32_t, set errno if the conversion fails or
260 * doesn't fit. Does not allow unit specifiers. Sets errno to zero
261 * prior to conversion so you can check for bad inputs by examining
262 * errno immediately after the call.
263 */
264 uint32_t
265 cvt_u32(
266 char *s,
267 int base)
268 {
269 uint64_t i;
270
271 i = cvt_u64(s, base);
272 if (errno)
273 return i;
274 if (i > UINT32_MAX) {
275 errno = -ERANGE;
276 return UINT32_MAX;
277 }
278 return i;
279 }
280
281 /*
282 * Convert string to uint16_t, set errno if the conversion fails or
283 * doesn't fit. Does not allow unit specifiers. Sets errno to zero
284 * prior to conversion so you can check for bad inputs by examining
285 * errno immediately after the call.
286 */
287 uint16_t
288 cvt_u16(
289 char *s,
290 int base)
291 {
292 uint64_t i;
293
294 i = cvt_u64(s, base);
295 if (errno)
296 return i;
297 if (i > UINT16_MAX) {
298 errno = -ERANGE;
299 return UINT16_MAX;
300 }
301 return i;
302 }
303
304 #define EXABYTES(x) ((long long)(x) << 60)
305 #define PETABYTES(x) ((long long)(x) << 50)
306 #define TERABYTES(x) ((long long)(x) << 40)
307 #define GIGABYTES(x) ((long long)(x) << 30)
308 #define MEGABYTES(x) ((long long)(x) << 20)
309 #define KILOBYTES(x) ((long long)(x) << 10)
310
311 long long
312 cvtnum(
313 size_t blocksize,
314 size_t sectorsize,
315 char *s)
316 {
317 long long i;
318 char *sp;
319 int c;
320
321 i = strtoll(s, &sp, 0);
322 if (i == 0 && sp == s)
323 return -1LL;
324 if (*sp == '\0')
325 return i;
326
327 if (sp[1] != '\0')
328 return -1LL;
329
330 c = tolower(*sp);
331 switch (c) {
332 case 'b':
333 return i * blocksize;
334 case 's':
335 return i * sectorsize;
336 case 'k':
337 return KILOBYTES(i);
338 case 'm':
339 return MEGABYTES(i);
340 case 'g':
341 return GIGABYTES(i);
342 case 't':
343 return TERABYTES(i);
344 case 'p':
345 return PETABYTES(i);
346 case 'e':
347 return EXABYTES(i);
348 }
349 return -1LL;
350 }
351
352 #define TO_EXABYTES(x) ((x) / EXABYTES(1))
353 #define TO_PETABYTES(x) ((x) / PETABYTES(1))
354 #define TO_TERABYTES(x) ((x) / TERABYTES(1))
355 #define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
356 #define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
357 #define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
358
359 void
360 cvtstr(
361 double value,
362 char *str,
363 size_t size)
364 {
365 char *fmt;
366 int precise;
367
368 precise = ((double)value * 1000 == (double)(int)value * 1000);
369
370 if (value >= EXABYTES(1)) {
371 fmt = precise ? "%.f EiB" : "%.3f EiB";
372 snprintf(str, size, fmt, TO_EXABYTES(value));
373 } else if (value >= PETABYTES(1)) {
374 fmt = precise ? "%.f PiB" : "%.3f PiB";
375 snprintf(str, size, fmt, TO_PETABYTES(value));
376 } else if (value >= TERABYTES(1)) {
377 fmt = precise ? "%.f TiB" : "%.3f TiB";
378 snprintf(str, size, fmt, TO_TERABYTES(value));
379 } else if (value >= GIGABYTES(1)) {
380 fmt = precise ? "%.f GiB" : "%.3f GiB";
381 snprintf(str, size, fmt, TO_GIGABYTES(value));
382 } else if (value >= MEGABYTES(1)) {
383 fmt = precise ? "%.f MiB" : "%.3f MiB";
384 snprintf(str, size, fmt, TO_MEGABYTES(value));
385 } else if (value >= KILOBYTES(1)) {
386 fmt = precise ? "%.f KiB" : "%.3f KiB";
387 snprintf(str, size, fmt, TO_KILOBYTES(value));
388 } else {
389 snprintf(str, size, "%f bytes", value);
390 }
391 }
392
393 #define MINUTES_TO_SECONDS(m) ((m) * 60)
394 #define HOURS_TO_SECONDS(h) ((h) * MINUTES_TO_SECONDS(60))
395 #define DAYS_TO_SECONDS(d) ((d) * HOURS_TO_SECONDS(24))
396 #define WEEKS_TO_SECONDS(w) ((w) * DAYS_TO_SECONDS(7))
397
398 unsigned long
399 cvttime(
400 char *s)
401 {
402 unsigned long i;
403 char *sp;
404
405 i = strtoul(s, &sp, 0);
406 if (i == 0 && sp == s)
407 return 0;
408 if (*sp == '\0')
409 return i;
410 if ((*sp == 'm' && sp[1] == '\0') ||
411 (strcmp(sp, "minutes") == 0) ||
412 (strcmp(sp, "minute") == 0))
413 return MINUTES_TO_SECONDS(i);
414 if ((*sp == 'h' && sp[1] == '\0') ||
415 (strcmp(sp, "hours") == 0) ||
416 (strcmp(sp, "hour") == 0))
417 return HOURS_TO_SECONDS(i);
418 if ((*sp == 'd' && sp[1] == '\0') ||
419 (strcmp(sp, "days") == 0) ||
420 (strcmp(sp, "day") == 0))
421 return DAYS_TO_SECONDS(i);
422 if ((*sp == 'w' && sp[1] == '\0') ||
423 (strcmp(sp, "weeks") == 0) ||
424 (strcmp(sp, "week") == 0))
425 return WEEKS_TO_SECONDS(i);
426 return 0;
427 }
428
429 struct timeval
430 tadd(struct timeval t1, struct timeval t2)
431 {
432 t1.tv_usec += t2.tv_usec;
433 if (t1.tv_usec > 1000000) {
434 t1.tv_usec -= 1000000;
435 t1.tv_sec++;
436 }
437 t1.tv_sec += t2.tv_sec;
438 return t1;
439 }
440
441 struct timeval
442 tsub(struct timeval t1, struct timeval t2)
443 {
444 t1.tv_usec -= t2.tv_usec;
445 if (t1.tv_usec < 0) {
446 t1.tv_usec += 1000000;
447 t1.tv_sec--;
448 }
449 t1.tv_sec -= t2.tv_sec;
450 return t1;
451 }
452
453 double
454 tdiv(double value, struct timeval tv)
455 {
456 return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
457 }
458
459 #define HOURS(sec) ((sec) / (60 * 60))
460 #define MINUTES(sec) (((sec) % (60 * 60)) / 60)
461 #define SECONDS(sec) ((sec) % 60)
462
463 void
464 timestr(
465 struct timeval *tv,
466 char *ts,
467 size_t size,
468 int format)
469 {
470 double usec = (double)tv->tv_usec / 1000000.0;
471
472 if (format & TERSE_FIXED_TIME) {
473 if (!HOURS(tv->tv_sec)) {
474 snprintf(ts, size, "%u:%02u.%02u",
475 (unsigned int) MINUTES(tv->tv_sec),
476 (unsigned int) SECONDS(tv->tv_sec),
477 (unsigned int) usec * 100);
478 return;
479 }
480 format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
481 }
482
483 if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
484 snprintf(ts, size, "%u:%02u:%02u.%02u",
485 (unsigned int) HOURS(tv->tv_sec),
486 (unsigned int) MINUTES(tv->tv_sec),
487 (unsigned int) SECONDS(tv->tv_sec),
488 (unsigned int) usec * 100);
489 } else {
490 snprintf(ts, size, "0.%04u sec", (unsigned int) usec * 10000);
491 }
492 }
493
494 /*
495 * Convert from a pair of arbitrary user strings into a timespec.
496 */
497
498 int
499 timespec_from_string(
500 const char * secs,
501 const char * nsecs,
502 struct timespec * ts)
503 {
504 char* p;
505 if (!secs || !nsecs || !ts)
506 return 1;
507 ts->tv_sec = strtoull(secs, &p, 0);
508 if (*p)
509 return 1;
510 ts->tv_nsec = strtoull(nsecs, &p, 0);
511 if (*p)
512 return 1;
513 return 0;
514 }
515
516 /*
517 * Convert from arbitrary user strings into a numeric ID.
518 * If it's all numeric, we convert that inplace, else we do
519 * the name lookup, and return the found identifier.
520 */
521
522 prid_t
523 prid_from_string(
524 char *project)
525 {
526 fs_project_t *prj;
527 unsigned long prid_long;
528 char *sp;
529
530 /*
531 * Allow either a full numeric or a valid projectname, even
532 * if it starts with a digit.
533 */
534 prid_long = strtoul(project, &sp, 10);
535 if (*project != '\0' && *sp == '\0') {
536 if ((prid_long == ULONG_MAX && errno == ERANGE)
537 || (prid_long > (prid_t)-1))
538 return -1;
539 return (prid_t)prid_long;
540 }
541 prj = getprnam(project);
542 if (prj)
543 return prj->pr_prid;
544 return -1;
545 }
546
547 uid_t
548 uid_from_string(
549 char *user)
550 {
551 struct passwd *pwd;
552 unsigned long uid_long;
553 char *sp;
554
555 uid_long = strtoul(user, &sp, 10);
556 if (sp != user && *sp == '\0') {
557 if ((uid_long == ULONG_MAX && errno == ERANGE)
558 || (uid_long > (uid_t)-1))
559 return -1;
560 return (uid_t)uid_long;
561 }
562 pwd = getpwnam(user);
563 if (pwd)
564 return pwd->pw_uid;
565 return -1;
566 }
567
568 gid_t
569 gid_from_string(
570 char *group)
571 {
572 struct group *grp;
573 unsigned long gid_long;
574 char *sp;
575
576 gid_long = strtoul(group, &sp, 10);
577 if (sp != group && *sp == '\0') {
578 if ((gid_long == ULONG_MAX && errno == ERANGE)
579 || (gid_long > (gid_t)-1))
580 return -1;
581 return (gid_t)gid_long;
582 }
583 grp = getgrnam(group);
584 if (grp)
585 return grp->gr_gid;
586 return -1;
587 }
588
589 bool isdigits_only(
590 const char *str)
591 {
592 int i;
593
594 for (i = 0; i < strlen(str); i++) {
595 if (!isdigit(str[i]))
596 return false;
597 }
598 return true;
599 }
600
601 #define HAVE_FTW_H 1 /* TODO: configure me */
602
603 #ifndef HAVE_FTW_H
604 int
605 nftw(
606 char *dir,
607 int (*fn)(const char *, const struct stat *, int, struct FTW *),
608 int depth,
609 int flags)
610 {
611 fprintf(stderr, "%s: not implemented, no recursion available\n",
612 __FUNCTION__);
613 return 0;
614 }
615 #endif