xref: /netbsd-src/external/bsd/pdisk/dist/io.c (revision 81a719df6ea00ae13b21ce821a407eaf4d42dee6)
19428323dSchristos //
29428323dSchristos // io.c - simple io and input parsing routines
39428323dSchristos //
49428323dSchristos // Written by Eryk Vershen
59428323dSchristos //
69428323dSchristos 
79428323dSchristos /*
89428323dSchristos  * Copyright 1996,1997,1998 by Apple Computer, Inc.
99428323dSchristos  *              All Rights Reserved
109428323dSchristos  *
119428323dSchristos  * Permission to use, copy, modify, and distribute this software and
129428323dSchristos  * its documentation for any purpose and without fee is hereby granted,
139428323dSchristos  * provided that the above copyright notice appears in all copies and
149428323dSchristos  * that both the copyright notice and this permission notice appear in
159428323dSchristos  * supporting documentation.
169428323dSchristos  *
179428323dSchristos  * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
189428323dSchristos  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
199428323dSchristos  * FOR A PARTICULAR PURPOSE.
209428323dSchristos  *
219428323dSchristos  * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
229428323dSchristos  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
239428323dSchristos  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
249428323dSchristos  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
259428323dSchristos  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
269428323dSchristos  */
279428323dSchristos 
289428323dSchristos // for *printf()
299428323dSchristos #include <stdio.h>
309428323dSchristos 
319428323dSchristos // for malloc() & free()
329428323dSchristos #if !defined(__linux__)
339428323dSchristos #include <stdlib.h>
349428323dSchristos #else
359428323dSchristos #include <malloc.h>
369428323dSchristos #endif
379428323dSchristos // for strncpy()
389428323dSchristos #include <string.h>
399428323dSchristos // for va_start(), etc.
409428323dSchristos #include <stdarg.h>
419428323dSchristos // for errno
429428323dSchristos #include <errno.h>
439428323dSchristos 
449428323dSchristos #include "io.h"
459428323dSchristos #include "errors.h"
469428323dSchristos 
479428323dSchristos 
489428323dSchristos //
499428323dSchristos // Defines
509428323dSchristos //
519428323dSchristos #define BAD_DIGIT 17	/* must be greater than any base */
529428323dSchristos #define	STRING_CHUNK	16
539428323dSchristos #define UNGET_MAX_COUNT 10
549428323dSchristos #ifndef __linux__
559428323dSchristos #ifndef __unix__
569428323dSchristos #define SCSI_FD 8
579428323dSchristos #endif
589428323dSchristos #ifdef NeXT
599428323dSchristos #define loff_t off_t
609428323dSchristos #define llseek lseek
619428323dSchristos #else
629428323dSchristos #define loff_t long
639428323dSchristos #define llseek lseek
649428323dSchristos #endif
659428323dSchristos #endif
669428323dSchristos 
679428323dSchristos 
689428323dSchristos //
699428323dSchristos // Types
709428323dSchristos //
719428323dSchristos 
729428323dSchristos 
739428323dSchristos //
749428323dSchristos // Global Constants
759428323dSchristos //
769428323dSchristos const long kDefault = -1;
779428323dSchristos 
789428323dSchristos 
799428323dSchristos //
809428323dSchristos // Global Variables
819428323dSchristos //
829428323dSchristos short unget_buf[UNGET_MAX_COUNT+1];
839428323dSchristos int unget_count;
849428323dSchristos char io_buffer[MAXIOSIZE];
859428323dSchristos 
869428323dSchristos 
879428323dSchristos //
889428323dSchristos // Forward declarations
899428323dSchristos //
909428323dSchristos long get_number(int first_char);
919428323dSchristos char* get_string(int eos);
9248a628aeSchristos int my_getch(void);
939428323dSchristos void my_ungetch(int c);
949428323dSchristos 
959428323dSchristos //
969428323dSchristos // Routines
979428323dSchristos //
989428323dSchristos int
my_getch(void)9948a628aeSchristos my_getch(void)
1009428323dSchristos {
1019428323dSchristos     if (unget_count > 0) {
1029428323dSchristos 	return (unget_buf[--unget_count]);
1039428323dSchristos     } else {
1049428323dSchristos 	return (getc(stdin));
1059428323dSchristos     }
1069428323dSchristos }
1079428323dSchristos 
1089428323dSchristos 
1099428323dSchristos void
my_ungetch(int c)1109428323dSchristos my_ungetch(int c)
1119428323dSchristos {
1129428323dSchristos     // In practice there is never more than one character in
1139428323dSchristos     // the unget_buf, but what's a little overkill among friends?
1149428323dSchristos 
1159428323dSchristos     if (unget_count < UNGET_MAX_COUNT) {
1169428323dSchristos 	unget_buf[unget_count++] = c;
1179428323dSchristos     } else {
1189428323dSchristos 	fatal(-1, "Programmer error in my_ungetch().");
1199428323dSchristos     }
1209428323dSchristos }
1219428323dSchristos 
1229428323dSchristos 
1239428323dSchristos void
flush_to_newline(int keep_newline)1249428323dSchristos flush_to_newline(int keep_newline)
1259428323dSchristos {
1269428323dSchristos     int		c;
1279428323dSchristos 
1289428323dSchristos     for (;;) {
1299428323dSchristos 	c = my_getch();
1309428323dSchristos 
1319428323dSchristos 	if (c <= 0) {
1329428323dSchristos 	    break;
1339428323dSchristos 	} else if (c == '\n') {
1349428323dSchristos 	    if (keep_newline) {
1359428323dSchristos 		my_ungetch(c);
1369428323dSchristos 	    }
1379428323dSchristos 	    break;
1389428323dSchristos 	} else {
1399428323dSchristos 	    // skip
1409428323dSchristos 	}
1419428323dSchristos     }
1429428323dSchristos     return;
1439428323dSchristos }
1449428323dSchristos 
1459428323dSchristos 
1469428323dSchristos int
get_okay(const char * prompt,int default_value)14748a628aeSchristos get_okay(const char *prompt, int default_value)
1489428323dSchristos {
1499428323dSchristos     int		c;
1509428323dSchristos 
1519428323dSchristos     flush_to_newline(0);
15248a628aeSchristos     printf("%s", prompt);
1539428323dSchristos 
1549428323dSchristos     for (;;) {
1559428323dSchristos 	c = my_getch();
1569428323dSchristos 
1579428323dSchristos 	if (c <= 0) {
1589428323dSchristos 	    break;
1599428323dSchristos 	} else if (c == ' ' || c == '\t') {
1609428323dSchristos 	    // skip blanks and tabs
1619428323dSchristos 	} else if (c == '\n') {
1629428323dSchristos 	    my_ungetch(c);
1639428323dSchristos 	    return default_value;
1649428323dSchristos 	} else if (c == 'y' || c == 'Y') {
1659428323dSchristos 	    return 1;
1669428323dSchristos 	} else if (c == 'n' || c == 'N') {
1679428323dSchristos 	    return 0;
1689428323dSchristos 	} else {
1699428323dSchristos 	    flush_to_newline(0);
17048a628aeSchristos 	    printf("%s", prompt);
1719428323dSchristos 	}
1729428323dSchristos     }
1739428323dSchristos     return -1;
1749428323dSchristos }
1759428323dSchristos 
1769428323dSchristos 
1779428323dSchristos int
get_command(const char * prompt,int promptBeforeGet,int * command)17848a628aeSchristos get_command(const char *prompt, int promptBeforeGet, int *command)
1799428323dSchristos {
1809428323dSchristos     int		c;
1819428323dSchristos 
1829428323dSchristos     if (promptBeforeGet) {
18348a628aeSchristos 	printf("%s", prompt);
1849428323dSchristos     }
1859428323dSchristos     for (;;) {
1869428323dSchristos 	c = my_getch();
1879428323dSchristos 
1889428323dSchristos 	if (c <= 0) {
1899428323dSchristos 	    break;
1909428323dSchristos 	} else if (c == ' ' || c == '\t') {
1919428323dSchristos 	    // skip blanks and tabs
1929428323dSchristos 	} else if (c == '\n') {
19348a628aeSchristos 	    printf("%s", prompt);
1949428323dSchristos 	} else {
1959428323dSchristos 	    *command = c;
1969428323dSchristos 	    return 1;
1979428323dSchristos 	}
1989428323dSchristos     }
1999428323dSchristos     return 0;
2009428323dSchristos }
2019428323dSchristos 
2029428323dSchristos 
2039428323dSchristos int
get_number_argument(const char * prompt,long * number,long default_value)20448a628aeSchristos get_number_argument(const char *prompt, long *number, long default_value)
2059428323dSchristos {
2069428323dSchristos     int c;
2079428323dSchristos     int result = 0;
2089428323dSchristos 
2099428323dSchristos     for (;;) {
2109428323dSchristos 	c = my_getch();
2119428323dSchristos 
2129428323dSchristos 	if (c <= 0) {
2139428323dSchristos 	    break;
2149428323dSchristos 	} else if (c == ' ' || c == '\t') {
2159428323dSchristos 	    // skip blanks and tabs
2169428323dSchristos 	} else if (c == '\n') {
2179428323dSchristos 	    if (default_value == kDefault) {
21848a628aeSchristos 		printf("%s", prompt);
2199428323dSchristos 	    } else {
2209428323dSchristos 		my_ungetch(c);
2219428323dSchristos 		*number = default_value;
2229428323dSchristos 		result = 1;
2239428323dSchristos 		break;
2249428323dSchristos 	    }
2259428323dSchristos 	} else if ('0' <= c && c <= '9') {
2269428323dSchristos 	    *number = get_number(c);
2279428323dSchristos 	    result = 1;
2289428323dSchristos 	    break;
2299428323dSchristos 	} else {
2309428323dSchristos 	    my_ungetch(c);
2319428323dSchristos 	    *number = 0;
2329428323dSchristos 	    break;
2339428323dSchristos 	}
2349428323dSchristos     }
2359428323dSchristos     return result;
2369428323dSchristos }
2379428323dSchristos 
2389428323dSchristos 
2399428323dSchristos long
get_number(int first_char)2409428323dSchristos get_number(int first_char)
2419428323dSchristos {
2429428323dSchristos     register int c;
2439428323dSchristos     int base;
2449428323dSchristos     int digit;
2459428323dSchristos     int ret_value;
2469428323dSchristos 
2479428323dSchristos     if (first_char != '0') {
2489428323dSchristos 	c = first_char;
2499428323dSchristos 	base = 10;
2509428323dSchristos 	digit = BAD_DIGIT;
2519428323dSchristos     } else if ((c=my_getch()) == 'x' || c == 'X') {
2529428323dSchristos 	c = my_getch();
2539428323dSchristos 	base = 16;
2549428323dSchristos 	digit = BAD_DIGIT;
2559428323dSchristos     } else {
2569428323dSchristos 	my_ungetch(c);
2579428323dSchristos 	c = first_char;
2589428323dSchristos 	base = 8;
2599428323dSchristos 	digit = 0;
2609428323dSchristos     }
2619428323dSchristos     ret_value = 0;
2629428323dSchristos     for (ret_value = 0; ; c = my_getch()) {
2639428323dSchristos 	if (c >= '0' && c <= '9') {
2649428323dSchristos 	    digit = c - '0';
2659428323dSchristos 	} else if (c >='A' && c <= 'F') {
2669428323dSchristos 	    digit = 10 + (c - 'A');
2679428323dSchristos 	} else if (c >='a' && c <= 'f') {
2689428323dSchristos 	    digit = 10 + (c - 'a');
2699428323dSchristos 	} else {
2709428323dSchristos 	    digit = BAD_DIGIT;
2719428323dSchristos 	}
2729428323dSchristos 	if (digit >= base) {
2739428323dSchristos 	    break;
2749428323dSchristos 	}
2759428323dSchristos 	ret_value = ret_value * base + digit;
2769428323dSchristos     }
2779428323dSchristos     my_ungetch(c);
2789428323dSchristos     return(ret_value);
2799428323dSchristos }
2809428323dSchristos 
2819428323dSchristos 
2829428323dSchristos int
get_string_argument(const char * prompt,char ** string,int reprompt)28348a628aeSchristos get_string_argument(const char *prompt, char **string, int reprompt)
2849428323dSchristos {
2859428323dSchristos     int c;
2869428323dSchristos     int result = 0;
2879428323dSchristos 
2889428323dSchristos     for (;;) {
2899428323dSchristos 	c = my_getch();
2909428323dSchristos 
2919428323dSchristos 	if (c <= 0) {
2929428323dSchristos 	    break;
2939428323dSchristos 	} else if (c == ' ' || c == '\t') {
2949428323dSchristos 	    // skip blanks and tabs
2959428323dSchristos 	} else if (c == '\n') {
2969428323dSchristos 	    if (reprompt) {
29748a628aeSchristos 		printf("%s", prompt);
2989428323dSchristos 	    } else {
2999428323dSchristos 		my_ungetch(c);
3009428323dSchristos 		*string = NULL;
3019428323dSchristos 		break;
3029428323dSchristos 	    }
3039428323dSchristos 	} else if (c == '"' || c == '\'') {
3049428323dSchristos 	    *string = get_string(c);
3059428323dSchristos 	    result = 1;
3069428323dSchristos 	    break;
3079428323dSchristos 	} else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
3089428323dSchristos 		|| (c == '-' || c == '/' || c == '.' || c == ':')) {
3099428323dSchristos 	    my_ungetch(c);
3109428323dSchristos 	    *string = get_string(' ');
3119428323dSchristos 	    result = 1;
3129428323dSchristos 	    break;
3139428323dSchristos 	} else {
3149428323dSchristos 	    my_ungetch(c);
3159428323dSchristos 	    *string = NULL;
3169428323dSchristos 	    break;
3179428323dSchristos 	}
3189428323dSchristos     }
3199428323dSchristos     return result;
3209428323dSchristos }
3219428323dSchristos 
3229428323dSchristos 
3239428323dSchristos char *
get_string(int eos)3249428323dSchristos get_string(int eos)
3259428323dSchristos {
3269428323dSchristos     int c;
3279428323dSchristos     char *s;
3289428323dSchristos     char *ret_value;
3299428323dSchristos     char *limit;
3309428323dSchristos     int length;
331*81a719dfSmrg     ptrdiff_t off;
3329428323dSchristos 
3339428323dSchristos     ret_value = (char *) malloc(STRING_CHUNK);
3349428323dSchristos     if (ret_value == NULL) {
3359428323dSchristos 	error(errno, "can't allocate memory for string buffer");
3369428323dSchristos 	return NULL;
3379428323dSchristos     }
3389428323dSchristos     length = STRING_CHUNK;
3399428323dSchristos     limit = ret_value + length;
3409428323dSchristos 
3419428323dSchristos     c = my_getch();
3429428323dSchristos     for (s = ret_value; ; c = my_getch()) {
3439428323dSchristos 	if (s >= limit) {
3449428323dSchristos 	    // expand string
3459428323dSchristos 	    limit = (char *) malloc(length+STRING_CHUNK);
3469428323dSchristos 	    if (limit == NULL) {
3479428323dSchristos 		error(errno, "can't allocate memory for string buffer");
3489428323dSchristos 		ret_value[length-1] = 0;
3499428323dSchristos 		break;
3509428323dSchristos 	    }
3519428323dSchristos 	    strncpy(limit, ret_value, length);
352*81a719dfSmrg 	    off = s - ret_value;
3539428323dSchristos 	    free(ret_value);
354*81a719dfSmrg 	    s = limit + off;
3559428323dSchristos 	    ret_value = limit;
3569428323dSchristos 	    length += STRING_CHUNK;
3579428323dSchristos 	    limit = ret_value + length;
3589428323dSchristos 	}
3599428323dSchristos 	if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) {
3609428323dSchristos 	    *s++ = 0;
3619428323dSchristos 	    break;
3629428323dSchristos 	} else if (c == '\n') {
3639428323dSchristos 	    *s++ = 0;
3649428323dSchristos 	    my_ungetch(c);
3659428323dSchristos 	    break;
3669428323dSchristos 	} else {
3679428323dSchristos 	    *s++ = c;
3689428323dSchristos 	}
3699428323dSchristos     }
3709428323dSchristos     return(ret_value);
3719428323dSchristos }
3729428323dSchristos 
3739428323dSchristos 
37448a628aeSchristos uint32_t
get_multiplier(long divisor)3759428323dSchristos get_multiplier(long divisor)
3769428323dSchristos {
3779428323dSchristos     int c;
37848a628aeSchristos     uint32_t result;
37948a628aeSchristos     uint32_t extra;
3809428323dSchristos 
3819428323dSchristos     c = my_getch();
3829428323dSchristos 
3839428323dSchristos     extra = 1;
3849428323dSchristos     if (c <= 0 || divisor <= 0) {
3859428323dSchristos 	result = 0;
3869428323dSchristos     } else if (c == 't' || c == 'T') {
3879428323dSchristos 	result = 1024*1024;
3889428323dSchristos 	extra = 1024*1024;
3899428323dSchristos     } else if (c == 'g' || c == 'G') {
3909428323dSchristos 	result = 1024*1024*1024;
3919428323dSchristos     } else if (c == 'm' || c == 'M') {
3929428323dSchristos 	result = 1024*1024;
3939428323dSchristos     } else if (c == 'k' || c == 'K') {
3949428323dSchristos 	result = 1024;
3959428323dSchristos     } else {
3969428323dSchristos 	my_ungetch(c);
3979428323dSchristos 	result = 1;
3989428323dSchristos     }
3999428323dSchristos     if (result > 1) {
4009428323dSchristos 	if (extra > 1) {
4019428323dSchristos 	    result /= divisor;
4029428323dSchristos 	    if (result >= 4096) {
4039428323dSchristos 		/* overflow -> 20bits + >12bits */
4049428323dSchristos 		result = 0;
4059428323dSchristos 	    } else {
4069428323dSchristos 		result *= extra;
4079428323dSchristos 	    }
40848a628aeSchristos 	} else if ((long long)result >= divisor) {
4099428323dSchristos 	    result /= divisor;
4109428323dSchristos 	} else {
4119428323dSchristos 	    result = 1;
4129428323dSchristos 	}
4139428323dSchristos     }
4149428323dSchristos     return result;
4159428323dSchristos }
4169428323dSchristos 
4179428323dSchristos 
4189428323dSchristos int
get_partition_modifier(void)4199428323dSchristos get_partition_modifier(void)
4209428323dSchristos {
4219428323dSchristos     int c;
4229428323dSchristos     int result;
4239428323dSchristos 
4249428323dSchristos     result = 0;
4259428323dSchristos 
4269428323dSchristos     c = my_getch();
4279428323dSchristos 
4289428323dSchristos     if (c == 'p' || c == 'P') {
4299428323dSchristos     	result = 1;
4309428323dSchristos     } else if (c > 0) {
4319428323dSchristos 	my_ungetch(c);
4329428323dSchristos     }
4339428323dSchristos     return result;
4349428323dSchristos }
4359428323dSchristos 
4369428323dSchristos 
4379428323dSchristos int
number_of_digits(uint32_t value)43848a628aeSchristos number_of_digits(uint32_t value)
4399428323dSchristos {
4409428323dSchristos     int j;
4419428323dSchristos 
4429428323dSchristos     j = 1;
4439428323dSchristos     while (value > 9) {
4449428323dSchristos 	j++;
4459428323dSchristos 	value = value / 10;
4469428323dSchristos     }
4479428323dSchristos     return j;
4489428323dSchristos }
4499428323dSchristos 
4509428323dSchristos 
4519428323dSchristos //
4529428323dSchristos // Print a message on standard error & flush the input.
4539428323dSchristos //
4549428323dSchristos void
bad_input(const char * fmt,...)45548a628aeSchristos bad_input(const char *fmt, ...)
4569428323dSchristos {
4579428323dSchristos     va_list ap;
4589428323dSchristos 
4599428323dSchristos     va_start(ap, fmt);
4609428323dSchristos     vfprintf(stderr, fmt, ap);
4619428323dSchristos     va_end(ap);
4629428323dSchristos     fprintf(stderr, "\n");
4639428323dSchristos     flush_to_newline(1);
4649428323dSchristos }
465