From aa5b6f9ae4c9ec8afa7aded0a71d16fe65d47bfc Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 5 Nov 2016 14:41:21 +0100 Subject: [PATCH] Implement space completion when selling items. fixes #5 --- include/general.h | 23 +++++++++++++ src/general.c | 48 +++++++++++++++++--------- src/kasse.c | 87 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 134 insertions(+), 24 deletions(-) diff --git a/include/general.h b/include/general.h index cdc997e..768b01c 100644 --- a/include/general.h +++ b/include/general.h @@ -1,6 +1,12 @@ #ifndef GENERAL_H_ #define GENERAL_H_ typedef unsigned char BYTE; +typedef enum { + INPUT_TERMINATOR_RETURN = (1 << 0), + INPUT_TERMINATOR_SPACE = (1 << 1), +} input_terminator_t; +typedef input_terminator_t input_terminator_mask_t; +input_terminator_t get_input_terminated_by(input_terminator_mask_t terminators, char *out, BYTE outlen); char *get_input(void); char retry_or_quit(void); char *format_euro(char * s, int maxlen, int cent); @@ -32,6 +38,23 @@ extern BYTE _oserror; #define TC_LIGHT_BLUE 14 #define TC_LIGHT_GRAY 15 +/* Carriage return */ +#define PETSCII_CR 13 +/* Delete */ +#define PETSCII_DEL 20 +/* Space */ +#define PETSCII_SP 32 +#define PETSCII_0 48 +#define PETSCII_1 49 +#define PETSCII_2 50 +#define PETSCII_3 51 +#define PETSCII_4 52 +#define PETSCII_5 53 +#define PETSCII_6 54 +#define PETSCII_7 55 +#define PETSCII_8 56 +#define PETSCII_9 57 + #define VIDEOMODE (((* (BYTE *)0xD7) == 0x80) ? 80 : 40) /* because there is no macro expansion when stringifying, we need to use two diff --git a/src/general.c b/src/general.c index bdd38ea..53d7804 100644 --- a/src/general.c +++ b/src/general.c @@ -12,38 +12,52 @@ #include "general.h" /* - * Liest (maximal 31) Zeichen ein, bis Enter gedrückt wird. - * Vorsicht: Es wird ein statischer Buffer benutzt, sodass man - * das Ergebnis via strdup() retten muss, bevor man get_input() - * erneut aufruft + * get_input_terminated_by() reads input (handling backspace correctly) until + * a terminator of |terminators| is encountered or |out| is full (outlen-1 + * characters were read). + * + * get_input_terminated_by() returns the terminator it encountered. * */ -char *get_input(void) { - BYTE i = 0; +input_terminator_t get_input_terminated_by(input_terminator_mask_t terminators, char *out, BYTE outlen) { + BYTE i = strlen(out); BYTE c, x, y; - static char output[32]; - x = wherex(); + x = wherex() - i; y = wherey(); - memset(output, '\0', 32); while (1) { - if (i == 31) - break; c = cgetc(); - if (c == 13) - break; - /* backspace? */ - if (c == 20) { + if (((terminators & INPUT_TERMINATOR_RETURN) == INPUT_TERMINATOR_RETURN) && (c == PETSCII_CR)) { + return INPUT_TERMINATOR_RETURN; + } else if (((terminators & INPUT_TERMINATOR_SPACE) == INPUT_TERMINATOR_SPACE) && (c == PETSCII_SP)) { + return INPUT_TERMINATOR_SPACE; + } else if (c == PETSCII_DEL) { /* If you are at the left-most position, do nothing */ if (i == 0) continue; - output[--i] = '\0'; + out[--i] = '\0'; cputcxy(x+i, y, ' '); gotoxy(x+i, y); continue; } + if (i == (outlen-1)) { + continue; + } cputc(c); - output[i++] = c; + out[i++] = c; } +} + +/* + * Liest (maximal 31) Zeichen ein, bis Enter gedrückt wird. + * Vorsicht: Es wird ein statischer Buffer benutzt, sodass man + * das Ergebnis via strdup() retten muss, bevor man get_input() + * erneut aufruft + * + */ +char *get_input(void) { + static char output[32]; + memset(output, '\0', sizeof(output)); + get_input_terminated_by(INPUT_TERMINATOR_RETURN, output, sizeof(output)); return output; } diff --git a/src/kasse.c b/src/kasse.c index c225d87..2a78826 100644 --- a/src/kasse.c +++ b/src/kasse.c @@ -128,10 +128,11 @@ static signed int buy(char *name, unsigned int price) { BYTE c, x, y, nickname_len; int einheiten; char *input; - char nickname[11]; + char nickname[NICKNAME_MAX_LEN+1]; char rest[11]; struct credits_t *credit; + memset(nickname, '\0', sizeof(nickname)); memset(rest, ' ', sizeof(rest)); rest[8] = '\0'; @@ -146,10 +147,10 @@ static signed int buy(char *name, unsigned int price) { c = cgetc(); /* Enter */ - if (c == 13) + if (c == PETSCII_CR) break; /* Backspace */ - if (c == 20) { + if (c == PETSCII_DEL) { if (i == 0) continue; entered[--i] = '\0'; @@ -165,7 +166,7 @@ static signed int buy(char *name, unsigned int price) { if (c == '-' && i == 0) { negative = -1; cputc(c); - } else if (c > 47 && c < 58) { + } else if (c >= PETSCII_0 && c <= PETSCII_9) { entered[i++] = c; cputc(c); } @@ -184,10 +185,82 @@ static signed int buy(char *name, unsigned int price) { cprintf("\r\n *** VERKAUF ***\r\n\r\n"); cprintf("%dx %s", einheiten, name); toggle_videomode(); - + cprintf("\r\nAuf ein Guthaben kaufen? Wenn ja, Nickname eingeben:\r\n"); - input = get_input(); - strncpy(nickname, input, 11); + { + BYTE i; + BYTE x; + BYTE y; + BYTE matches; + char *uniquematch; + input_terminator_t terminator; + while (1) { + terminator = get_input_terminated_by( + INPUT_TERMINATOR_RETURN | + INPUT_TERMINATOR_SPACE, + nickname, + sizeof(nickname)); + + /* Clear the screen from any previous completions */ + x = wherex(); + y = wherey(); + for (i = 1; i < 7; i++) { + /* "Completion:" is longer than NICKNAME_MAX_LEN */ + cclearxy(0, y + i, strlen("Completion:")); + } + gotoxy(x, y); + + if (terminator != INPUT_TERMINATOR_SPACE) { + break; + } + + matches = 0; + uniquematch = NULL; + for (i = 0; i < credits.num_items; i++) { + if (strncmp(nickname, credits.credits[i].nickname, strlen(nickname)) != 0) { + continue; + } + matches++; + if (matches > 1) { + break; + } + uniquematch = credits.credits[i].nickname; + } + if (matches == 1) { + /* Display the rest of the nickname */ + textcolor(TC_LIGHT_GREEN); + cprintf("%s", uniquematch + strlen(nickname)); + textcolor(TC_LIGHT_GRAY); + strcat(nickname, uniquematch + strlen(nickname)); + } else { + /* Multiple nicknames match what was entered so far. Abort and + * display all matches, then prompt the user again. */ + char completion[NICKNAME_MAX_LEN+1]; + BYTE len = strlen(nickname); + x = wherex(); + y = wherey(); + cprintf("\r\nCompletion:\r\n"); + matches = 0; + for (i = 0; i < credits.num_items; i++) { + if (strncmp(nickname, credits.credits[i].nickname, len) != 0) { + continue; + } + if (++matches == 5) { + cprintf("...\r\n"); + break; + } + strcpy(completion, credits.credits[i].nickname); + *(completion + len) = '\0'; + cprintf("%s", completion); + textcolor(TC_LIGHT_GREEN); + cprintf("%c", *(credits.credits[i].nickname + len)); + textcolor(TC_LIGHT_GRAY); + cprintf("%s\r\n", completion + len + 1); + } + gotoxy(x, y); + } + } + } if (*nickname != '\0') { toggle_videomode(); cprintf(" fuer %s\r\n", nickname); -- 2.39.2