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 ptrdiff_t off; 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 off = s - ret_value; 353 free(ret_value); 354 s = limit + off; 355 ret_value = limit; 356 length += STRING_CHUNK; 357 limit = ret_value + length; 358 } 359 if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) { 360 *s++ = 0; 361 break; 362 } else if (c == '\n') { 363 *s++ = 0; 364 my_ungetch(c); 365 break; 366 } else { 367 *s++ = c; 368 } 369 } 370 return(ret_value); 371 } 372 373 374 uint32_t 375 get_multiplier(long divisor) 376 { 377 int c; 378 uint32_t result; 379 uint32_t extra; 380 381 c = my_getch(); 382 383 extra = 1; 384 if (c <= 0 || divisor <= 0) { 385 result = 0; 386 } else if (c == 't' || c == 'T') { 387 result = 1024*1024; 388 extra = 1024*1024; 389 } else if (c == 'g' || c == 'G') { 390 result = 1024*1024*1024; 391 } else if (c == 'm' || c == 'M') { 392 result = 1024*1024; 393 } else if (c == 'k' || c == 'K') { 394 result = 1024; 395 } else { 396 my_ungetch(c); 397 result = 1; 398 } 399 if (result > 1) { 400 if (extra > 1) { 401 result /= divisor; 402 if (result >= 4096) { 403 /* overflow -> 20bits + >12bits */ 404 result = 0; 405 } else { 406 result *= extra; 407 } 408 } else if ((long long)result >= divisor) { 409 result /= divisor; 410 } else { 411 result = 1; 412 } 413 } 414 return result; 415 } 416 417 418 int 419 get_partition_modifier(void) 420 { 421 int c; 422 int result; 423 424 result = 0; 425 426 c = my_getch(); 427 428 if (c == 'p' || c == 'P') { 429 result = 1; 430 } else if (c > 0) { 431 my_ungetch(c); 432 } 433 return result; 434 } 435 436 437 int 438 number_of_digits(uint32_t value) 439 { 440 int j; 441 442 j = 1; 443 while (value > 9) { 444 j++; 445 value = value / 10; 446 } 447 return j; 448 } 449 450 451 // 452 // Print a message on standard error & flush the input. 453 // 454 void 455 bad_input(const char *fmt, ...) 456 { 457 va_list ap; 458 459 va_start(ap, fmt); 460 vfprintf(stderr, fmt, ap); 461 va_end(ap); 462 fprintf(stderr, "\n"); 463 flush_to_newline(1); 464 } 465