xref: /openbsd-src/sbin/pdisk/io.c (revision 8799a2d3ee7d3e0bcd7cd963ce1816b6e8a1734b)
1 /*	$OpenBSD: io.c,v 1.24 2016/01/26 23:41:48 krw Exp $	*/
2 
3 /*
4  * io.c - simple io and input parsing routines
5  *
6  * Written by Eryk Vershen
7  */
8 
9 /*
10  * Copyright 1996,1997,1998 by Apple Computer, Inc.
11  *              All Rights Reserved
12  *
13  * Permission to use, copy, modify, and distribute this software and
14  * its documentation for any purpose and without fee is hereby granted,
15  * provided that the above copyright notice appears in all copies and
16  * that both the copyright notice and this permission notice appear in
17  * supporting documentation.
18  *
19  * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
20  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE.
22  *
23  * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
24  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
25  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
26  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
27  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28  */
29 
30 #include <err.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35 
36 #include "dpme.h"
37 #include "io.h"
38 
39 #define BAD_DIGIT 17		/* must be greater than any base */
40 #define UNGET_MAX_COUNT 10
41 
42 short	unget_buf[UNGET_MAX_COUNT + 1];
43 int	unget_count;
44 
45 static long	get_number(int);
46 static char    *get_string(int);
47 static int	my_getch (void);
48 
49 int
50 my_getch()
51 {
52 	if (unget_count > 0)
53 		return (unget_buf[--unget_count]);
54 	else
55 		return (getc(stdin));
56 }
57 
58 
59 void
60 my_ungetch(int c)
61 {
62 	/*
63          * In practice there is never more than one character in
64          * the unget_buf, but what's a little overkill among friends?
65          */
66 	if (unget_count < UNGET_MAX_COUNT)
67 		unget_buf[unget_count++] = c;
68 	else
69 		errx(1, "Programmer error in my_ungetch().");
70 }
71 
72 void
73 flush_to_newline(int keep_newline)
74 {
75 	int c;
76 
77 	for (;;) {
78 		c = my_getch();
79 
80 		if (c <= 0) {
81 			break;
82 		} else if (c == '\n') {
83 			if (keep_newline) {
84 				my_ungetch(c);
85 			}
86 			break;
87 		} else {
88 			/* skip */
89 		}
90 	}
91 	return;
92 }
93 
94 
95 int
96 get_okay(const char *prompt, int default_value)
97 {
98 	int c;
99 
100 	flush_to_newline(0);
101 	printf(prompt);
102 
103 	for (;;) {
104 		c = my_getch();
105 
106 		if (c <= 0) {
107 			break;
108 		} else if (c == ' ' || c == '\t') {
109 			/* skip blanks and tabs */
110 		} else if (c == '\n') {
111 			my_ungetch(c);
112 			return default_value;
113 		} else if (c == 'y' || c == 'Y') {
114 			return 1;
115 		} else if (c == 'n' || c == 'N') {
116 			return 0;
117 		} else {
118 			flush_to_newline(0);
119 			printf(prompt);
120 		}
121 	}
122 	return -1;
123 }
124 
125 int
126 get_command(const char *prompt, int promptBeforeGet, int *command)
127 {
128 	int c;
129 
130 	if (promptBeforeGet)
131 		printf(prompt);
132 
133 	for (;;) {
134 		c = my_getch();
135 
136 		if (c <= 0) {
137 			break;
138 		} else if (c == ' ' || c == '\t') {
139 			/* skip blanks and tabs */
140 		} else if (c == '\n') {
141 			printf(prompt);
142 		} else {
143 			*command = c;
144 			return 1;
145 		}
146 	}
147 	return 0;
148 }
149 
150 int
151 get_number_argument(const char *prompt, long *number)
152 {
153 	int c;
154 	int result = 0;
155 
156 	for (;;) {
157 		c = my_getch();
158 
159 		if (c <= 0) {
160 			break;
161 		} else if (c == ' ' || c == '\t') {
162 			/* skip blanks and tabs */
163 		} else if (c == '\n') {
164 			printf(prompt);
165 		} else if ('0' <= c && c <= '9') {
166 			*number = get_number(c);
167 			result = 1;
168 			break;
169 		} else {
170 			my_ungetch(c);
171 			*number = 0;
172 			break;
173 		}
174 	}
175 	return result;
176 }
177 
178 
179 long
180 get_number(int first_char)
181 {
182 	int c, base, digit, ret_value;
183 
184 	if (first_char != '0') {
185 		c = first_char;
186 		base = 10;
187 		digit = BAD_DIGIT;
188 	} else if ((c = my_getch()) == 'x' || c == 'X') {
189 		c = my_getch();
190 		base = 16;
191 		digit = BAD_DIGIT;
192 	} else {
193 		my_ungetch(c);
194 		c = first_char;
195 		base = 8;
196 		digit = 0;
197 	}
198 	ret_value = 0;
199 	for (ret_value = 0;; c = my_getch()) {
200 		if (c >= '0' && c <= '9') {
201 			digit = c - '0';
202 		} else if (c >= 'A' && c <= 'F') {
203 			digit = 10 + (c - 'A');
204 		} else if (c >= 'a' && c <= 'f') {
205 			digit = 10 + (c - 'a');
206 		} else {
207 			digit = BAD_DIGIT;
208 		}
209 		if (digit >= base) {
210 			break;
211 		}
212 		ret_value = ret_value * base + digit;
213 	}
214 	my_ungetch(c);
215 	return (ret_value);
216 }
217 
218 char *
219 get_dpistr_argument(const char *prompt)
220 {
221 	int c;
222 
223 	for (;;) {
224 		c = my_getch();
225 
226 		if (c <= 0) {
227 			break;
228 		} else if (c == ' ' || c == '\t') {
229 			/* skip blanks and tabs */
230 		} else if (c == '\n') {
231 			printf(prompt);
232 		} else if (c == '"' || c == '\'') {
233 			return get_string(c);
234 		} else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
235 		    (c == '-' || c == '/' || c == '.' || c == ':')) {
236 			my_ungetch(c);
237 			return get_string(' ');
238 		} else {
239 			my_ungetch(c);
240 			return NULL;
241 		}
242 	}
243 	return NULL;
244 }
245 
246 
247 char *
248 get_string(int eos)
249 {
250 	char buf[DPISTRLEN];
251 	char *s, *limit;
252 	int c;
253 
254 	memset(buf, 0, sizeof(buf));
255 	limit = buf + sizeof(buf);
256 
257 	c = my_getch();
258 	for (s = buf;; c = my_getch()) {
259 		if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) {
260 			*s = 0;
261 			break;
262 		} else if (c == '\n') {
263 			*s = 0;
264 			my_ungetch(c);
265 			break;
266 		} else {
267 			*s++ = c;
268 			if (s >= limit)
269 				return NULL;
270 		}
271 	}
272 	return (strdup(buf));
273 }
274 
275 
276 unsigned long
277 get_multiplier(long divisor)
278 {
279 	unsigned long result, extra;
280 	int c;
281 
282 	c = my_getch();
283 
284 	extra = 1;
285 	if (c <= 0 || divisor <= 0) {
286 		result = 0;
287 	} else if (c == 't' || c == 'T') {
288 		result = 1024 * 1024;
289 		extra = 1024 * 1024;
290 	} else if (c == 'g' || c == 'G') {
291 		result = 1024 * 1024 * 1024;
292 	} else if (c == 'm' || c == 'M') {
293 		result = 1024 * 1024;
294 	} else if (c == 'k' || c == 'K') {
295 		result = 1024;
296 	} else {
297 		my_ungetch(c);
298 		result = 1;
299 	}
300 	if (result > 1) {
301 		if (extra > 1) {
302 			result /= divisor;
303 			if (result >= 4096) {
304 				/* overflow -> 20bits + >12bits */
305 				result = 0;
306 			} else {
307 				result *= extra;
308 			}
309 		} else if (result >= divisor) {
310 			result /= divisor;
311 		} else {
312 			result = 1;
313 		}
314 	}
315 	return result;
316 }
317 
318 
319 int
320 get_partition_modifier(void)
321 {
322 	int c, result;
323 
324 	result = 0;
325 
326 	c = my_getch();
327 
328 	if (c == 'p' || c == 'P')
329 		result = 1;
330 	else if (c > 0)
331 		my_ungetch(c);
332 
333 	return result;
334 }
335 
336 
337 int
338 number_of_digits(unsigned long value)
339 {
340 	int j;
341 
342 	j = 1;
343 	while (value > 9) {
344 		j++;
345 		value = value / 10;
346 	}
347 	return j;
348 }
349 
350 
351 /*
352  * Print a message on standard error & flush the input.
353  */
354 void
355 bad_input(const char *fmt,...)
356 {
357 	va_list ap;
358 
359 	va_start(ap, fmt);
360 	vfprintf(stderr, fmt, ap);
361 	va_end(ap);
362 	fprintf(stderr, "\n");
363 	flush_to_newline(1);
364 }
365