// Command-line interface to the Student DB ADT // !!! DO NOT MODIFY THIS FILE !!! #include #include #include #include #include #include "Record.h" #include "StudentDb.h" #define MAX 8192 static void processOptions(int argc, char *argv[]); static void showUsage(char *progName); static void showWelcomeMessage(void); static bool getCommand(char *buf); static char **tokenise(char *s, int *ntokens); static void showHelp(void); static void runInsertRecord(StudentDb db, char **tokens); static void runListByZid(StudentDb db, char **tokens); static void runListByName(StudentDb db, char **tokens); static void runDeleteByZid(StudentDb db, char **tokens); static void runFindByZid(StudentDb db, char **tokens); static void runFindByName(StudentDb db, char **tokens); static void showRecordList(List l); //////////////////////////////////////////////////////////////////////// typedef struct command { char *code; int numArgs; void (*fn)(StudentDb, char **); char *argHint; char *helpMsg; } Command; #define NUM_COMMANDS 8 static Command COMMANDS[NUM_COMMANDS] = { {"+", 3, runInsertRecord, " ", "add a student record"}, {"lz", 0, runListByZid, "", "list all records in order of zid"}, {"ln", 0, runListByName, "", "list all records in order of name"}, {"d", 1, runDeleteByZid, "", "delete a student record"}, {"fz", 1, runFindByZid, "", "find a student record by zid"}, {"fn", 2, runFindByName, " ", "find student records by name"}, // Meta-commands {"?", 0, NULL, "", "show this message"}, {"q", 0, NULL, "", "quit"}, }; //////////////////////////////////////////////////////////////////////// bool ECHO = false; int main(int argc, char *argv[]) { processOptions(argc, argv); showWelcomeMessage(); StudentDb db = DbNew(); bool done = false; char cmd[MAX] = {0}; while (!done && getCommand(cmd)) { if (ECHO) { printf("%s", cmd); } int ntokens = 0; char **tokens = tokenise(cmd, &ntokens); if (ntokens == 0) { free(tokens); continue; } char *cmdname = tokens[0]; // Meta-commands if (strcmp(cmdname, "?") == 0) { showHelp(); } else if (strcmp(cmdname, "q") == 0) { done = true; // Actual commands } else { bool validCommand = false; for (int i = 0; i < NUM_COMMANDS; i++) { if (strcmp(cmdname, COMMANDS[i].code) == 0) { validCommand = true; if (ntokens - 1 == COMMANDS[i].numArgs) { COMMANDS[i].fn(db, tokens); } else { printf("Usage: %s %s\n", COMMANDS[i].code, COMMANDS[i].argHint); } } } if (!validCommand) { printf("Unknown command '%s'\n", cmdname); } } free(tokens); } DbFree(db); } static void processOptions(int argc, char *argv[]) { for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-h") == 0) { showUsage(argv[0]); exit(EXIT_SUCCESS); } else if (strcmp(argv[i], "-e") == 0) { ECHO = true; } } } static void showUsage(char *progName) { printf("Usage: %s [options]...\n" "Options:\n" " -h show this help message\n" " -e echo - echo all commands\n", progName); } static void showWelcomeMessage(void) { printf("StudentDb v1.0\n"); printf("Enter ? to see the list of commands.\n"); } static bool getCommand(char *buf) { printf("> "); return (fgets(buf, MAX, stdin) != NULL); } static char **tokenise(char *s, int *ntokens) { char p; // count number of tokens *ntokens = 0; p = ' '; for (char *c = s; *c != '\0'; p = *c, c++) { if (isspace(p) && !isspace(*c)) { (*ntokens)++; } } char **tokens = malloc((*ntokens + 1) * sizeof(char *)); int i = 0; p = ' '; for (char *c = s; *c != '\0'; p = *c, c++) { if ((p == '\0' || isspace(p)) && !isspace(*c)) { tokens[i++] = c; } else if (!isspace(p) && isspace(*c)) { *c = '\0'; } } tokens[i] = NULL; return tokens; } static void showHelp(void) { printf("Commands:\n"); for (int i = 0; i < NUM_COMMANDS; i++) { printf("%5s %-36s %s\n", COMMANDS[i].code, COMMANDS[i].argHint, COMMANDS[i].helpMsg); } printf("\n"); } //////////////////////////////////////////////////////////////////////// // Commands static void runInsertRecord(StudentDb db, char **tokens) { char *zidStr = tokens[1]; char *familyName = tokens[2]; char *givenName = tokens[3]; int zid = atoi(zidStr); if (zid == 0 || zid < MIN_ZID || zid > MAX_ZID) { fprintf(stderr, "Invalid zid '%s'\n", zidStr); return; } Record r = RecordNew(zid, familyName, givenName); if (r == NULL) { return; } if (DbInsertRecord(db, r)) { printf("Successfully inserted record!\n"); } else { printf("There is already a record with zid '%d'\n", zid); RecordFree(r); } } static void runListByZid(StudentDb db, char **tokens) { DbListByZid(db); } static void runListByName(StudentDb db, char **tokens) { DbListByName(db); } static void runDeleteByZid(StudentDb db, char **tokens) { char *zidStr = tokens[1]; int zid = atoi(zidStr); if (zid == 0 || zid < MIN_ZID || zid > MAX_ZID) { fprintf(stderr, "Invalid zid '%s'\n", zidStr); return; } if (DbDeleteByZid(db, zid)) { printf("Successfully deleted record!\n"); } else { printf("Could not find a record with zid '%d' to delete\n", zid); } } static void runFindByZid(StudentDb db, char **tokens) { char *zidStr = tokens[1]; int zid = atoi(zidStr); if (zid == 0 || zid < MIN_ZID || zid > MAX_ZID) { fprintf(stderr, "Invalid zid '%s'\n", zidStr); return; } Record r = DbFindByZid(db, zid); if (r == NULL) { printf("No records with zid '%d'\n", zid); } else { printf("Found a record:\n"); RecordShow(r); printf("\n"); } } static void runFindByName(StudentDb db, char **tokens) { char *familyName = tokens[1]; char *givenName = tokens[2]; List l = DbFindByName(db, familyName, givenName); if (ListSize(l) == 0) { printf("No records found\n"); } else { printf("Found records:\n"); showRecordList(l); } ListFree(l); } //////////////////////////////////////////////////////////////////////// static void showRecordList(List l) { ListIterator it = ListItNew(l); while (ListItHasNext(it)) { RecordShow(ListItNext(it)); printf("\n"); } ListItFree(it); }