io.c revision 1.3
1// 2// io.c - simple io and input parsing routines 3// 4// Written by Eryk Vershen (eryk@apple.com) 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__) && !defined(__unix__) || defined(__OpenBSD__) 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(); 93void my_ungetch(int c); 94 95 96// 97// Routines 98// 99int 100my_getch() 101{ 102 if (unget_count > 0) { 103 return (unget_buf[--unget_count]); 104 } else { 105 return (getc(stdin)); 106 } 107} 108 109 110void 111my_ungetch(int c) 112{ 113 // In practice there is never more than one character in 114 // the unget_buf, but what's a little overkill among friends? 115 116 if (unget_count < UNGET_MAX_COUNT) { 117 unget_buf[unget_count++] = c; 118 } else { 119 fatal(-1, "Programmer error in my_ungetch()."); 120 } 121} 122 123 124void 125flush_to_newline(int keep_newline) 126{ 127 int c; 128 129 for (;;) { 130 c = my_getch(); 131 132 if (c <= 0) { 133 break; 134 } else if (c == '\n') { 135 if (keep_newline) { 136 my_ungetch(c); 137 } 138 break; 139 } else { 140 // skip 141 } 142 } 143 return; 144} 145 146 147int 148get_okay(char *prompt, int default_value) 149{ 150 int c; 151 152 flush_to_newline(0); 153 printf(prompt); 154 155 for (;;) { 156 c = my_getch(); 157 158 if (c <= 0) { 159 break; 160 } else if (c == ' ' || c == '\t') { 161 // skip blanks and tabs 162 } else if (c == '\n') { 163 my_ungetch(c); 164 return default_value; 165 } else if (c == 'y' || c == 'Y') { 166 return 1; 167 } else if (c == 'n' || c == 'N') { 168 return 0; 169 } else { 170 flush_to_newline(0); 171 printf(prompt); 172 } 173 } 174 return -1; 175} 176 177 178int 179get_command(char *prompt, int promptBeforeGet, int *command) 180{ 181 int c; 182 183 if (promptBeforeGet) { 184 printf(prompt); 185 } 186 for (;;) { 187 c = my_getch(); 188 189 if (c <= 0) { 190 break; 191 } else if (c == ' ' || c == '\t') { 192 // skip blanks and tabs 193 } else if (c == '\n') { 194 printf(prompt); 195 } else { 196 *command = c; 197 return 1; 198 } 199 } 200 return 0; 201} 202 203 204int 205get_number_argument(char *prompt, long *number, long default_value) 206{ 207 int c; 208 int result = 0; 209 210 for (;;) { 211 c = my_getch(); 212 213 if (c <= 0) { 214 break; 215 } else if (c == ' ' || c == '\t') { 216 // skip blanks and tabs 217 } else if (c == '\n') { 218 if (default_value == kDefault) { 219 printf(prompt); 220 } else { 221 my_ungetch(c); 222 *number = default_value; 223 result = 1; 224 break; 225 } 226 } else if ('0' <= c && c <= '9') { 227 *number = get_number(c); 228 result = 1; 229 break; 230 } else { 231 my_ungetch(c); 232 *number = 0; 233 break; 234 } 235 } 236 return result; 237} 238 239 240long 241get_number(int first_char) 242{ 243 int c; 244 int base; 245 int digit; 246 int ret_value; 247 248 if (first_char != '0') { 249 c = first_char; 250 base = 10; 251 digit = BAD_DIGIT; 252 } else if ((c=my_getch()) == 'x' || c == 'X') { 253 c = my_getch(); 254 base = 16; 255 digit = BAD_DIGIT; 256 } else { 257 my_ungetch(c); 258 c = first_char; 259 base = 8; 260 digit = 0; 261 } 262 ret_value = 0; 263 for (ret_value = 0; ; c = my_getch()) { 264 if (c >= '0' && c <= '9') { 265 digit = c - '0'; 266 } else if (c >='A' && c <= 'F') { 267 digit = 10 + (c - 'A'); 268 } else if (c >='a' && c <= 'f') { 269 digit = 10 + (c - 'a'); 270 } else { 271 digit = BAD_DIGIT; 272 } 273 if (digit >= base) { 274 break; 275 } 276 ret_value = ret_value * base + digit; 277 } 278 my_ungetch(c); 279 return(ret_value); 280} 281 282 283int 284get_string_argument(char *prompt, char **string, int reprompt) 285{ 286 int c; 287 int result = 0; 288 289 for (;;) { 290 c = my_getch(); 291 292 if (c <= 0) { 293 break; 294 } else if (c == ' ' || c == '\t') { 295 // skip blanks and tabs 296 } else if (c == '\n') { 297 if (reprompt) { 298 printf(prompt); 299 } else { 300 my_ungetch(c); 301 *string = NULL; 302 break; 303 } 304 } else if (c == '"' || c == '\'') { 305 *string = get_string(c); 306 result = 1; 307 break; 308 } else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') 309 || (c == '-' || c == '/' || c == '.' || c == ':')) { 310 my_ungetch(c); 311 *string = get_string(' '); 312 result = 1; 313 break; 314 } else { 315 my_ungetch(c); 316 *string = NULL; 317 break; 318 } 319 } 320 return result; 321} 322 323 324char * 325get_string(int eos) 326{ 327 int c; 328 char *s; 329 char *ret_value; 330 char *limit; 331 int length; 332 333 ret_value = (char *) malloc(STRING_CHUNK); 334 if (ret_value == NULL) { 335 error(errno, "can't allocate memory for string buffer"); 336 return NULL; 337 } 338 length = STRING_CHUNK; 339 limit = ret_value + length; 340 341 c = my_getch(); 342 for (s = ret_value; ; c = my_getch()) { 343 if (s >= limit) { 344 // expand string 345 limit = (char *) malloc(length+STRING_CHUNK); 346 if (limit == NULL) { 347 error(errno, "can't allocate memory for string buffer"); 348 ret_value[length-1] = 0; 349 break; 350 } 351 strncpy(limit, ret_value, length); 352 free(ret_value); 353 s = limit + (s - ret_value); 354 ret_value = limit; 355 length += STRING_CHUNK; 356 limit = ret_value + length; 357 } 358 if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) { 359 *s++ = 0; 360 break; 361 } else if (c == '\n') { 362 *s++ = 0; 363 my_ungetch(c); 364 break; 365 } else { 366 *s++ = c; 367 } 368 } 369 return(ret_value); 370} 371 372 373unsigned long 374get_multiplier(long divisor) 375{ 376 int c; 377 unsigned long result; 378 unsigned long extra; 379 380 c = my_getch(); 381 382 extra = 1; 383 if (c <= 0 || divisor <= 0) { 384 result = 0; 385 } else if (c == 't' || c == 'T') { 386 result = 1024*1024; 387 extra = 1024*1024; 388 } else if (c == 'g' || c == 'G') { 389 result = 1024*1024*1024; 390 } else if (c == 'm' || c == 'M') { 391 result = 1024*1024; 392 } else if (c == 'k' || c == 'K') { 393 result = 1024; 394 } else { 395 my_ungetch(c); 396 result = 1; 397 } 398 if (result > 1) { 399 if (extra > 1) { 400 result /= divisor; 401 if (result >= 4096) { 402 /* overflow -> 20bits + >12bits */ 403 result = 0; 404 } else { 405 result *= extra; 406 } 407 } else if (result >= divisor) { 408 result /= divisor; 409 } else { 410 result = 1; 411 } 412 } 413 return result; 414} 415 416 417int 418get_partition_modifier(void) 419{ 420 int c; 421 int result; 422 423 result = 0; 424 425 c = my_getch(); 426 427 if (c == 'p' || c == 'P') { 428 result = 1; 429 } else if (c > 0) { 430 my_ungetch(c); 431 } 432 return result; 433} 434 435 436int 437number_of_digits(unsigned long value) 438{ 439 int j; 440 441 j = 1; 442 while (value > 9) { 443 j++; 444 value = value / 10; 445 } 446 return j; 447} 448 449 450// 451// Print a message on standard error & flush the input. 452// 453void 454bad_input(char *fmt, ...) 455{ 456 va_list ap; 457 458 va_start(ap, fmt); 459 vfprintf(stderr, fmt, ap); 460 va_end(ap); 461 fprintf(stderr, "\n"); 462 flush_to_newline(1); 463} 464