xref: /openbsd/sbin/pdisk/io.c (revision dda28197)
1 /*	$OpenBSD: io.c,v 1.31 2016/02/01 18:55:00 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 <sys/queue.h>
31 
32 #include <err.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdarg.h>
37 
38 #include "partition_map.h"
39 #include "io.h"
40 
41 #define UNGET_MAX_COUNT 10
42 
43 short	unget_buf[UNGET_MAX_COUNT + 1];
44 int	unget_count;
45 
46 static int	get_number(long *);
47 static char    *get_string(int);
48 static int	my_getch (void);
49 
50 int
51 my_getch()
52 {
53 	if (unget_count > 0)
54 		return unget_buf[--unget_count];
55 	else
56 		return getc(stdin);
57 }
58 
59 
60 void
61 my_ungetch(int c)
62 {
63 	/*
64          * In practice there is never more than one character in
65          * the unget_buf, but what's a little overkill among friends?
66          */
67 	if (unget_count < UNGET_MAX_COUNT)
68 		unget_buf[unget_count++] = c;
69 	else
70 		errx(1, "Programmer error in my_ungetch().");
71 }
72 
73 void
74 flush_to_newline(int keep_newline)
75 {
76 	int c;
77 
78 	for (;;) {
79 		c = my_getch();
80 
81 		if (c <= 0) {
82 			break;
83 		} else if (c == '\n') {
84 			if (keep_newline)
85 				my_ungetch(c);
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("%s", 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("%s", 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("%s", 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("%s", 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("%s", prompt);
165 		} else if ('0' <= c && c <= '9') {
166 			my_ungetch(c);
167 			result = get_number(number);
168 			break;
169 		} else {
170 			my_ungetch(c);
171 			*number = 0;
172 			break;
173 		}
174 	}
175 	return result;
176 }
177 
178 
179 int
180 get_number(long *number)
181 {
182 	long value;
183 	int c;
184 
185 	value = 0;
186 	while ((c = my_getch())) {
187 		if (c >= '0' && c <= '9') {
188 			value = value * 10 + (c - '0');
189 		} else if (c == ' ' || c == '\t' || c == '\n') {
190 			my_ungetch(c);
191 			*number = value;
192 			return 1;
193 		} else {
194 			return 0;
195 		}
196 	}
197 
198 	return 0;
199 }
200 
201 char *
202 get_dpistr_argument(const char *prompt)
203 {
204 	int c;
205 
206 	for (;;) {
207 		c = my_getch();
208 
209 		if (c <= 0) {
210 			break;
211 		} else if (c == ' ' || c == '\t') {
212 			/* skip blanks and tabs */
213 		} else if (c == '\n') {
214 			printf("%s", prompt);
215 		} else if (c == '"' || c == '\'') {
216 			return get_string(c);
217 		} else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
218 		    (c == '-' || c == '/' || c == '.' || c == ':')) {
219 			my_ungetch(c);
220 			return get_string(' ');
221 		} else {
222 			my_ungetch(c);
223 			return NULL;
224 		}
225 	}
226 	return NULL;
227 }
228 
229 
230 char *
231 get_string(int eos)
232 {
233 	char buf[DPISTRLEN+1];
234 	char *s, *limit;
235 	int c;
236 
237 	memset(buf, 0, sizeof(buf));
238 	limit = buf + sizeof(buf);
239 
240 	c = my_getch();
241 	for (s = buf;; c = my_getch()) {
242 		if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) {
243 			*s = 0;
244 			break;
245 		} else if (c == '\n') {
246 			*s = 0;
247 			my_ungetch(c);
248 			break;
249 		} else {
250 			*s++ = c;
251 			if (s >= limit)
252 				return NULL;
253 		}
254 	}
255 	return strdup(buf);
256 }
257 
258 
259 unsigned long
260 get_multiplier(long divisor)
261 {
262 	unsigned long result, extra;
263 	int c;
264 
265 	c = my_getch();
266 
267 	extra = 1;
268 	if (c <= 0 || divisor <= 0) {
269 		result = 0;
270 	} else if (c == 't' || c == 'T') {
271 		result = 1024 * 1024;
272 		extra = 1024 * 1024;
273 	} else if (c == 'g' || c == 'G') {
274 		result = 1024 * 1024 * 1024;
275 	} else if (c == 'm' || c == 'M') {
276 		result = 1024 * 1024;
277 	} else if (c == 'k' || c == 'K') {
278 		result = 1024;
279 	} else {
280 		my_ungetch(c);
281 		result = 1;
282 	}
283 	if (result > 1) {
284 		if (extra > 1) {
285 			result /= divisor;
286 			if (result >= 4096)
287 				result = 0; /* overflow -> 20bits + >12bits */
288 			else
289 				result *= extra;
290 		} else if (result >= divisor) {
291 			result /= divisor;
292 		} else {
293 			result = 1;
294 		}
295 	}
296 	return result;
297 }
298 
299 
300 int
301 get_partition_modifier(void)
302 {
303 	int c, result;
304 
305 	result = 0;
306 
307 	c = my_getch();
308 
309 	if (c == 'p' || c == 'P')
310 		result = 1;
311 	else if (c > 0)
312 		my_ungetch(c);
313 
314 	return result;
315 }
316 
317 
318 int
319 number_of_digits(unsigned long value)
320 {
321 	int j;
322 
323 	j = 1;
324 	while (value > 9) {
325 		j++;
326 		value = value / 10;
327 	}
328 	return j;
329 }
330 
331 
332 /*
333  * Print a message on standard error & flush the input.
334  */
335 void
336 bad_input(const char *fmt,...)
337 {
338 	va_list ap;
339 
340 	va_start(ap, fmt);
341 	vfprintf(stderr, fmt, ap);
342 	va_end(ap);
343 	fprintf(stderr, "\n");
344 	flush_to_newline(1);
345 }
346