#include #include #include #include #include "string_util.h" #include "ismap.h" int int_hash_identity(int n); void free_value(int key, char *value); void print_entry(int key, char *value); bool read_segment(FILE *stream, int *id, int *seq, int *tot, char *origin, char *destination); #define CODE_LENGTH 3 int main(int argc, char **argv) { ismap *routes = ismap_create(int_hash_identity); int id, seq, tot; char origin[CODE_LENGTH + 1]; char destination[CODE_LENGTH + 1]; while (read_segment(stdin, &id, &seq, &tot, origin, destination)) { if (!ismap_contains_key(routes, id)) { // key is not present; add it with empty route of // approriate size (3 chars for each airport in the route); char *route = malloc(sizeof(char) * CODE_LENGTH * (tot + 1) + 1); for (int i = 0; i < CODE_LENGTH * (tot + 1); i++) { route[i] = ' '; } route[CODE_LENGTH * (tot + 1)] = '\0'; ismap_put(routes, id, route); } // key should be present now; get value and update it char *route = ismap_get(routes, id); if (route != NULL) { // make sure sequence numbers work out if (strlen(route) >= (tot + 1) * CODE_LENGTH) { // copy origin and destination airports into appropriate // location in route strncpy(route + (seq - 1) * CODE_LENGTH, origin, CODE_LENGTH); strncpy(route + seq * CODE_LENGTH, destination, CODE_LENGTH); } } } ismap_for_each(routes, print_entry); // free allocated memory ismap_for_each(routes, free_value); ismap_destroy(routes); } /** * Prints the given map entry to standard output. */ void print_entry(int key, char *value) { printf("%d=%s\n", key, value); } /** * Frees the value in the given map entry. */ void free_value(int key, char *value) { free(value); } /** * A very bad hash function for integers. */ int int_hash_identity(int n) { return n; } /** * Reads a record from the US DOT coupons database into the given * (simulated) reference parameters. * * @param stream the stream to read from * @param id a pointer to an int, non-NULL * @param tot a pointer to an int, non-NULL * @param seq a pointer to an int, non-NULL * @param origin a pointer to an array of 4 characters, non-NULL * @param destination a pointer to an array of 4 characters, non-NULL */ bool read_segment(FILE *stream, int *id, int *seq, int *tot, char *origin, char *destination) { // zero everything out so we can check later if they were read correctly *id = 0; *seq = 0; *tot = 0; origin[0] = '\0'; destination[0] = '\0'; // no line in the database is > 80 characters, but use read_line to be safe char line[81]; read_line(line, 80); // check that we read enough to at least get the id int len = strlen(line); if (strlen(line) > 2) { // skip the 1st two digits in the id (they're always 20 in our data) // (if we want all the digits then we need to use a long for the ids // and hence our map need to work with longs as keys) *id = atoi(line + 2); // look for spaces in the input, and pluck out the parts before // the 2nd, 3rd, 5th, and 6th spaces, which are the sequence number, // number of records in the sequence, origin, and destination // respectively int space = 0; char *last = line; for (int i = 0; i < len; i++) { if (line[i] == ' ') { // found a space...count it and replace with a null character // so we can treat from after the last space to here as a string space++; line[i] = '\0'; if (space == 2) { *seq = atoi(last); } else if (space == 3) { *tot = atoi(last); } else if (space == 5) { if (strlen(last) == CODE_LENGTH) { strcpy(origin, last); } } else if (space == 6) { if (strlen(last) == CODE_LENGTH) { strcpy(destination, last); } } // remember location of this space to use as the beginning // of the string ended by the next space we found last = line + i + 1; } } } // return true if we were able to read everything return (*id != 0 && *seq != 0 && *tot != 0 && strlen(origin) > 0 && strlen(destination) > 0); }