io.c revision 1.25
1/* $OpenBSD: io.c,v 1.25 2016/01/27 00:03:52 krw 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#include <err.h> 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34#include <stdarg.h> 35 36#include "dpme.h" 37#include "io.h" 38 39#define BAD_DIGIT 17 /* must be greater than any base */ 40#define UNGET_MAX_COUNT 10 41 42short unget_buf[UNGET_MAX_COUNT + 1]; 43int unget_count; 44 45static long get_number(int); 46static char *get_string(int); 47static int my_getch (void); 48 49int 50my_getch() 51{ 52 if (unget_count > 0) 53 return (unget_buf[--unget_count]); 54 else 55 return (getc(stdin)); 56} 57 58 59void 60my_ungetch(int c) 61{ 62 /* 63 * In practice there is never more than one character in 64 * the unget_buf, but what's a little overkill among friends? 65 */ 66 if (unget_count < UNGET_MAX_COUNT) 67 unget_buf[unget_count++] = c; 68 else 69 errx(1, "Programmer error in my_ungetch()."); 70} 71 72void 73flush_to_newline(int keep_newline) 74{ 75 int c; 76 77 for (;;) { 78 c = my_getch(); 79 80 if (c <= 0) { 81 break; 82 } else if (c == '\n') { 83 if (keep_newline) { 84 my_ungetch(c); 85 } 86 break; 87 } else { 88 /* skip */ 89 } 90 } 91 return; 92} 93 94 95int 96get_okay(const char *prompt, int default_value) 97{ 98 int c; 99 100 flush_to_newline(0); 101 printf(prompt); 102 103 for (;;) { 104 c = my_getch(); 105 106 if (c <= 0) { 107 break; 108 } else if (c == ' ' || c == '\t') { 109 /* skip blanks and tabs */ 110 } else if (c == '\n') { 111 my_ungetch(c); 112 return default_value; 113 } else if (c == 'y' || c == 'Y') { 114 return 1; 115 } else if (c == 'n' || c == 'N') { 116 return 0; 117 } else { 118 flush_to_newline(0); 119 printf(prompt); 120 } 121 } 122 return -1; 123} 124 125int 126get_command(const char *prompt, int promptBeforeGet, int *command) 127{ 128 int c; 129 130 if (promptBeforeGet) 131 printf(prompt); 132 133 for (;;) { 134 c = my_getch(); 135 136 if (c <= 0) { 137 break; 138 } else if (c == ' ' || c == '\t') { 139 /* skip blanks and tabs */ 140 } else if (c == '\n') { 141 printf(prompt); 142 } else { 143 *command = c; 144 return 1; 145 } 146 } 147 return 0; 148} 149 150int 151get_number_argument(const char *prompt, long *number) 152{ 153 int c; 154 int result = 0; 155 156 for (;;) { 157 c = my_getch(); 158 159 if (c <= 0) { 160 break; 161 } else if (c == ' ' || c == '\t') { 162 /* skip blanks and tabs */ 163 } else if (c == '\n') { 164 printf(prompt); 165 } else if ('0' <= c && c <= '9') { 166 *number = get_number(c); 167 result = 1; 168 break; 169 } else { 170 my_ungetch(c); 171 *number = 0; 172 break; 173 } 174 } 175 return result; 176} 177 178 179long 180get_number(int first_char) 181{ 182 int c, base, digit, ret_value; 183 184 if (first_char != '0') { 185 c = first_char; 186 base = 10; 187 digit = BAD_DIGIT; 188 } else if ((c = my_getch()) == 'x' || c == 'X') { 189 c = my_getch(); 190 base = 16; 191 digit = BAD_DIGIT; 192 } else { 193 my_ungetch(c); 194 c = first_char; 195 base = 8; 196 digit = 0; 197 } 198 ret_value = 0; 199 for (ret_value = 0;; c = my_getch()) { 200 if (c >= '0' && c <= '9') 201 digit = c - '0'; 202 else if (c >= 'A' && c <= 'F') 203 digit = 10 + (c - 'A'); 204 else if (c >= 'a' && c <= 'f') 205 digit = 10 + (c - 'a'); 206 else 207 digit = BAD_DIGIT; 208 if (digit >= base) 209 break; 210 ret_value = ret_value * base + digit; 211 } 212 my_ungetch(c); 213 return (ret_value); 214} 215 216char * 217get_dpistr_argument(const char *prompt) 218{ 219 int c; 220 221 for (;;) { 222 c = my_getch(); 223 224 if (c <= 0) { 225 break; 226 } else if (c == ' ' || c == '\t') { 227 /* skip blanks and tabs */ 228 } else if (c == '\n') { 229 printf(prompt); 230 } else if (c == '"' || c == '\'') { 231 return get_string(c); 232 } else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || 233 (c == '-' || c == '/' || c == '.' || c == ':')) { 234 my_ungetch(c); 235 return get_string(' '); 236 } else { 237 my_ungetch(c); 238 return NULL; 239 } 240 } 241 return NULL; 242} 243 244 245char * 246get_string(int eos) 247{ 248 char buf[DPISTRLEN]; 249 char *s, *limit; 250 int c; 251 252 memset(buf, 0, sizeof(buf)); 253 limit = buf + sizeof(buf); 254 255 c = my_getch(); 256 for (s = buf;; c = my_getch()) { 257 if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) { 258 *s = 0; 259 break; 260 } else if (c == '\n') { 261 *s = 0; 262 my_ungetch(c); 263 break; 264 } else { 265 *s++ = c; 266 if (s >= limit) 267 return NULL; 268 } 269 } 270 return (strdup(buf)); 271} 272 273 274unsigned long 275get_multiplier(long divisor) 276{ 277 unsigned long result, extra; 278 int c; 279 280 c = my_getch(); 281 282 extra = 1; 283 if (c <= 0 || divisor <= 0) { 284 result = 0; 285 } else if (c == 't' || c == 'T') { 286 result = 1024 * 1024; 287 extra = 1024 * 1024; 288 } else if (c == 'g' || c == 'G') { 289 result = 1024 * 1024 * 1024; 290 } else if (c == 'm' || c == 'M') { 291 result = 1024 * 1024; 292 } else if (c == 'k' || c == 'K') { 293 result = 1024; 294 } else { 295 my_ungetch(c); 296 result = 1; 297 } 298 if (result > 1) { 299 if (extra > 1) { 300 result /= divisor; 301 if (result >= 4096) { 302 /* overflow -> 20bits + >12bits */ 303 result = 0; 304 } else { 305 result *= extra; 306 } 307 } else if (result >= divisor) { 308 result /= divisor; 309 } else { 310 result = 1; 311 } 312 } 313 return result; 314} 315 316 317int 318get_partition_modifier(void) 319{ 320 int c, result; 321 322 result = 0; 323 324 c = my_getch(); 325 326 if (c == 'p' || c == 'P') 327 result = 1; 328 else if (c > 0) 329 my_ungetch(c); 330 331 return result; 332} 333 334 335int 336number_of_digits(unsigned long value) 337{ 338 int j; 339 340 j = 1; 341 while (value > 9) { 342 j++; 343 value = value / 10; 344 } 345 return j; 346} 347 348 349/* 350 * Print a message on standard error & flush the input. 351 */ 352void 353bad_input(const char *fmt,...) 354{ 355 va_list ap; 356 357 va_start(ap, fmt); 358 vfprintf(stderr, fmt, ap); 359 va_end(ap); 360 fprintf(stderr, "\n"); 361 flush_to_newline(1); 362} 363