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