From 550734fd3fbd645daa1df42997b8ad876461f609 Mon Sep 17 00:00:00 2001 From: "Jason S. Ninneman" Date: Sun, 18 Jun 2017 13:37:51 -0700 Subject: [PATCH] Gut and rebuild YES() with cleaner approach that doesn't rely on packing. The new support functions get_input() and echo_input() (and others not made yet) will eventually replace GETIN() and MAPLIN(). --- actions.c | 4 +- advent.h | 5 ++- main.c | 8 ++-- misc.c | 115 +++++++++++++++++++++++++++++++++++++++++------ saveresume.c | 6 +-- tests/logopt.chk | 3 +- 6 files changed, 116 insertions(+), 25 deletions(-) diff --git a/actions.c b/actions.c index 1938d24..5348d3d 100644 --- a/actions.c +++ b/actions.c @@ -792,7 +792,7 @@ static int pour(token_t verb, token_t obj) static int quit(FILE *input) /* Quit. Intransitive only. Verify intent and exit if that's what he wants. */ { - if (YES(input, REALLY_QUIT, OK_MAN, OK_MAN)) + if (YES(REALLY_QUIT, OK_MAN, OK_MAN)) terminate(quitgame); return GO_CLEAROBJ; } @@ -820,7 +820,7 @@ static int read(FILE *input, token_t verb, token_t obj) return GO_CLEAROBJ; } if (obj == OYSTER && !game.clshnt) { - game.clshnt = YES(input, CLUE_QUERY, WAYOUT_CLUE, OK_MAN); + game.clshnt = YES(CLUE_QUERY, WAYOUT_CLUE, OK_MAN); return GO_CLEAROBJ; } PSPEAK(obj, OBJTXT[obj] + game.prop[obj]); diff --git a/advent.h b/advent.h index 77c8079..d23d8fd 100644 --- a/advent.h +++ b/advent.h @@ -83,6 +83,7 @@ extern bool oldstyle, editline, prompt; /* b is not needed for POSIX but harmless */ #define READ_MODE "rb" #define WRITE_MODE "wb" +extern void* xmalloc(size_t size); extern char* xstrdup(const char*); extern void packed_to_token(long, char token[]); extern void speak(const char*); @@ -90,7 +91,9 @@ extern void PSPEAK(vocab_t,int); extern void RSPEAK(vocab_t); extern void SETPRM(long,long,long); extern bool GETIN(FILE *,token_t*,token_t*,token_t*,token_t*); -extern long YES(FILE *,vocab_t,vocab_t,vocab_t); +extern void echo_input(FILE*, char*, char*); +extern char* get_input(void); +extern bool YES(vocab_t, vocab_t, vocab_t); extern long GETTXT(bool,bool,bool); extern token_t MAKEWD(long); extern long VOCAB(long,long); diff --git a/main.c b/main.c index e5859b6..b97e44c 100644 --- a/main.c +++ b/main.c @@ -135,7 +135,7 @@ int main(int argc, char *argv[]) game.loc = LOC_START; game.limit = 330; if (!rfp) { - game.novice = YES(stdin, WELCOME_YOU, CAVE_NEARBY, NO_MESSAGE); + game.novice = YES(WELCOME_YOU, CAVE_NEARBY, NO_MESSAGE); if (game.novice)game.limit = 1000; } else { restore(rfp); @@ -251,11 +251,11 @@ static void checkhints(FILE *cmdin) /* Fall through to hint display */ game.hintlc[hint] = 0; - if (!YES(cmdin, HINTS[hint][3], NO_MESSAGE, OK_MAN)) + if (!YES(HINTS[hint][3], NO_MESSAGE, OK_MAN)) return; SETPRM(1, HINTS[hint][2], HINTS[hint][2]); RSPEAK(HINT_COST); - game.hinted[hint] = YES(cmdin, WANT_HINT, HINTS[hint][4], OK_MAN); + game.hinted[hint] = YES(WANT_HINT, HINTS[hint][4], OK_MAN); if (game.hinted[hint] && game.limit > WARNTIME) game.limit += WARNTIME * HINTS[hint][2]; } @@ -485,7 +485,7 @@ static void croak(FILE *cmdin) terminate(endgame); } /* FIXME: Arithmetic on message numbers */ - else if (game.numdie == MAXDIE || !YES(cmdin, WATCH_IT + game.numdie * 2, WHICH_WAY + game.numdie * 2, OK_MAN)) + else if (game.numdie == MAXDIE || !YES(WATCH_IT + game.numdie * 2, WHICH_WAY + game.numdie * 2, OK_MAN)) terminate(endgame); else { game.place[WATER] = game.place[OIL] = NOWHERE; diff --git a/misc.c b/misc.c index 410dfd8..aa4286b 100644 --- a/misc.c +++ b/misc.c @@ -10,6 +10,17 @@ #include "linenoise/linenoise.h" #include "newdb.h" +void* xmalloc(size_t size) +{ + void* ptr = malloc(size); + if (ptr == NULL) + { + fprintf(stderr, "Out of memory!\n"); + exit(EXIT_FAILURE); + } + return(ptr); +} + char* xstrdup(const char* s) { char* ptr = strdup(s); @@ -185,25 +196,101 @@ bool GETIN(FILE *input, } } -long YES(FILE *input, vocab_t x, vocab_t y, vocab_t z) +void echo_input(FILE* destination, char* input_prompt, char* input) +{ + size_t len = strlen(input_prompt) + strlen(input) + 1; + char* prompt_and_input = (char*) xmalloc(len); + strcpy(prompt_and_input, input_prompt); + strcat(prompt_and_input, input); + fprintf(destination, "%s\n", prompt_and_input); + free(prompt_and_input); +} + +char* get_input() +{ + // Set up the prompt + char input_prompt[] = "> "; + if (!prompt) + input_prompt[0] = '\0'; + + // Print a blank line if game.blklin tells us to. + if (game.blklin == true) + printf("\n"); + + char* input; + while (true) + { + if (editline) + input = linenoise(input_prompt); + else + { + input = NULL; + size_t n = 0; + if (isatty(0)) + printf("%s", input_prompt); + getline(&input, &n, stdin); + } + + if (input == NULL) // Got EOF; quit. + exit(EXIT_SUCCESS); + else if (input[0] == '#') // Ignore comments. + continue; + else // We have a 'normal' line; leave the loop. + break; + } + + // Strip trailing newlines from the input + input[strcspn(input, "\n")] = 0; + + linenoiseHistoryAdd(input); + + if (!isatty(0)) + echo_input(stdout, input_prompt, input); + + if (logfp) + echo_input(logfp, input_prompt, input); + + return(input); +} + +bool YES(vocab_t question, vocab_t yes_response, vocab_t no_response) /* Print message X, wait for yes/no answer. If yes, print Y and return true; * if no, print Z and return false. */ { - token_t reply, junk1, junk2, junk3; - + char* reply; + bool outcome; + for (;;) { - RSPEAK(x); - GETIN(input, &reply, &junk1, &junk2, &junk3); - if (reply == MAKEWD(250519) || reply == MAKEWD(25)) { - RSPEAK(y); - return true; - } - if (reply == MAKEWD(1415) || reply == MAKEWD(14)) { - RSPEAK(z); - return false; - } - RSPEAK(PLEASE_ANSWER); + RSPEAK(question); + + reply = get_input(); + + char* firstword = (char*) xmalloc(strlen(reply)); + sscanf(reply, "%s", firstword); + + for (int i = 0; i < strlen(firstword); ++i) + firstword[i] = tolower(firstword[i]); + + int yes = strncmp("yes", reply, sizeof("yes") - 1); + int y = strncmp("y", reply, sizeof("y") - 1); + int no = strncmp("no", reply, sizeof("no") - 1); + int n = strncmp("n", reply, sizeof("n") - 1); + + if (yes == 0 || y == 0) { + RSPEAK(yes_response); + outcome = true; + break; + } + else if (no == 0 || n == 0) { + RSPEAK(no_response); + outcome = false; + break; + } + else + RSPEAK(PLEASE_ANSWER); } + linenoiseFree(reply); + return(outcome); } /* Line-parsing routines (GETTXT, MAKEWD, PUTTXT, SHFTXT) */ diff --git a/saveresume.c b/saveresume.c index 6f570b9..5009171 100644 --- a/saveresume.c +++ b/saveresume.c @@ -44,7 +44,7 @@ int suspend(FILE *input) FILE *fp = NULL; RSPEAK(SUSPEND_WARNING); - if (!YES(input, THIS_ACCEPTABLE, OK_MAN, OK_MAN)) return GO_CLEAROBJ; + if (!YES(THIS_ACCEPTABLE, OK_MAN, OK_MAN)) return GO_CLEAROBJ; game.saved = game.saved + 5; while (fp == NULL) { @@ -83,7 +83,7 @@ int resume(FILE *input) if (game.loc != 1 || game.abbrev[1] != 1) { RSPEAK(RESUME_ABANDON); - if (!YES(input, THIS_ACCEPTABLE, OK_MAN, OK_MAN)) return GO_CLEAROBJ; + if (!YES(THIS_ACCEPTABLE, OK_MAN, OK_MAN)) return GO_CLEAROBJ; } while (fp == NULL) { @@ -123,4 +123,4 @@ int restore(FILE* fp) return GO_TOP; } -/* end */ \ No newline at end of file +/* end */ diff --git a/tests/logopt.chk b/tests/logopt.chk index 1ed3c78..06c8fba 100644 --- a/tests/logopt.chk +++ b/tests/logopt.chk @@ -1,7 +1,8 @@ Welcome to Adventure!! Would you like instructions? -> > > +> n + You are standing at the end of a road before a small brick building. Around you is a forest. A small stream flows out of the building and down a gully. -- 2.31.1