io.c revision 1.31
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
43short	unget_buf[UNGET_MAX_COUNT + 1];
44int	unget_count;
45
46static int	get_number(long *);
47static char    *get_string(int);
48static int	my_getch (void);
49
50int
51my_getch()
52{
53	if (unget_count > 0)
54		return unget_buf[--unget_count];
55	else
56		return getc(stdin);
57}
58
59
60void
61my_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
73void
74flush_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
95int
96get_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
125int
126get_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
150int
151get_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
179int
180get_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
201char *
202get_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
230char *
231get_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
259unsigned long
260get_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
300int
301get_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
318int
319number_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 */
335void
336bad_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