Home | History | Annotate | Line # | Download | only in dist
io.c revision 1.2.10.2
      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
     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
    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
    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
    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
    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
    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
    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
    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 *
    324 get_string(int eos)
    325 {
    326     int c;
    327     char *s;
    328     char *ret_value;
    329     char *limit;
    330     int length;
    331 
    332     ret_value = (char *) malloc(STRING_CHUNK);
    333     if (ret_value == NULL) {
    334 	error(errno, "can't allocate memory for string buffer");
    335 	return NULL;
    336     }
    337     length = STRING_CHUNK;
    338     limit = ret_value + length;
    339 
    340     c = my_getch();
    341     for (s = ret_value; ; c = my_getch()) {
    342 	if (s >= limit) {
    343 	    // expand string
    344 	    limit = (char *) malloc(length+STRING_CHUNK);
    345 	    if (limit == NULL) {
    346 		error(errno, "can't allocate memory for string buffer");
    347 		ret_value[length-1] = 0;
    348 		break;
    349 	    }
    350 	    strncpy(limit, ret_value, length);
    351 	    free(ret_value);
    352 	    s = limit + (s - ret_value);
    353 	    ret_value = limit;
    354 	    length += STRING_CHUNK;
    355 	    limit = ret_value + length;
    356 	}
    357 	if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) {
    358 	    *s++ = 0;
    359 	    break;
    360 	} else if (c == '\n') {
    361 	    *s++ = 0;
    362 	    my_ungetch(c);
    363 	    break;
    364 	} else {
    365 	    *s++ = c;
    366 	}
    367     }
    368     return(ret_value);
    369 }
    370 
    371 
    372 uint32_t
    373 get_multiplier(long divisor)
    374 {
    375     int c;
    376     uint32_t result;
    377     uint32_t extra;
    378 
    379     c = my_getch();
    380 
    381     extra = 1;
    382     if (c <= 0 || divisor <= 0) {
    383 	result = 0;
    384     } else if (c == 't' || c == 'T') {
    385 	result = 1024*1024;
    386 	extra = 1024*1024;
    387     } else if (c == 'g' || c == 'G') {
    388 	result = 1024*1024*1024;
    389     } else if (c == 'm' || c == 'M') {
    390 	result = 1024*1024;
    391     } else if (c == 'k' || c == 'K') {
    392 	result = 1024;
    393     } else {
    394 	my_ungetch(c);
    395 	result = 1;
    396     }
    397     if (result > 1) {
    398 	if (extra > 1) {
    399 	    result /= divisor;
    400 	    if (result >= 4096) {
    401 		/* overflow -> 20bits + >12bits */
    402 		result = 0;
    403 	    } else {
    404 		result *= extra;
    405 	    }
    406 	} else if ((long long)result >= divisor) {
    407 	    result /= divisor;
    408 	} else {
    409 	    result = 1;
    410 	}
    411     }
    412     return result;
    413 }
    414 
    415 
    416 int
    417 get_partition_modifier(void)
    418 {
    419     int c;
    420     int result;
    421 
    422     result = 0;
    423 
    424     c = my_getch();
    425 
    426     if (c == 'p' || c == 'P') {
    427     	result = 1;
    428     } else if (c > 0) {
    429 	my_ungetch(c);
    430     }
    431     return result;
    432 }
    433 
    434 
    435 int
    436 number_of_digits(uint32_t value)
    437 {
    438     int j;
    439 
    440     j = 1;
    441     while (value > 9) {
    442 	j++;
    443 	value = value / 10;
    444     }
    445     return j;
    446 }
    447 
    448 
    449 //
    450 // Print a message on standard error & flush the input.
    451 //
    452 void
    453 bad_input(const char *fmt, ...)
    454 {
    455     va_list ap;
    456 
    457     va_start(ap, fmt);
    458     vfprintf(stderr, fmt, ap);
    459     va_end(ap);
    460     fprintf(stderr, "\n");
    461     flush_to_newline(1);
    462 }
    463