xref: /netbsd-src/external/bsd/pdisk/dist/io.c (revision 81a719df6ea00ae13b21ce821a407eaf4d42dee6)
1 //
2 // io.c - simple io and input parsing routines
3 //
4 // Written by Eryk Vershen
5 //
6 
7 /*
8  * Copyright 1996,1997,1998 by Apple Computer, Inc.
9  *              All Rights Reserved
10  *
11  * Permission to use, copy, modify, and distribute this software and
12  * its documentation for any purpose and without fee is hereby granted,
13  * provided that the above copyright notice appears in all copies and
14  * that both the copyright notice and this permission notice appear in
15  * supporting documentation.
16  *
17  * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19  * FOR A PARTICULAR PURPOSE.
20  *
21  * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
22  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
23  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
24  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
25  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26  */
27 
28 // for *printf()
29 #include <stdio.h>
30 
31 // for malloc() & free()
32 #if !defined(__linux__)
33 #include <stdlib.h>
34 #else
35 #include <malloc.h>
36 #endif
37 // for strncpy()
38 #include <string.h>
39 // for va_start(), etc.
40 #include <stdarg.h>
41 // for errno
42 #include <errno.h>
43 
44 #include "io.h"
45 #include "errors.h"
46 
47 
48 //
49 // Defines
50 //
51 #define BAD_DIGIT 17	/* must be greater than any base */
52 #define	STRING_CHUNK	16
53 #define UNGET_MAX_COUNT 10
54 #ifndef __linux__
55 #ifndef __unix__
56 #define SCSI_FD 8
57 #endif
58 #ifdef NeXT
59 #define loff_t off_t
60 #define llseek lseek
61 #else
62 #define loff_t long
63 #define llseek lseek
64 #endif
65 #endif
66 
67 
68 //
69 // Types
70 //
71 
72 
73 //
74 // Global Constants
75 //
76 const long kDefault = -1;
77 
78 
79 //
80 // Global Variables
81 //
82 short unget_buf[UNGET_MAX_COUNT+1];
83 int unget_count;
84 char io_buffer[MAXIOSIZE];
85 
86 
87 //
88 // Forward declarations
89 //
90 long get_number(int first_char);
91 char* get_string(int eos);
92 int my_getch(void);
93 void my_ungetch(int c);
94 
95 //
96 // Routines
97 //
98 int
my_getch(void)99 my_getch(void)
100 {
101     if (unget_count > 0) {
102 	return (unget_buf[--unget_count]);
103     } else {
104 	return (getc(stdin));
105     }
106 }
107 
108 
109 void
my_ungetch(int c)110 my_ungetch(int c)
111 {
112     // In practice there is never more than one character in
113     // the unget_buf, but what's a little overkill among friends?
114 
115     if (unget_count < UNGET_MAX_COUNT) {
116 	unget_buf[unget_count++] = c;
117     } else {
118 	fatal(-1, "Programmer error in my_ungetch().");
119     }
120 }
121 
122 
123 void
flush_to_newline(int keep_newline)124 flush_to_newline(int keep_newline)
125 {
126     int		c;
127 
128     for (;;) {
129 	c = my_getch();
130 
131 	if (c <= 0) {
132 	    break;
133 	} else if (c == '\n') {
134 	    if (keep_newline) {
135 		my_ungetch(c);
136 	    }
137 	    break;
138 	} else {
139 	    // skip
140 	}
141     }
142     return;
143 }
144 
145 
146 int
get_okay(const char * prompt,int default_value)147 get_okay(const char *prompt, int default_value)
148 {
149     int		c;
150 
151     flush_to_newline(0);
152     printf("%s", prompt);
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 	    my_ungetch(c);
163 	    return default_value;
164 	} else if (c == 'y' || c == 'Y') {
165 	    return 1;
166 	} else if (c == 'n' || c == 'N') {
167 	    return 0;
168 	} else {
169 	    flush_to_newline(0);
170 	    printf("%s", prompt);
171 	}
172     }
173     return -1;
174 }
175 
176 
177 int
get_command(const char * prompt,int promptBeforeGet,int * command)178 get_command(const char *prompt, int promptBeforeGet, int *command)
179 {
180     int		c;
181 
182     if (promptBeforeGet) {
183 	printf("%s", prompt);
184     }
185     for (;;) {
186 	c = my_getch();
187 
188 	if (c <= 0) {
189 	    break;
190 	} else if (c == ' ' || c == '\t') {
191 	    // skip blanks and tabs
192 	} else if (c == '\n') {
193 	    printf("%s", prompt);
194 	} else {
195 	    *command = c;
196 	    return 1;
197 	}
198     }
199     return 0;
200 }
201 
202 
203 int
get_number_argument(const char * prompt,long * number,long default_value)204 get_number_argument(const char *prompt, long *number, long default_value)
205 {
206     int c;
207     int result = 0;
208 
209     for (;;) {
210 	c = my_getch();
211 
212 	if (c <= 0) {
213 	    break;
214 	} else if (c == ' ' || c == '\t') {
215 	    // skip blanks and tabs
216 	} else if (c == '\n') {
217 	    if (default_value == kDefault) {
218 		printf("%s", prompt);
219 	    } else {
220 		my_ungetch(c);
221 		*number = default_value;
222 		result = 1;
223 		break;
224 	    }
225 	} else if ('0' <= c && c <= '9') {
226 	    *number = get_number(c);
227 	    result = 1;
228 	    break;
229 	} else {
230 	    my_ungetch(c);
231 	    *number = 0;
232 	    break;
233 	}
234     }
235     return result;
236 }
237 
238 
239 long
get_number(int first_char)240 get_number(int first_char)
241 {
242     register int c;
243     int base;
244     int digit;
245     int ret_value;
246 
247     if (first_char != '0') {
248 	c = first_char;
249 	base = 10;
250 	digit = BAD_DIGIT;
251     } else if ((c=my_getch()) == 'x' || c == 'X') {
252 	c = my_getch();
253 	base = 16;
254 	digit = BAD_DIGIT;
255     } else {
256 	my_ungetch(c);
257 	c = first_char;
258 	base = 8;
259 	digit = 0;
260     }
261     ret_value = 0;
262     for (ret_value = 0; ; c = my_getch()) {
263 	if (c >= '0' && c <= '9') {
264 	    digit = c - '0';
265 	} else if (c >='A' && c <= 'F') {
266 	    digit = 10 + (c - 'A');
267 	} else if (c >='a' && c <= 'f') {
268 	    digit = 10 + (c - 'a');
269 	} else {
270 	    digit = BAD_DIGIT;
271 	}
272 	if (digit >= base) {
273 	    break;
274 	}
275 	ret_value = ret_value * base + digit;
276     }
277     my_ungetch(c);
278     return(ret_value);
279 }
280 
281 
282 int
get_string_argument(const char * prompt,char ** string,int reprompt)283 get_string_argument(const char *prompt, char **string, int reprompt)
284 {
285     int c;
286     int result = 0;
287 
288     for (;;) {
289 	c = my_getch();
290 
291 	if (c <= 0) {
292 	    break;
293 	} else if (c == ' ' || c == '\t') {
294 	    // skip blanks and tabs
295 	} else if (c == '\n') {
296 	    if (reprompt) {
297 		printf("%s", prompt);
298 	    } else {
299 		my_ungetch(c);
300 		*string = NULL;
301 		break;
302 	    }
303 	} else if (c == '"' || c == '\'') {
304 	    *string = get_string(c);
305 	    result = 1;
306 	    break;
307 	} else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
308 		|| (c == '-' || c == '/' || c == '.' || c == ':')) {
309 	    my_ungetch(c);
310 	    *string = get_string(' ');
311 	    result = 1;
312 	    break;
313 	} else {
314 	    my_ungetch(c);
315 	    *string = NULL;
316 	    break;
317 	}
318     }
319     return result;
320 }
321 
322 
323 char *
get_string(int eos)324 get_string(int eos)
325 {
326     int c;
327     char *s;
328     char *ret_value;
329     char *limit;
330     int length;
331     ptrdiff_t off;
332 
333     ret_value = (char *) malloc(STRING_CHUNK);
334     if (ret_value == NULL) {
335 	error(errno, "can't allocate memory for string buffer");
336 	return NULL;
337     }
338     length = STRING_CHUNK;
339     limit = ret_value + length;
340 
341     c = my_getch();
342     for (s = ret_value; ; c = my_getch()) {
343 	if (s >= limit) {
344 	    // expand string
345 	    limit = (char *) malloc(length+STRING_CHUNK);
346 	    if (limit == NULL) {
347 		error(errno, "can't allocate memory for string buffer");
348 		ret_value[length-1] = 0;
349 		break;
350 	    }
351 	    strncpy(limit, ret_value, length);
352 	    off = s - ret_value;
353 	    free(ret_value);
354 	    s = limit + off;
355 	    ret_value = limit;
356 	    length += STRING_CHUNK;
357 	    limit = ret_value + length;
358 	}
359 	if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) {
360 	    *s++ = 0;
361 	    break;
362 	} else if (c == '\n') {
363 	    *s++ = 0;
364 	    my_ungetch(c);
365 	    break;
366 	} else {
367 	    *s++ = c;
368 	}
369     }
370     return(ret_value);
371 }
372 
373 
374 uint32_t
get_multiplier(long divisor)375 get_multiplier(long divisor)
376 {
377     int c;
378     uint32_t result;
379     uint32_t extra;
380 
381     c = my_getch();
382 
383     extra = 1;
384     if (c <= 0 || divisor <= 0) {
385 	result = 0;
386     } else if (c == 't' || c == 'T') {
387 	result = 1024*1024;
388 	extra = 1024*1024;
389     } else if (c == 'g' || c == 'G') {
390 	result = 1024*1024*1024;
391     } else if (c == 'm' || c == 'M') {
392 	result = 1024*1024;
393     } else if (c == 'k' || c == 'K') {
394 	result = 1024;
395     } else {
396 	my_ungetch(c);
397 	result = 1;
398     }
399     if (result > 1) {
400 	if (extra > 1) {
401 	    result /= divisor;
402 	    if (result >= 4096) {
403 		/* overflow -> 20bits + >12bits */
404 		result = 0;
405 	    } else {
406 		result *= extra;
407 	    }
408 	} else if ((long long)result >= divisor) {
409 	    result /= divisor;
410 	} else {
411 	    result = 1;
412 	}
413     }
414     return result;
415 }
416 
417 
418 int
get_partition_modifier(void)419 get_partition_modifier(void)
420 {
421     int c;
422     int result;
423 
424     result = 0;
425 
426     c = my_getch();
427 
428     if (c == 'p' || c == 'P') {
429     	result = 1;
430     } else if (c > 0) {
431 	my_ungetch(c);
432     }
433     return result;
434 }
435 
436 
437 int
number_of_digits(uint32_t value)438 number_of_digits(uint32_t value)
439 {
440     int j;
441 
442     j = 1;
443     while (value > 9) {
444 	j++;
445 	value = value / 10;
446     }
447     return j;
448 }
449 
450 
451 //
452 // Print a message on standard error & flush the input.
453 //
454 void
bad_input(const char * fmt,...)455 bad_input(const char *fmt, ...)
456 {
457     va_list ap;
458 
459     va_start(ap, fmt);
460     vfprintf(stderr, fmt, ap);
461     va_end(ap);
462     fprintf(stderr, "\n");
463     flush_to_newline(1);
464 }
465