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// 76const long kDefault = -1; 77 78 79// 80// Global Variables 81// 82short unget_buf[UNGET_MAX_COUNT+1]; 83int unget_count; 84char io_buffer[MAXIOSIZE]; 85 86 87// 88// Forward declarations 89// 90long get_number(int first_char); 91char* get_string(int eos); 92int my_getch(void); 93void my_ungetch(int c); 94 95// 96// Routines 97// 98int 99my_getch() 100{ 101 if (unget_count > 0) { 102 return (unget_buf[--unget_count]); 103 } else { 104 return (getc(stdin)); 105 } 106} 107 108 109void 110my_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 123void 124flush_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 146int 147get_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 177int 178get_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 203int 204get_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 239long 240get_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 282int 283get_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 323char * 324get_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 372unsigned long 373get_multiplier(long divisor) 374{ 375 int c; 376 unsigned long result; 377 unsigned long 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 416int 417get_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 435int 436number_of_digits(unsigned long 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// 452void 453bad_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