xref: /openbsd-src/sbin/pdisk/io.c (revision 32401e4b3cd40e6bf50d41c88f6f3f4e61967aea)
1 /*	$OpenBSD: io.c,v 1.29 2016/01/29 18:40:08 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 UNGET_MAX_COUNT 10
40 
41 short	unget_buf[UNGET_MAX_COUNT + 1];
42 int	unget_count;
43 
44 static int	get_number(long *);
45 static char    *get_string(int);
46 static int	my_getch (void);
47 
48 int
49 my_getch()
50 {
51 	if (unget_count > 0)
52 		return unget_buf[--unget_count];
53 	else
54 		return getc(stdin);
55 }
56 
57 
58 void
59 my_ungetch(int c)
60 {
61 	/*
62          * In practice there is never more than one character in
63          * the unget_buf, but what's a little overkill among friends?
64          */
65 	if (unget_count < UNGET_MAX_COUNT)
66 		unget_buf[unget_count++] = c;
67 	else
68 		errx(1, "Programmer error in my_ungetch().");
69 }
70 
71 void
72 flush_to_newline(int keep_newline)
73 {
74 	int c;
75 
76 	for (;;) {
77 		c = my_getch();
78 
79 		if (c <= 0) {
80 			break;
81 		} else if (c == '\n') {
82 			if (keep_newline)
83 				my_ungetch(c);
84 			break;
85 		} else {
86 			/* skip */
87 		}
88 	}
89 	return;
90 }
91 
92 
93 int
94 get_okay(const char *prompt, int default_value)
95 {
96 	int c;
97 
98 	flush_to_newline(0);
99 	printf(prompt);
100 
101 	for (;;) {
102 		c = my_getch();
103 
104 		if (c <= 0) {
105 			break;
106 		} else if (c == ' ' || c == '\t') {
107 			/* skip blanks and tabs */
108 		} else if (c == '\n') {
109 			my_ungetch(c);
110 			return default_value;
111 		} else if (c == 'y' || c == 'Y') {
112 			return 1;
113 		} else if (c == 'n' || c == 'N') {
114 			return 0;
115 		} else {
116 			flush_to_newline(0);
117 			printf(prompt);
118 		}
119 	}
120 	return -1;
121 }
122 
123 int
124 get_command(const char *prompt, int promptBeforeGet, int *command)
125 {
126 	int c;
127 
128 	if (promptBeforeGet)
129 		printf(prompt);
130 
131 	for (;;) {
132 		c = my_getch();
133 
134 		if (c <= 0) {
135 			break;
136 		} else if (c == ' ' || c == '\t') {
137 			/* skip blanks and tabs */
138 		} else if (c == '\n') {
139 			printf(prompt);
140 		} else {
141 			*command = c;
142 			return 1;
143 		}
144 	}
145 	return 0;
146 }
147 
148 int
149 get_number_argument(const char *prompt, long *number)
150 {
151 	int c;
152 	int result = 0;
153 
154 	for (;;) {
155 		c = my_getch();
156 
157 		if (c <= 0) {
158 			break;
159 		} else if (c == ' ' || c == '\t') {
160 			/* skip blanks and tabs */
161 		} else if (c == '\n') {
162 			printf(prompt);
163 		} else if ('0' <= c && c <= '9') {
164 			my_ungetch(c);
165 			result = get_number(number);
166 			break;
167 		} else {
168 			my_ungetch(c);
169 			*number = 0;
170 			break;
171 		}
172 	}
173 	return result;
174 }
175 
176 
177 int
178 get_number(long *number)
179 {
180 	long value;
181 	int c;
182 
183 	value = 0;
184 	while ((c = my_getch())) {
185 		if (c >= '0' && c <= '9') {
186 			value = value * 10 + (c - '0');
187 		} else if (c == ' ' || c == '\t' || c == '\n') {
188 			my_ungetch(c);
189 			*number = value;
190 			return 1;
191 		} else {
192 			return 0;
193 		}
194 	}
195 
196 	return 0;
197 }
198 
199 char *
200 get_dpistr_argument(const char *prompt)
201 {
202 	int c;
203 
204 	for (;;) {
205 		c = my_getch();
206 
207 		if (c <= 0) {
208 			break;
209 		} else if (c == ' ' || c == '\t') {
210 			/* skip blanks and tabs */
211 		} else if (c == '\n') {
212 			printf(prompt);
213 		} else if (c == '"' || c == '\'') {
214 			return get_string(c);
215 		} else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
216 		    (c == '-' || c == '/' || c == '.' || c == ':')) {
217 			my_ungetch(c);
218 			return get_string(' ');
219 		} else {
220 			my_ungetch(c);
221 			return NULL;
222 		}
223 	}
224 	return NULL;
225 }
226 
227 
228 char *
229 get_string(int eos)
230 {
231 	char buf[DPISTRLEN+1];
232 	char *s, *limit;
233 	int c;
234 
235 	memset(buf, 0, sizeof(buf));
236 	limit = buf + sizeof(buf);
237 
238 	c = my_getch();
239 	for (s = buf;; c = my_getch()) {
240 		if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) {
241 			*s = 0;
242 			break;
243 		} else if (c == '\n') {
244 			*s = 0;
245 			my_ungetch(c);
246 			break;
247 		} else {
248 			*s++ = c;
249 			if (s >= limit)
250 				return NULL;
251 		}
252 	}
253 	return strdup(buf);
254 }
255 
256 
257 unsigned long
258 get_multiplier(long divisor)
259 {
260 	unsigned long result, extra;
261 	int c;
262 
263 	c = my_getch();
264 
265 	extra = 1;
266 	if (c <= 0 || divisor <= 0) {
267 		result = 0;
268 	} else if (c == 't' || c == 'T') {
269 		result = 1024 * 1024;
270 		extra = 1024 * 1024;
271 	} else if (c == 'g' || c == 'G') {
272 		result = 1024 * 1024 * 1024;
273 	} else if (c == 'm' || c == 'M') {
274 		result = 1024 * 1024;
275 	} else if (c == 'k' || c == 'K') {
276 		result = 1024;
277 	} else {
278 		my_ungetch(c);
279 		result = 1;
280 	}
281 	if (result > 1) {
282 		if (extra > 1) {
283 			result /= divisor;
284 			if (result >= 4096)
285 				result = 0; /* overflow -> 20bits + >12bits */
286 			else
287 				result *= extra;
288 		} else if (result >= divisor) {
289 			result /= divisor;
290 		} else {
291 			result = 1;
292 		}
293 	}
294 	return result;
295 }
296 
297 
298 int
299 get_partition_modifier(void)
300 {
301 	int c, result;
302 
303 	result = 0;
304 
305 	c = my_getch();
306 
307 	if (c == 'p' || c == 'P')
308 		result = 1;
309 	else if (c > 0)
310 		my_ungetch(c);
311 
312 	return result;
313 }
314 
315 
316 int
317 number_of_digits(unsigned long value)
318 {
319 	int j;
320 
321 	j = 1;
322 	while (value > 9) {
323 		j++;
324 		value = value / 10;
325 	}
326 	return j;
327 }
328 
329 
330 /*
331  * Print a message on standard error & flush the input.
332  */
333 void
334 bad_input(const char *fmt,...)
335 {
336 	va_list ap;
337 
338 	va_start(ap, fmt);
339 	vfprintf(stderr, fmt, ap);
340 	va_end(ap);
341 	fprintf(stderr, "\n");
342 	flush_to_newline(1);
343 }
344