]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxcmd/input.c
xfsprogs: don't install platform_defs.h
[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 #define EXABYTES(x) ((long long)(x) << 60)
140 #define PETABYTES(x) ((long long)(x) << 50)
141 #define TERABYTES(x) ((long long)(x) << 40)
142 #define GIGABYTES(x) ((long long)(x) << 30)
143 #define MEGABYTES(x) ((long long)(x) << 20)
144 #define KILOBYTES(x) ((long long)(x) << 10)
145
146 long long
147 cvtnum(
148 size_t blocksize,
149 size_t sectorsize,
150 char *s)
151 {
152 long long i;
153 char *sp;
154 int c;
155
156 i = strtoll(s, &sp, 0);
157 if (i == 0 && sp == s)
158 return -1LL;
159 if (*sp == '\0')
160 return i;
161
162 if (sp[1] != '\0')
163 return -1LL;
164
165 c = tolower(*sp);
166 switch (c) {
167 case 'b':
168 return i * blocksize;
169 case 's':
170 return i * sectorsize;
171 case 'k':
172 return KILOBYTES(i);
173 case 'm':
174 return MEGABYTES(i);
175 case 'g':
176 return GIGABYTES(i);
177 case 't':
178 return TERABYTES(i);
179 case 'p':
180 return PETABYTES(i);
181 case 'e':
182 return EXABYTES(i);
183 }
184 return -1LL;
185 }
186
187 #define TO_EXABYTES(x) ((x) / EXABYTES(1))
188 #define TO_PETABYTES(x) ((x) / PETABYTES(1))
189 #define TO_TERABYTES(x) ((x) / TERABYTES(1))
190 #define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
191 #define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
192 #define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
193
194 void
195 cvtstr(
196 double value,
197 char *str,
198 size_t size)
199 {
200 char *fmt;
201 int precise;
202
203 precise = ((double)value * 1000 == (double)(int)value * 1000);
204
205 if (value >= EXABYTES(1)) {
206 fmt = precise ? "%.f EiB" : "%.3f EiB";
207 snprintf(str, size, fmt, TO_EXABYTES(value));
208 } else if (value >= PETABYTES(1)) {
209 fmt = precise ? "%.f PiB" : "%.3f PiB";
210 snprintf(str, size, fmt, TO_PETABYTES(value));
211 } else if (value >= TERABYTES(1)) {
212 fmt = precise ? "%.f TiB" : "%.3f TiB";
213 snprintf(str, size, fmt, TO_TERABYTES(value));
214 } else if (value >= GIGABYTES(1)) {
215 fmt = precise ? "%.f GiB" : "%.3f GiB";
216 snprintf(str, size, fmt, TO_GIGABYTES(value));
217 } else if (value >= MEGABYTES(1)) {
218 fmt = precise ? "%.f MiB" : "%.3f MiB";
219 snprintf(str, size, fmt, TO_MEGABYTES(value));
220 } else if (value >= KILOBYTES(1)) {
221 fmt = precise ? "%.f KiB" : "%.3f KiB";
222 snprintf(str, size, fmt, TO_KILOBYTES(value));
223 } else {
224 snprintf(str, size, "%f bytes", value);
225 }
226 }
227
228 #define MINUTES_TO_SECONDS(m) ((m) * 60)
229 #define HOURS_TO_SECONDS(h) ((h) * MINUTES_TO_SECONDS(60))
230 #define DAYS_TO_SECONDS(d) ((d) * HOURS_TO_SECONDS(24))
231 #define WEEKS_TO_SECONDS(w) ((w) * DAYS_TO_SECONDS(7))
232
233 unsigned long
234 cvttime(
235 char *s)
236 {
237 unsigned long i;
238 char *sp;
239
240 i = strtoul(s, &sp, 0);
241 if (i == 0 && sp == s)
242 return 0;
243 if (*sp == '\0')
244 return i;
245 if ((*sp == 'm' && sp[1] == '\0') ||
246 (strcmp(sp, "minutes") == 0) ||
247 (strcmp(sp, "minute") == 0))
248 return MINUTES_TO_SECONDS(i);
249 if ((*sp == 'h' && sp[1] == '\0') ||
250 (strcmp(sp, "hours") == 0) ||
251 (strcmp(sp, "hour") == 0))
252 return HOURS_TO_SECONDS(i);
253 if ((*sp == 'd' && sp[1] == '\0') ||
254 (strcmp(sp, "days") == 0) ||
255 (strcmp(sp, "day") == 0))
256 return DAYS_TO_SECONDS(i);
257 if ((*sp == 'w' && sp[1] == '\0') ||
258 (strcmp(sp, "weeks") == 0) ||
259 (strcmp(sp, "week") == 0))
260 return WEEKS_TO_SECONDS(i);
261 return 0;
262 }
263
264 struct timeval
265 tadd(struct timeval t1, struct timeval t2)
266 {
267 t1.tv_usec += t2.tv_usec;
268 if (t1.tv_usec > 1000000) {
269 t1.tv_usec -= 1000000;
270 t1.tv_sec++;
271 }
272 t1.tv_sec += t2.tv_sec;
273 return t1;
274 }
275
276 struct timeval
277 tsub(struct timeval t1, struct timeval t2)
278 {
279 t1.tv_usec -= t2.tv_usec;
280 if (t1.tv_usec < 0) {
281 t1.tv_usec += 1000000;
282 t1.tv_sec--;
283 }
284 t1.tv_sec -= t2.tv_sec;
285 return t1;
286 }
287
288 double
289 tdiv(double value, struct timeval tv)
290 {
291 return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
292 }
293
294 #define HOURS(sec) ((sec) / (60 * 60))
295 #define MINUTES(sec) (((sec) % (60 * 60)) / 60)
296 #define SECONDS(sec) ((sec) % 60)
297
298 void
299 timestr(
300 struct timeval *tv,
301 char *ts,
302 size_t size,
303 int format)
304 {
305 double usec = (double)tv->tv_usec / 1000000.0;
306
307 if (format & TERSE_FIXED_TIME) {
308 if (!HOURS(tv->tv_sec)) {
309 snprintf(ts, size, "%u:%02u.%02u",
310 (unsigned int) MINUTES(tv->tv_sec),
311 (unsigned int) SECONDS(tv->tv_sec),
312 (unsigned int) usec * 100);
313 return;
314 }
315 format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
316 }
317
318 if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
319 snprintf(ts, size, "%u:%02u:%02u.%02u",
320 (unsigned int) HOURS(tv->tv_sec),
321 (unsigned int) MINUTES(tv->tv_sec),
322 (unsigned int) SECONDS(tv->tv_sec),
323 (unsigned int) usec * 100);
324 } else {
325 snprintf(ts, size, "0.%04u sec", (unsigned int) usec * 10000);
326 }
327 }
328
329 /*
330 * Convert from arbitrary user strings into a numeric ID.
331 * If it's all numeric, we convert that inplace, else we do
332 * the name lookup, and return the found identifier.
333 */
334
335 prid_t
336 prid_from_string(
337 char *project)
338 {
339 fs_project_t *prj;
340 unsigned long prid_long;
341 char *sp;
342
343 /*
344 * Allow either a full numeric or a valid projectname, even
345 * if it starts with a digit.
346 */
347 prid_long = strtoul(project, &sp, 10);
348 if (*project != '\0' && *sp == '\0') {
349 if ((prid_long == ULONG_MAX && errno == ERANGE)
350 || (prid_long > (prid_t)-1))
351 return -1;
352 return (prid_t)prid_long;
353 }
354 prj = getprnam(project);
355 if (prj)
356 return prj->pr_prid;
357 return -1;
358 }
359
360 uid_t
361 uid_from_string(
362 char *user)
363 {
364 struct passwd *pwd;
365 unsigned long uid_long;
366 char *sp;
367
368 uid_long = strtoul(user, &sp, 10);
369 if (sp != user) {
370 if ((uid_long == ULONG_MAX && errno == ERANGE)
371 || (uid_long > (uid_t)-1))
372 return -1;
373 return (uid_t)uid_long;
374 }
375 pwd = getpwnam(user);
376 if (pwd)
377 return pwd->pw_uid;
378 return -1;
379 }
380
381 gid_t
382 gid_from_string(
383 char *group)
384 {
385 struct group *grp;
386 unsigned long gid_long;
387 char *sp;
388
389 gid_long = strtoul(group, &sp, 10);
390 if (sp != group) {
391 if ((gid_long == ULONG_MAX && errno == ERANGE)
392 || (gid_long > (gid_t)-1))
393 return -1;
394 return (gid_t)gid_long;
395 }
396 grp = getgrnam(group);
397 if (grp)
398 return grp->gr_gid;
399 return -1;
400 }
401
402 bool isdigits_only(
403 const char *str)
404 {
405 int i;
406
407 for (i = 0; i < strlen(str); i++) {
408 if (!isdigit(str[i]))
409 return false;
410 }
411 return true;
412 }
413
414 #define HAVE_FTW_H 1 /* TODO: configure me */
415
416 #ifndef HAVE_FTW_H
417 int
418 nftw(
419 char *dir,
420 int (*fn)(const char *, const struct stat *, int, struct FTW *),
421 int depth,
422 int flags)
423 {
424 fprintf(stderr, "%s: not implemented, no recursion available\n",
425 __FUNCTION__);
426 return 0;
427 }
428 #endif