xref: /openbsd-src/sbin/pdisk/io.c (revision f4081a220753e60fa588b8656e7555a04bc34d27)
1 /*	$OpenBSD: io.c,v 1.27 2016/01/27 16:38:37 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 			break;
86 		} else {
87 			/* skip */
88 		}
89 	}
90 	return;
91 }
92 
93 
94 int
95 get_okay(const char *prompt, int default_value)
96 {
97 	int c;
98 
99 	flush_to_newline(0);
100 	printf(prompt);
101 
102 	for (;;) {
103 		c = my_getch();
104 
105 		if (c <= 0) {
106 			break;
107 		} else if (c == ' ' || c == '\t') {
108 			/* skip blanks and tabs */
109 		} else if (c == '\n') {
110 			my_ungetch(c);
111 			return default_value;
112 		} else if (c == 'y' || c == 'Y') {
113 			return 1;
114 		} else if (c == 'n' || c == 'N') {
115 			return 0;
116 		} else {
117 			flush_to_newline(0);
118 			printf(prompt);
119 		}
120 	}
121 	return -1;
122 }
123 
124 int
125 get_command(const char *prompt, int promptBeforeGet, int *command)
126 {
127 	int c;
128 
129 	if (promptBeforeGet)
130 		printf(prompt);
131 
132 	for (;;) {
133 		c = my_getch();
134 
135 		if (c <= 0) {
136 			break;
137 		} else if (c == ' ' || c == '\t') {
138 			/* skip blanks and tabs */
139 		} else if (c == '\n') {
140 			printf(prompt);
141 		} else {
142 			*command = c;
143 			return 1;
144 		}
145 	}
146 	return 0;
147 }
148 
149 int
150 get_number_argument(const char *prompt, long *number)
151 {
152 	int c;
153 	int result = 0;
154 
155 	for (;;) {
156 		c = my_getch();
157 
158 		if (c <= 0) {
159 			break;
160 		} else if (c == ' ' || c == '\t') {
161 			/* skip blanks and tabs */
162 		} else if (c == '\n') {
163 			printf(prompt);
164 		} else if ('0' <= c && c <= '9') {
165 			*number = get_number(c);
166 			result = 1;
167 			break;
168 		} else {
169 			my_ungetch(c);
170 			*number = 0;
171 			break;
172 		}
173 	}
174 	return result;
175 }
176 
177 
178 long
179 get_number(int first_char)
180 {
181 	int c, base, digit, ret_value;
182 
183 	if (first_char != '0') {
184 		c = first_char;
185 		base = 10;
186 		digit = BAD_DIGIT;
187 	} else if ((c = my_getch()) == 'x' || c == 'X') {
188 		c = my_getch();
189 		base = 16;
190 		digit = BAD_DIGIT;
191 	} else {
192 		my_ungetch(c);
193 		c = first_char;
194 		base = 8;
195 		digit = 0;
196 	}
197 	ret_value = 0;
198 	for (ret_value = 0;; c = my_getch()) {
199 		if (c >= '0' && c <= '9')
200 			digit = c - '0';
201 		else if (c >= 'A' && c <= 'F')
202 			digit = 10 + (c - 'A');
203 		else if (c >= 'a' && c <= 'f')
204 			digit = 10 + (c - 'a');
205 		else
206 			digit = BAD_DIGIT;
207 		if (digit >= base)
208 			break;
209 		ret_value = ret_value * base + digit;
210 	}
211 	my_ungetch(c);
212 	return (ret_value);
213 }
214 
215 char *
216 get_dpistr_argument(const char *prompt)
217 {
218 	int c;
219 
220 	for (;;) {
221 		c = my_getch();
222 
223 		if (c <= 0) {
224 			break;
225 		} else if (c == ' ' || c == '\t') {
226 			/* skip blanks and tabs */
227 		} else if (c == '\n') {
228 			printf(prompt);
229 		} else if (c == '"' || c == '\'') {
230 			return get_string(c);
231 		} else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
232 		    (c == '-' || c == '/' || c == '.' || c == ':')) {
233 			my_ungetch(c);
234 			return get_string(' ');
235 		} else {
236 			my_ungetch(c);
237 			return NULL;
238 		}
239 	}
240 	return NULL;
241 }
242 
243 
244 char *
245 get_string(int eos)
246 {
247 	char buf[DPISTRLEN+1];
248 	char *s, *limit;
249 	int c;
250 
251 	memset(buf, 0, sizeof(buf));
252 	limit = buf + sizeof(buf);
253 
254 	c = my_getch();
255 	for (s = buf;; c = my_getch()) {
256 		if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) {
257 			*s = 0;
258 			break;
259 		} else if (c == '\n') {
260 			*s = 0;
261 			my_ungetch(c);
262 			break;
263 		} else {
264 			*s++ = c;
265 			if (s >= limit)
266 				return NULL;
267 		}
268 	}
269 	return (strdup(buf));
270 }
271 
272 
273 unsigned long
274 get_multiplier(long divisor)
275 {
276 	unsigned long result, extra;
277 	int c;
278 
279 	c = my_getch();
280 
281 	extra = 1;
282 	if (c <= 0 || divisor <= 0) {
283 		result = 0;
284 	} else if (c == 't' || c == 'T') {
285 		result = 1024 * 1024;
286 		extra = 1024 * 1024;
287 	} else if (c == 'g' || c == 'G') {
288 		result = 1024 * 1024 * 1024;
289 	} else if (c == 'm' || c == 'M') {
290 		result = 1024 * 1024;
291 	} else if (c == 'k' || c == 'K') {
292 		result = 1024;
293 	} else {
294 		my_ungetch(c);
295 		result = 1;
296 	}
297 	if (result > 1) {
298 		if (extra > 1) {
299 			result /= divisor;
300 			if (result >= 4096)
301 				result = 0; /* overflow -> 20bits + >12bits */
302 			else
303 				result *= extra;
304 		} else if (result >= divisor) {
305 			result /= divisor;
306 		} else {
307 			result = 1;
308 		}
309 	}
310 	return result;
311 }
312 
313 
314 int
315 get_partition_modifier(void)
316 {
317 	int c, result;
318 
319 	result = 0;
320 
321 	c = my_getch();
322 
323 	if (c == 'p' || c == 'P')
324 		result = 1;
325 	else if (c > 0)
326 		my_ungetch(c);
327 
328 	return result;
329 }
330 
331 
332 int
333 number_of_digits(unsigned long value)
334 {
335 	int j;
336 
337 	j = 1;
338 	while (value > 9) {
339 		j++;
340 		value = value / 10;
341 	}
342 	return j;
343 }
344 
345 
346 /*
347  * Print a message on standard error & flush the input.
348  */
349 void
350 bad_input(const char *fmt,...)
351 {
352 	va_list ap;
353 
354 	va_start(ap, fmt);
355 	vfprintf(stderr, fmt, ap);
356 	va_end(ap);
357 	fprintf(stderr, "\n");
358 	flush_to_newline(1);
359 }
360