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