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