// // io.c - simple io and input parsing routines // // Written by Eryk Vershen // /* * Copyright 1996,1997,1998 by Apple Computer, Inc. * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies and * that both the copyright notice and this permission notice appear in * supporting documentation. * * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ // for *printf() #include <stdio.h> // for malloc() & free() #include <stdlib.h> // for strncpy() #include <string.h> // for va_start(), etc. #include <stdarg.h> // for errno #include <errno.h> #include "io.h" #include "errors.h" // // Defines // #define BAD_DIGIT 17 /* must be greater than any base */ #define STRING_CHUNK 16 #define UNGET_MAX_COUNT 10 #define loff_t long #define llseek lseek // // Types // // // Global Constants // const long kDefault = -1; // // Global Variables // short unget_buf[UNGET_MAX_COUNT+1]; int unget_count; char io_buffer[MAXIOSIZE]; // // Forward declarations // long get_number(int first_char); char* get_string(int eos); int my_getch(void); void my_ungetch(int c); // // Routines // int my_getch() { if (unget_count > 0) { return (unget_buf[--unget_count]); } else { return (getc(stdin)); } } void my_ungetch(int c) { // In practice there is never more than one character in // the unget_buf, but what's a little overkill among friends? if (unget_count < UNGET_MAX_COUNT) { unget_buf[unget_count++] = c; } else { fatal(-1, "Programmer error in my_ungetch()."); } } void flush_to_newline(int keep_newline) { int c; for (;;) { c = my_getch(); if (c <= 0) { break; } else if (c == '\n') { if (keep_newline) { my_ungetch(c); } break; } else { // skip } } return; } int get_okay(const char *prompt, int default_value) { int c; flush_to_newline(0); printf(prompt); for (;;) { c = my_getch(); if (c <= 0) { break; } else if (c == ' ' || c == '\t') { // skip blanks and tabs } else if (c == '\n') { my_ungetch(c); return default_value; } else if (c == 'y' || c == 'Y') { return 1; } else if (c == 'n' || c == 'N') { return 0; } else { flush_to_newline(0); printf(prompt); } } return -1; } int get_command(const char *prompt, int promptBeforeGet, int *command) { int c; if (promptBeforeGet) { printf(prompt); } for (;;) { c = my_getch(); if (c <= 0) { break; } else if (c == ' ' || c == '\t') { // skip blanks and tabs } else if (c == '\n') { printf(prompt); } else { *command = c; return 1; } } return 0; } int get_number_argument(const char *prompt, long *number, long default_value) { int c; int result = 0; for (;;) { c = my_getch(); if (c <= 0) { break; } else if (c == ' ' || c == '\t') { // skip blanks and tabs } else if (c == '\n') { if (default_value == kDefault) { printf(prompt); } else { my_ungetch(c); *number = default_value; result = 1; break; } } else if ('0' <= c && c <= '9') { *number = get_number(c); result = 1; break; } else { my_ungetch(c); *number = 0; break; } } return result; } long get_number(int first_char) { int c; int base; int digit; int ret_value; if (first_char != '0') { c = first_char; base = 10; digit = BAD_DIGIT; } else if ((c=my_getch()) == 'x' || c == 'X') { c = my_getch(); base = 16; digit = BAD_DIGIT; } else { my_ungetch(c); c = first_char; base = 8; digit = 0; } ret_value = 0; for (ret_value = 0; ; c = my_getch()) { if (c >= '0' && c <= '9') { digit = c - '0'; } else if (c >='A' && c <= 'F') { digit = 10 + (c - 'A'); } else if (c >='a' && c <= 'f') { digit = 10 + (c - 'a'); } else { digit = BAD_DIGIT; } if (digit >= base) { break; } ret_value = ret_value * base + digit; } my_ungetch(c); return(ret_value); } int get_string_argument(const char *prompt, char **string, int reprompt) { int c; int result = 0; for (;;) { c = my_getch(); if (c <= 0) { break; } else if (c == ' ' || c == '\t') { // skip blanks and tabs } else if (c == '\n') { if (reprompt) { printf(prompt); } else { my_ungetch(c); *string = NULL; break; } } else if (c == '"' || c == '\'') { *string = get_string(c); result = 1; break; } else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || (c == '-' || c == '/' || c == '.' || c == ':')) { my_ungetch(c); *string = get_string(' '); result = 1; break; } else { my_ungetch(c); *string = NULL; break; } } return result; } char * get_string(int eos) { int c; char *s; char *ret_value; char *limit; int length; ret_value = (char *) malloc(STRING_CHUNK); if (ret_value == NULL) { error(errno, "can't allocate memory for string buffer"); return NULL; } length = STRING_CHUNK; limit = ret_value + length; c = my_getch(); for (s = ret_value; ; c = my_getch()) { if (s >= limit) { // expand string limit = (char *) malloc(length+STRING_CHUNK); if (limit == NULL) { error(errno, "can't allocate memory for string buffer"); ret_value[length-1] = 0; break; } strncpy(limit, ret_value, length); free(ret_value); s = limit + (s - ret_value); ret_value = limit; length += STRING_CHUNK; limit = ret_value + length; } if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) { *s++ = 0; break; } else if (c == '\n') { *s++ = 0; my_ungetch(c); break; } else { *s++ = c; } } return(ret_value); } unsigned long get_multiplier(long divisor) { int c; unsigned long result; unsigned long extra; c = my_getch(); extra = 1; if (c <= 0 || divisor <= 0) { result = 0; } else if (c == 't' || c == 'T') { result = 1024*1024; extra = 1024*1024; } else if (c == 'g' || c == 'G') { result = 1024*1024*1024; } else if (c == 'm' || c == 'M') { result = 1024*1024; } else if (c == 'k' || c == 'K') { result = 1024; } else { my_ungetch(c); result = 1; } if (result > 1) { if (extra > 1) { result /= divisor; if (result >= 4096) { /* overflow -> 20bits + >12bits */ result = 0; } else { result *= extra; } } else if (result >= divisor) { result /= divisor; } else { result = 1; } } return result; } int get_partition_modifier(void) { int c; int result; result = 0; c = my_getch(); if (c == 'p' || c == 'P') { result = 1; } else if (c > 0) { my_ungetch(c); } return result; } int number_of_digits(unsigned long value) { int j; j = 1; while (value > 9) { j++; value = value / 10; } return j; } // // Print a message on standard error & flush the input. // void bad_input(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); flush_to_newline(1); }