|
2 | 2 | #include <stdlib.h>
|
3 | 3 | #include <stdbool.h>
|
4 | 4 | #include <string.h>
|
| 5 | +#include <ctype.h> |
5 | 6 |
|
6 | 7 | #define FLIGHTS ((int) (sizeof(flights) / sizeof(flights[0])))
|
7 |
| -#define INPUT_MAX 6 |
8 |
| -#define INPUT_SIZE 512 /* extra long to ensure newline gets consumed |
9 |
| - * on each entry. This keeps validation and |
10 |
| - * potential re-entry simple. |
11 |
| - */ |
| 8 | +#define INPUT_SIZE 6 |
12 | 9 | void print_am_pm(int minutes_since_midnight);
|
13 | 10 | void find_closest_flight(int requested, int *departure_time, int *arrival_time);
|
14 | 11 | int get_valid_input(void);
|
15 |
| -bool validate_and_convert(char *input, int *hour, int *minute); |
| 12 | +bool is_format_valid(char *); |
| 13 | +void convert(char *, int *, int *); |
16 | 14 |
|
17 | 15 | static int flights[][2] = {
|
18 | 16 | {8*60, 10*60+16},
|
@@ -86,51 +84,72 @@ void find_closest_flight(int requested_departure, int *departure_time, int *arri
|
86 | 84 |
|
87 | 85 | int get_valid_input(void)
|
88 | 86 | {
|
89 |
| - int hour, minute; |
| 87 | + int i, ch, hour, minute; |
90 | 88 | char input[INPUT_SIZE];
|
91 | 89 |
|
92 | 90 | for (;;) {
|
93 | 91 | printf("Request departure time: (e.g. 21:23): ");
|
94 |
| - /* extra long buffer to ensure the newline is consumed |
95 |
| - * otherwise, we get a double prompt per every |
96 |
| - * bad entry */ |
97 |
| - fgets(input, INPUT_SIZE, stdin); |
98 |
| - if (validate_and_convert(input, &hour, &minute)) |
99 |
| - return (hour * 60) + minute; |
100 |
| - fprintf(stderr, "Invalid Input\n"); |
| 92 | + /* swallow spaces */ |
| 93 | + while (isspace(ch = getchar())) |
| 94 | + ; |
| 95 | + |
| 96 | + /* fill in the input buffer, |
| 97 | + * and consume any remaining input |
| 98 | + * on stdin including the newline. |
| 99 | + * That way, we don't get any double prompts |
| 100 | + * should we have to re-prompt after bad input |
| 101 | + */ |
| 102 | + for (i = 0; ch != '\n'; ch = getchar()) |
| 103 | + if (i < INPUT_SIZE) |
| 104 | + input[i++] = ch; |
| 105 | + |
| 106 | + input[i] = '\0'; |
| 107 | + if (is_format_valid(input)) { |
| 108 | + convert(input, &hour, &minute); |
| 109 | + if (hour < 24 && minute < 60) |
| 110 | + return (hour * 60) + minute; |
| 111 | + } |
| 112 | + |
| 113 | + fprintf(stderr, "Invalid Input: '%s'\n", input); |
101 | 114 | }
|
102 | 115 | }
|
103 |
| -bool validate_and_convert(char *input, int *hour, int *minute) |
| 116 | +bool is_format_valid(char *input) |
104 | 117 | {
|
105 |
| - char *h, *m; |
106 |
| - int len; |
107 |
| - |
108 |
| - if (strlen(input) > (size_t)INPUT_MAX) |
109 |
| - return false; |
110 |
| - |
111 |
| - /* find delimiter */ |
112 |
| - if (strchr(input, ':') == NULL) |
113 |
| - return false; |
114 |
| - |
115 |
| - /* point to start of token before the delimiter; */ |
116 |
| - /* replace the delimiter w/ NULL */ |
117 |
| - h = strtok(input, ":"); |
118 |
| - if ((len = strlen(h)) == 0 || len > 2) |
| 118 | + size_t i, len = strlen(input); |
| 119 | + int d; |
| 120 | + if (!len) |
119 | 121 | return false;
|
120 | 122 |
|
121 |
| - *hour = atoi(h); |
122 |
| - if (*hour < 0 || *hour > 23) |
123 |
| - return false; |
| 123 | + for (d = -1, i = 0; i < len; i++) { |
| 124 | + if (d < 0 && /* No delimiter found yet */ |
| 125 | + input[i] == ':') { /* First instance of delimiter */ |
| 126 | + d = i; /* Can't follow this branch anymore: |
| 127 | + * any other copies of ':' will see isdigit(). |
| 128 | + */ |
| 129 | + if (d < 1 || d > 2) /* possible positions */ |
| 130 | + return false; |
| 131 | + } else if (!isdigit(input[i])) |
| 132 | + return false; |
| 133 | + } |
124 | 134 |
|
125 |
| - /* point to start of next token after the delimiter; */ |
126 |
| - /* replace any NEWLINE with NULL */ |
127 |
| - m = strtok(NULL, ":\n"); |
128 |
| - if ((len = strlen(m)) == 0 || len > 2) |
129 |
| - return false; |
| 135 | + if (d == -1 && len > 2) /* if there's no delimiter, */ |
| 136 | + return false; /* there can only be a 1 or 2 digit hour */ |
130 | 137 |
|
131 |
| - *minute = atoi(m); |
132 |
| - if (*minute < 0 || *minute > 59) |
| 138 | + if (d == (int)len - 1) /* delimiter is at the end */ |
133 | 139 | return false;
|
134 | 140 |
|
135 | 141 | return true;
|
136 | 142 | }
|
| 143 | +void convert(char *input, int *hour, int *minute) |
| 144 | +{ |
| 145 | + char h[3], *delimiter; |
| 146 | + |
| 147 | + if ((delimiter = strchr(input, ':'))) { |
| 148 | + strncpy(h, input, delimiter - input); |
| 149 | + *hour = atoi(h); |
| 150 | + *minute = atoi(delimiter + 1); |
| 151 | + } else { |
| 152 | + *hour = atoi(input); |
| 153 | + *minute = 0; |
| 154 | + } |
| 155 | +} |
0 commit comments