Skip to content

Commit eeefa82

Browse files
committed
pgm 22.13, input val rationalized and bullet proofed
1 parent b3807d7 commit eeefa82

File tree

1 file changed

+58
-39
lines changed

1 file changed

+58
-39
lines changed

22/22.13-find-departure.c

Lines changed: 58 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,15 @@
22
#include <stdlib.h>
33
#include <stdbool.h>
44
#include <string.h>
5+
#include <ctype.h>
56

67
#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
129
void print_am_pm(int minutes_since_midnight);
1310
void find_closest_flight(int requested, int *departure_time, int *arrival_time);
1411
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 *);
1614

1715
static int flights[][2] = {
1816
{8*60, 10*60+16},
@@ -86,51 +84,72 @@ void find_closest_flight(int requested_departure, int *departure_time, int *arri
8684

8785
int get_valid_input(void)
8886
{
89-
int hour, minute;
87+
int i, ch, hour, minute;
9088
char input[INPUT_SIZE];
9189

9290
for (;;) {
9391
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);
101114
}
102115
}
103-
bool validate_and_convert(char *input, int *hour, int *minute)
116+
bool is_format_valid(char *input)
104117
{
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)
119121
return false;
120122

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+
}
124134

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 */
130137

131-
*minute = atoi(m);
132-
if (*minute < 0 || *minute > 59)
138+
if (d == (int)len - 1) /* delimiter is at the end */
133139
return false;
134140

135141
return true;
136142
}
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

Comments
 (0)