1 /* $OpenBSD: io.c,v 1.10 2016/01/11 07:57:54 jasper Exp $ */ 2 3 // 4 // io.c - simple io and input parsing routines 5 // 6 // Written by Eryk Vershen 7 // 8 9 /* 10 * Copyright 1996,1997,1998 by Apple Computer, Inc. 11 * All Rights Reserved 12 * 13 * Permission to use, copy, modify, and distribute this software and 14 * its documentation for any purpose and without fee is hereby granted, 15 * provided that the above copyright notice appears in all copies and 16 * that both the copyright notice and this permission notice appear in 17 * supporting documentation. 18 * 19 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 20 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 * FOR A PARTICULAR PURPOSE. 22 * 23 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 24 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 25 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 26 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 27 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 28 */ 29 30 // for *printf() 31 #include <stdio.h> 32 33 // for malloc() & free() 34 #include <stdlib.h> 35 // for strncpy() 36 #include <string.h> 37 // for va_start(), etc. 38 #include <stdarg.h> 39 // for errno 40 #include <errno.h> 41 42 #include "io.h" 43 #include "errors.h" 44 45 46 // 47 // Defines 48 // 49 #define BAD_DIGIT 17 /* must be greater than any base */ 50 #define STRING_CHUNK 16 51 #define UNGET_MAX_COUNT 10 52 #define loff_t long 53 #define llseek lseek 54 55 56 // 57 // Types 58 // 59 60 61 // 62 // Global Constants 63 // 64 const long kDefault = -1; 65 66 67 // 68 // Global Variables 69 // 70 short unget_buf[UNGET_MAX_COUNT+1]; 71 int unget_count; 72 char io_buffer[MAXIOSIZE]; 73 74 75 // 76 // Forward declarations 77 // 78 long get_number(int first_char); 79 char* get_string(int eos); 80 int my_getch(void); 81 void my_ungetch(int c); 82 83 84 // 85 // Routines 86 // 87 int 88 my_getch() 89 { 90 if (unget_count > 0) { 91 return (unget_buf[--unget_count]); 92 } else { 93 return (getc(stdin)); 94 } 95 } 96 97 98 void 99 my_ungetch(int c) 100 { 101 // In practice there is never more than one character in 102 // the unget_buf, but what's a little overkill among friends? 103 104 if (unget_count < UNGET_MAX_COUNT) { 105 unget_buf[unget_count++] = c; 106 } else { 107 fatal(-1, "Programmer error in my_ungetch()."); 108 } 109 } 110 111 void 112 flush_to_newline(int keep_newline) 113 { 114 int c; 115 116 for (;;) { 117 c = my_getch(); 118 119 if (c <= 0) { 120 break; 121 } else if (c == '\n') { 122 if (keep_newline) { 123 my_ungetch(c); 124 } 125 break; 126 } else { 127 // skip 128 } 129 } 130 return; 131 } 132 133 134 int 135 get_okay(const char *prompt, int default_value) 136 { 137 int c; 138 139 flush_to_newline(0); 140 printf(prompt); 141 142 for (;;) { 143 c = my_getch(); 144 145 if (c <= 0) { 146 break; 147 } else if (c == ' ' || c == '\t') { 148 // skip blanks and tabs 149 } else if (c == '\n') { 150 my_ungetch(c); 151 return default_value; 152 } else if (c == 'y' || c == 'Y') { 153 return 1; 154 } else if (c == 'n' || c == 'N') { 155 return 0; 156 } else { 157 flush_to_newline(0); 158 printf(prompt); 159 } 160 } 161 return -1; 162 } 163 164 int 165 get_command(const char *prompt, int promptBeforeGet, int *command) 166 { 167 int c; 168 169 if (promptBeforeGet) { 170 printf(prompt); 171 } 172 for (;;) { 173 c = my_getch(); 174 175 if (c <= 0) { 176 break; 177 } else if (c == ' ' || c == '\t') { 178 // skip blanks and tabs 179 } else if (c == '\n') { 180 printf(prompt); 181 } else { 182 *command = c; 183 return 1; 184 } 185 } 186 return 0; 187 } 188 189 int 190 get_number_argument(const char *prompt, long *number, long default_value) 191 { 192 int c; 193 int result = 0; 194 195 for (;;) { 196 c = my_getch(); 197 198 if (c <= 0) { 199 break; 200 } else if (c == ' ' || c == '\t') { 201 // skip blanks and tabs 202 } else if (c == '\n') { 203 if (default_value == kDefault) { 204 printf(prompt); 205 } else { 206 my_ungetch(c); 207 *number = default_value; 208 result = 1; 209 break; 210 } 211 } else if ('0' <= c && c <= '9') { 212 *number = get_number(c); 213 result = 1; 214 break; 215 } else { 216 my_ungetch(c); 217 *number = 0; 218 break; 219 } 220 } 221 return result; 222 } 223 224 225 long 226 get_number(int first_char) 227 { 228 int c; 229 int base; 230 int digit; 231 int ret_value; 232 233 if (first_char != '0') { 234 c = first_char; 235 base = 10; 236 digit = BAD_DIGIT; 237 } else if ((c=my_getch()) == 'x' || c == 'X') { 238 c = my_getch(); 239 base = 16; 240 digit = BAD_DIGIT; 241 } else { 242 my_ungetch(c); 243 c = first_char; 244 base = 8; 245 digit = 0; 246 } 247 ret_value = 0; 248 for (ret_value = 0; ; c = my_getch()) { 249 if (c >= '0' && c <= '9') { 250 digit = c - '0'; 251 } else if (c >='A' && c <= 'F') { 252 digit = 10 + (c - 'A'); 253 } else if (c >='a' && c <= 'f') { 254 digit = 10 + (c - 'a'); 255 } else { 256 digit = BAD_DIGIT; 257 } 258 if (digit >= base) { 259 break; 260 } 261 ret_value = ret_value * base + digit; 262 } 263 my_ungetch(c); 264 return(ret_value); 265 } 266 267 int 268 get_string_argument(const char *prompt, char **string, int reprompt) 269 { 270 int c; 271 int result = 0; 272 273 for (;;) { 274 c = my_getch(); 275 276 if (c <= 0) { 277 break; 278 } else if (c == ' ' || c == '\t') { 279 // skip blanks and tabs 280 } else if (c == '\n') { 281 if (reprompt) { 282 printf(prompt); 283 } else { 284 my_ungetch(c); 285 *string = NULL; 286 break; 287 } 288 } else if (c == '"' || c == '\'') { 289 *string = get_string(c); 290 result = 1; 291 break; 292 } else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') 293 || (c == '-' || c == '/' || c == '.' || c == ':')) { 294 my_ungetch(c); 295 *string = get_string(' '); 296 result = 1; 297 break; 298 } else { 299 my_ungetch(c); 300 *string = NULL; 301 break; 302 } 303 } 304 return result; 305 } 306 307 308 char * 309 get_string(int eos) 310 { 311 int c; 312 char *s; 313 char *ret_value; 314 char *limit; 315 int length; 316 317 ret_value = malloc(STRING_CHUNK); 318 if (ret_value == NULL) { 319 error(errno, "can't allocate memory for string buffer"); 320 return NULL; 321 } 322 length = STRING_CHUNK; 323 limit = ret_value + length; 324 325 c = my_getch(); 326 for (s = ret_value; ; c = my_getch()) { 327 if (s >= limit) { 328 // expand string 329 limit = malloc(length+STRING_CHUNK); 330 if (limit == NULL) { 331 error(errno, "can't allocate memory for string buffer"); 332 ret_value[length-1] = 0; 333 break; 334 } 335 strncpy(limit, ret_value, length); 336 free(ret_value); 337 s = limit + (s - ret_value); 338 ret_value = limit; 339 length += STRING_CHUNK; 340 limit = ret_value + length; 341 } 342 if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) { 343 *s++ = 0; 344 break; 345 } else if (c == '\n') { 346 *s++ = 0; 347 my_ungetch(c); 348 break; 349 } else { 350 *s++ = c; 351 } 352 } 353 return(ret_value); 354 } 355 356 357 unsigned long 358 get_multiplier(long divisor) 359 { 360 int c; 361 unsigned long result; 362 unsigned long extra; 363 364 c = my_getch(); 365 366 extra = 1; 367 if (c <= 0 || divisor <= 0) { 368 result = 0; 369 } else if (c == 't' || c == 'T') { 370 result = 1024*1024; 371 extra = 1024*1024; 372 } else if (c == 'g' || c == 'G') { 373 result = 1024*1024*1024; 374 } else if (c == 'm' || c == 'M') { 375 result = 1024*1024; 376 } else if (c == 'k' || c == 'K') { 377 result = 1024; 378 } else { 379 my_ungetch(c); 380 result = 1; 381 } 382 if (result > 1) { 383 if (extra > 1) { 384 result /= divisor; 385 if (result >= 4096) { 386 /* overflow -> 20bits + >12bits */ 387 result = 0; 388 } else { 389 result *= extra; 390 } 391 } else if (result >= divisor) { 392 result /= divisor; 393 } else { 394 result = 1; 395 } 396 } 397 return result; 398 } 399 400 401 int 402 get_partition_modifier(void) 403 { 404 int c; 405 int result; 406 407 result = 0; 408 409 c = my_getch(); 410 411 if (c == 'p' || c == 'P') { 412 result = 1; 413 } else if (c > 0) { 414 my_ungetch(c); 415 } 416 return result; 417 } 418 419 420 int 421 number_of_digits(unsigned long value) 422 { 423 int j; 424 425 j = 1; 426 while (value > 9) { 427 j++; 428 value = value / 10; 429 } 430 return j; 431 } 432 433 434 // 435 // Print a message on standard error & flush the input. 436 // 437 void 438 bad_input(const char *fmt, ...) 439 { 440 va_list ap; 441 442 va_start(ap, fmt); 443 vfprintf(stderr, fmt, ap); 444 va_end(ap); 445 fprintf(stderr, "\n"); 446 flush_to_newline(1); 447 } 448