From 5fd104afee44fa5987134d27b9a3b425fa6574db Mon Sep 17 00:00:00 2001 From: Brian Barto Date: Thu, 19 Jan 2017 11:17:40 -0500 Subject: [PATCH] Change file names and update function names (to align with file name changes) modified: Makefile renamed: src/main.c -> src/nms.c deleted: src/nms.h renamed: src/nms.c -> src/nmseffect.c new file: src/nmseffect.h modified: src/sneakers.c --- Makefile | 8 +- src/main.c | 68 -------- src/nms.c | 456 +++++------------------------------------------- src/nms.h | 20 --- src/nmseffect.c | 421 ++++++++++++++++++++++++++++++++++++++++++++ src/nmseffect.h | 20 +++ src/sneakers.c | 10 +- 7 files changed, 498 insertions(+), 505 deletions(-) delete mode 100644 src/main.c delete mode 100644 src/nms.h create mode 100644 src/nmseffect.c create mode 100644 src/nmseffect.h diff --git a/Makefile b/Makefile index 80e060a..40cac4d 100644 --- a/Makefile +++ b/Makefile @@ -17,20 +17,20 @@ CFLAGS ?= -Wextra -Wall .PHONY: all install uninstall clean -nms: $(OBJ)/nmsterm.o $(OBJ)/nms.o $(OBJ)/main.o | $(BIN) +nms: $(OBJ)/nmsterm.o $(OBJ)/nmseffect.o $(OBJ)/nms.o | $(BIN) $(CC) $(CFLAGS) -o $(BIN)/$@ $^ -sneakers: $(OBJ)/nmsterm.o $(OBJ)/nms.o $(OBJ)/sneakers.o | $(BIN) +sneakers: $(OBJ)/nmsterm.o $(OBJ)/nmseffect.o $(OBJ)/sneakers.o | $(BIN) $(CC) $(CFLAGS) -o $(BIN)/$@ $^ all: nms sneakers all-ncurses: nms-ncurses sneakers-ncurses -nms-ncurses: $(OBJ)/nmsterm_ncurses.o $(OBJ)/nms.o $(OBJ)/main.o | $(BIN) +nms-ncurses: $(OBJ)/nmsterm_ncurses.o $(OBJ)/nmseffect.o $(OBJ)/nms.o | $(BIN) $(CC) $(CFLAGS) -o $(BIN)/nms $^ -lncurses -sneakers-ncurses: $(OBJ)/nmsterm_ncurses.o $(OBJ)/nms.o $(OBJ)/sneakers.o | $(BIN) +sneakers-ncurses: $(OBJ)/nmsterm_ncurses.o $(OBJ)/nmseffect.o $(OBJ)/sneakers.o | $(BIN) $(CC) $(CFLAGS) -o $(BIN)/sneakers $^ -lncurses $(OBJ)/%.o: $(SRC)/%.c | $(OBJ) diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 095d459..0000000 --- a/src/main.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2017 Brian Barto - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the MIT License. See LICENSE for more details. - */ - -#include -#include -#include -#include -#include "nms.h" - -#define VERSION "0.3.0" -#define INPUT_GROWTH_FACTOR 2 - -int main(int argc, char *argv[]) { - int c, o, inSize = 0, inCapacity = 0; - char *input = NULL; - - // Processing command arguments - while ((o = getopt(argc, argv, "f:acv")) != -1) { - switch (o) { - case 'f': - nms_set_foregroundcolor(optarg); - break; - case 'a': - nms_set_auto_decrypt(1); - break; - case 'c': - nms_set_clearscr(1); - break; - case 'v': - printf("nms version " VERSION "\n"); - return 0; - case '?': - if (isprint(optopt)) - fprintf (stderr, "Unknown option '-%c'.\n", optopt); - else - fprintf (stderr, "Unknown option character '\\x%x'.\n", optopt); - return 1; - } - } - - // Geting input - while ((c = getchar()) != EOF) { - ++inSize; - if (inSize > inCapacity) { - inCapacity = inCapacity == 0 ? INPUT_GROWTH_FACTOR : inCapacity * INPUT_GROWTH_FACTOR; - input = realloc(input, inCapacity + 1); - } - input[inSize - 1] = c; - input[inSize] = '\0'; - } - - // Display characters - c = nms_exec(input); - - // Print out from nms_exec if it is not null - if (c) { - printf("%c", c); - } - - // Don't forget to free the allocated memory! - free(input); - - return 0; -} diff --git a/src/nms.c b/src/nms.c index 91cd4b3..564bf08 100644 --- a/src/nms.c +++ b/src/nms.c @@ -4,425 +4,65 @@ * This program is free software; you can redistribute it and/or modify it * under the terms of the MIT License. See LICENSE for more details. */ - -/* - * DESCRIPTION - * - * This library encapsulates the functionality required to produce the - * famous data decryption effect from the 1992 hacker movie Sneakers. - */ - -#define _XOPEN_SOURCE 700 #include -#include #include #include #include -#include -#include -#include -#include "nms.h" -#include "nmsterm.h" +#include "nmseffect.h" -// Program settings -#define TYPE_EFFECT_SPEED 4 // miliseconds per char -#define JUMBLE_SECONDS 2 // number of seconds for jumble effect -#define JUMBLE_LOOP_SPEED 35 // miliseconds between each jumble -#define REVEAL_LOOP_SPEED 50 // miliseconds between each reveal loop -#define MASK_CHAR_COUNT 218 // Total characters in maskCharTable[] array. +#define VERSION "0.3.0" +#define INPUT_GROWTH_FACTOR 2 -// Character attribute structure, linked list. Keeps track of every -// character's attributes required for rendering and decryption effect. -struct charAttr { - char *source; - char *mask; - int width; - int is_space; - int time; - struct charAttr *next; -}; +int main(int argc, char *argv[]) { + int c, o, inSize = 0, inCapacity = 0; + char *input = NULL; -// Static function prototypes -static void nms_sleep(int); - -// NMS settings -static char *returnOpts = NULL; // Return option setting -static int autoDecrypt = 0; // Auto-decrypt flag -static int colorOn = 1; // Terminal color flag -static int inputPositionX = -1; // X coordinate for input position -static int inputPositionY = -1; // Y coordinate for input position - -// Character table representing the character set know as CP437 used by -// the original IBM PC - https://en.wikipedia.org/wiki/Code_page_437 -static char *maskCharTable[] = { - "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", "~", - ".", "/", ":", ";", "<", "=", ">", "?", "[", "\\", "]", "_", "{", "}", - "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", - "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", - "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", - "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", - "\xc3\x87", "\xc3\xbc", "\xc3\xa9", "\xc3\xa2", "\xc3\xa4", "\xc3\xa0", - "\xc3\xa5", "\xc3\xa7", "\xc3\xaa", "\xc3\xab", "\xc3\xa8", "\xc3\xaf", - "\xc3\xae", "\xc3\xac", "\xc3\x84", "\xc3\x85", "\xc3\x89", "\xc3\xa6", - "\xc3\x86", "\xc3\xb4", "\xc3\xb6", "\xc3\xb2", "\xc3\xbb", "\xc3\xb9", - "\xc3\xbf", "\xc3\x96", "\xc3\x9c", "\xc2\xa2", "\xc2\xa3", "\xc2\xa5", - "\xc6\x92", "\xc3\xa1", "\xc3\xad", "\xc3\xb3", "\xc3\xba", "\xc3\xb1", - "\xc3\x91", "\xc2\xaa", "\xc2\xba", "\xc2\xbf", "\xc2\xac", "\xc2\xbd", - "\xc2\xbc", "\xc2\xa1", "\xc2\xab", "\xc2\xbb", "\xce\xb1", "\xc3\x9f", - "\xce\x93", "\xcf\x80", "\xce\xa3", "\xcf\x83", "\xc2\xb5", "\xcf\x84", - "\xce\xa6", "\xce\x98", "\xce\xa9", "\xce\xb4", "\xcf\x86", "\xce\xb5", - "\xc2\xb1", "\xc3\xb7", "\xc2\xb0", "\xc2\xb7", "\xc2\xb2", "\xc2\xb6", - "\xe2\x8c\x90", "\xe2\x82\xa7", "\xe2\x96\x91", "\xe2\x96\x92", - "\xe2\x96\x93", "\xe2\x94\x82", "\xe2\x94\xa4", "\xe2\x95\xa1", - "\xe2\x95\xa2", "\xe2\x95\x96", "\xe2\x95\x95", "\xe2\x95\xa3", - "\xe2\x95\x91", "\xe2\x95\x97", "\xe2\x95\x9d", "\xe2\x95\x9c", - "\xe2\x95\x9b", "\xe2\x94\x90", "\xe2\x94\x94", "\xe2\x94\xb4", - "\xe2\x94\xac", "\xe2\x94\x9c", "\xe2\x94\x80", "\xe2\x94\xbc", - "\xe2\x95\x9e", "\xe2\x95\x9f", "\xe2\x95\x9a", "\xe2\x95\x94", - "\xe2\x95\xa9", "\xe2\x95\xa6", "\xe2\x95\xa0", "\xe2\x95\x90", - "\xe2\x95\xac", "\xe2\x95\xa7", "\xe2\x95\xa8", "\xe2\x95\xa4", - "\xe2\x95\xa7", "\xe2\x95\x99", "\xe2\x95\x98", "\xe2\x95\x92", - "\xe2\x95\x93", "\xe2\x95\xab", "\xe2\x95\xaa", "\xe2\x94\x98", - "\xe2\x94\x8c", "\xe2\x96\x88", "\xe2\x96\x84", "\xe2\x96\x8c", - "\xe2\x96\x90", "\xe2\x96\x80", "\xe2\x88\x9e", "\xe2\x88\xa9", - "\xe2\x89\xa1", "\xe2\x89\xa5", "\xe2\x89\xa4", "\xe2\x8c\xa0", - "\xe2\x8c\xa1", "\xe2\x89\x88", "\xe2\x88\x99", "\xe2\x88\x9a", - "\xe2\x81\xbf", "\xe2\x96\xa0" -}; - -/* - * nms_exec() - This function is passed a pointer to a character string - * and displays the contents of the string in a way that mimicks the - * "decrypting text" effect in the 1992 movie Sneakers. It returns the - * last character pressed by the user. - */ -char nms_exec(char *string) { - struct charAttr *list_pointer = NULL; - struct charAttr *list_head = NULL; - struct charAttr *list_temp = NULL; - int i, revealed = 0; - int maxRows, maxCols, curRow, curCol, origRow = 0, origCol = 0; - char ret = 0; - - // Error if we have an empty string. - if (string == NULL || string[0] == '\0') { - fprintf(stderr, "Error. Empty string.\n"); - return 0; + // Processing command arguments + while ((o = getopt(argc, argv, "f:acv")) != -1) { + switch (o) { + case 'f': + nmseffect_set_foregroundcolor(optarg); + break; + case 'a': + nmseffect_set_auto_decrypt(1); + break; + case 'c': + nmseffect_set_clearscr(1); + break; + case 'v': + printf("nms version " VERSION "\n"); + return 0; + case '?': + if (isprint(optopt)) + fprintf (stderr, "Unknown option '-%c'.\n", optopt); + else + fprintf (stderr, "Unknown option character '\\x%x'.\n", optopt); + return 1; + } } + + // Geting input + while ((c = getchar()) != EOF) { + ++inSize; + if (inSize > inCapacity) { + inCapacity = inCapacity == 0 ? INPUT_GROWTH_FACTOR : inCapacity * INPUT_GROWTH_FACTOR; + input = realloc(input, inCapacity + 1); + } + input[inSize - 1] = c; + input[inSize] = '\0'; + } + + // Execute effect + c = nmseffect_exec(input); - // Reassociate STDIN to the terminal is needed - if (!isatty(STDIN_FILENO) && !freopen ("/dev/tty", "r", stdin)) { - fprintf(stderr, "Error. Can't associate STDIN with terminal.\n"); - return 0; - } - - // Needed for UTF-8 support - setlocale(LC_ALL, ""); - - // Initialize terminal - nmsterm_init_terminal(); - - if (!nmsterm_get_clearscr()) { - // Get current row position - origRow = nmsterm_get_cursor_row(); - - // nms_get_cursor_row() may display output in some terminals. So - // we need to reposition the cursor to the start of the row. - nmsterm_move_cursor(origRow, 0); + // Print out from nms_exec if it is not null + if (c) { + printf("%c", c); } - // Get terminal window rows/cols - maxRows = nmsterm_get_rows(); - maxCols = nmsterm_get_cols(); + // Don't forget to free the allocated memory! + free(input); - // Seed my random number generator with the current time - srand(time(NULL)); - - // Assign current row/col positions - curRow = origRow; - curCol = origCol; - - // Processing input - for (i = 0; string[i] != '\0'; ++i) { - - // Don't go beyond maxRows - if (curRow - origRow >= maxRows - 1) { - break; - } - - // Allocate memory for next list link - if (list_pointer == NULL) { - list_pointer = malloc(sizeof(struct charAttr)); - list_head = list_pointer; - } else { - list_pointer->next = malloc(sizeof(struct charAttr)); - list_pointer = list_pointer->next; - } - - // Get character's byte-length and store character. - if (mblen(&string[i], 4) > 0) { - list_pointer->source = malloc(mblen(&string[i], 4) + 1); - strncpy(list_pointer->source, &string[i], mblen(&string[i], 4)); - list_pointer->source[mblen(&string[i], 4)] = '\0'; - i += (mblen(&string[i], 4) - 1); - } else { - fprintf(stderr, "Unknown character encountered. Quitting.\n"); - nmsterm_restore_terminal(); - return 0; - } - - // Set flag if we have a whitespace character - if (strlen(list_pointer->source) == 1 && isspace(list_pointer->source[0])) - list_pointer->is_space = 1; - else - list_pointer->is_space = 0; - - // Set initial mask chharacter - list_pointer->mask = maskCharTable[rand() % MASK_CHAR_COUNT]; - - // Set reveal time - list_pointer->time = rand() % 5000; - - // Set character column width - wchar_t widec[sizeof(list_pointer->source)] = {}; - mbstowcs(widec, list_pointer->source, sizeof(list_pointer->source)); - list_pointer->width = wcwidth(*widec); - - // Set next node to null - list_pointer->next = NULL; - - // Track row count - if (string[i] == '\n' || (curCol += list_pointer->width) > maxCols) { - curCol = 0; - curRow++; - if (curRow == maxRows + 1 && origRow > 0) { - origRow--; - curRow--; - } - } - } - - // Print mask characters with 'type effect' - for (list_pointer = list_head; list_pointer != NULL; list_pointer = list_pointer->next) { - - // Print mask character (or space) - if (list_pointer->is_space) { - nmsterm_print_string(list_pointer->source); - continue; - } - - // print mask character - nmsterm_print_string(list_pointer->mask); - if (list_pointer->width == 2) { - nmsterm_print_string(maskCharTable[rand() % MASK_CHAR_COUNT]); - } - - // flush output and sleep - nmsterm_refresh(); - nms_sleep(TYPE_EFFECT_SPEED); - } - - // Flush any input up to this point - nmsterm_clear_input(); - - // If autoDecrypt flag is set, we sleep. Otherwise require user to - // press a key to continue. - if (autoDecrypt) - sleep(1); - else - nmsterm_get_char(); - - // Jumble loop - for (i = 0; i < (JUMBLE_SECONDS * 1000) / JUMBLE_LOOP_SPEED; ++i) { - - // Move cursor to start position - nmsterm_move_cursor(origRow, origCol); - - // Print new mask for all characters - for (list_pointer = list_head; list_pointer != NULL; list_pointer = list_pointer->next) { - - // Print mask character (or space) - if (list_pointer->is_space) { - nmsterm_print_string(list_pointer->source); - continue; - } - - // print new mask character - nmsterm_print_string(maskCharTable[rand() % MASK_CHAR_COUNT]); - if (list_pointer->width == 2) { - nmsterm_print_string(maskCharTable[rand() % MASK_CHAR_COUNT]); - } - } - - // flush output and sleep - nmsterm_refresh(); - nms_sleep(JUMBLE_LOOP_SPEED); - } - - // Reveal loop - while (!revealed) { - - // Move cursor to start position - nmsterm_move_cursor(origRow, origCol); - - // Set revealed flag - revealed = 1; - - for (list_pointer = list_head; list_pointer != NULL; list_pointer = list_pointer->next) { - - // Print mask character (or space) - if (list_pointer->is_space) { - nmsterm_print_string(list_pointer->source); - continue; - } - - // If we still have time before the char is revealed, display the mask - if (list_pointer->time > 0) { - - // Change the mask randomly - if (list_pointer->time < 500) { - if (rand() % 3 == 0) { - list_pointer->mask = maskCharTable[rand() % MASK_CHAR_COUNT]; - } - } else { - if (rand() % 10 == 0) { - list_pointer->mask = maskCharTable[rand() % MASK_CHAR_COUNT]; - } - } - - // Print mask - nmsterm_print_string(list_pointer->mask); - - // Decrement reveal time - list_pointer->time -= REVEAL_LOOP_SPEED; - - // Unset revealed flag - revealed = 0; - } else { - - // print source character - nmsterm_print_reveal_string(list_pointer->source, colorOn); - } - } - - // flush output and sleep - nmsterm_refresh(); - nms_sleep(REVEAL_LOOP_SPEED); - } - - // Flush any input up to this point - nmsterm_clear_input(); - - // Check if user must select from a set of options - if (returnOpts != NULL && strlen(returnOpts) > 0) { - - // Position cursor if necessary - if (inputPositionY >= 0 && inputPositionX >= 0) { - nmsterm_move_cursor(inputPositionY, inputPositionX); - } - - nmsterm_show_cursor(); - - // Get and validate user selection - while (strchr(returnOpts, ret = nmsterm_get_char()) == NULL) { - nmsterm_beep(); - } - - } - - // User must press a key to continue when clearSrc is set - // without returnOpts - else if (nmsterm_get_clearscr()) { - nmsterm_get_char(); - } - - // Restore terminal - nmsterm_restore_terminal(); - - // Freeing the list. - list_pointer = list_head; - while (list_pointer != NULL) { - list_temp = list_pointer; - list_pointer = list_pointer->next; - free(list_temp->source); - free(list_temp); - } - - return ret; -} - -/* - * nms_set_foreground_color() sets the foreground color of the unencrypted - * characters as they are revealed to the color indicated by the 'color' - * argument. Valid arguments are "white", "yellow", "magenta", "blue", - * "green", "red", and "cyan". This function will default to blue if - * passed an invalid color. No value is returned. - */ -void nms_set_foregroundcolor(char *color) { - nmsterm_set_foregroundcolor(color); -} - -/* - * nms_set_return_opts() takes a character sting and copies it to the - * returnOpts setting used by nms_exec(). - */ -void nms_set_return_opts(char *opts) { - returnOpts = realloc(returnOpts, strlen(opts) + 1); - strcpy(returnOpts, opts); -} - -/* - * nms_set_auto_decrypt() sets the autoDecrypt flag according to the - * true/false value of the 'setting' argument. - */ -void nms_set_auto_decrypt(int setting) { - if (setting) - autoDecrypt = 1; - else - autoDecrypt = 0; -} - -/* - * nms_set_clear_scr() sets the clearScr flag according to the - * true/false value of the 'setting' argument. - */ -void nms_set_clearscr(int s) { - nmsterm_set_clearscr(s); -} - -/* - * nms_set_color() sets the colorOn flag according to the - * true/false value of the 'setting' argument. - */ -void nms_use_color(int setting) { - if (setting) - colorOn = 1; - else - colorOn = 0; -} - -/* - * nms_set_input_position() sets the desired coordinate of the cursor in - * the terminal when accepting user input after nms_exec() reveals the - * unencrypted characters. - */ -void nms_set_input_position(int x, int y) { - if (x >= 0 && y >= 0) { - inputPositionX = x; - inputPositionY = y; - } -} - -/* - * nms_sleep() sleeps for the number of miliseconds indicated by 't'. - */ -static void nms_sleep(int t) { - struct timespec ts; - - ts.tv_sec = t / 1000; - ts.tv_nsec = (t % 1000) * 1000000; - - nanosleep(&ts, NULL); + return 0; } diff --git a/src/nms.h b/src/nms.h deleted file mode 100644 index ab3164c..0000000 --- a/src/nms.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2017 Brian Barto - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the MIT License. See LICENSE for more details. - */ - -#ifndef NMS_H -#define NMS_H 1 - -// Function prototypes -char nms_exec(char *); -void nms_set_foregroundcolor(char *); -void nms_set_return_opts(char *); -void nms_set_auto_decrypt(int); -void nms_set_clearscr(int); -void nms_use_color(int); -void nms_set_input_position(int, int); - -#endif diff --git a/src/nmseffect.c b/src/nmseffect.c new file mode 100644 index 0000000..c089c9c --- /dev/null +++ b/src/nmseffect.c @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2017 Brian Barto + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the MIT License. See LICENSE for more details. + */ + +#define _XOPEN_SOURCE 700 + +#include +#include +#include +#include +#include +#include +#include +#include +#include "nmseffect.h" +#include "nmsterm.h" + +// Program settings +#define TYPE_EFFECT_SPEED 4 // miliseconds per char +#define JUMBLE_SECONDS 2 // number of seconds for jumble effect +#define JUMBLE_LOOP_SPEED 35 // miliseconds between each jumble +#define REVEAL_LOOP_SPEED 50 // miliseconds between each reveal loop +#define MASK_CHAR_COUNT 218 // Total characters in maskCharTable[] array. + +// Character attribute structure, linked list. Keeps track of every +// character's attributes required for rendering and decryption effect. +struct charAttr { + char *source; + char *mask; + int width; + int is_space; + int time; + struct charAttr *next; +}; + +// Static function prototypes +static void nmseffect_sleep(int); + +// NMS settings +static char *returnOpts = NULL; // Return option setting +static int autoDecrypt = 0; // Auto-decrypt flag +static int colorOn = 1; // Terminal color flag +static int inputPositionX = -1; // X coordinate for input position +static int inputPositionY = -1; // Y coordinate for input position + +// Character table representing the character set know as CP437 used by +// the original IBM PC - https://en.wikipedia.org/wiki/Code_page_437 +static char *maskCharTable[] = { + "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", "~", + ".", "/", ":", ";", "<", "=", ">", "?", "[", "\\", "]", "_", "{", "}", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", + "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "\xc3\x87", "\xc3\xbc", "\xc3\xa9", "\xc3\xa2", "\xc3\xa4", "\xc3\xa0", + "\xc3\xa5", "\xc3\xa7", "\xc3\xaa", "\xc3\xab", "\xc3\xa8", "\xc3\xaf", + "\xc3\xae", "\xc3\xac", "\xc3\x84", "\xc3\x85", "\xc3\x89", "\xc3\xa6", + "\xc3\x86", "\xc3\xb4", "\xc3\xb6", "\xc3\xb2", "\xc3\xbb", "\xc3\xb9", + "\xc3\xbf", "\xc3\x96", "\xc3\x9c", "\xc2\xa2", "\xc2\xa3", "\xc2\xa5", + "\xc6\x92", "\xc3\xa1", "\xc3\xad", "\xc3\xb3", "\xc3\xba", "\xc3\xb1", + "\xc3\x91", "\xc2\xaa", "\xc2\xba", "\xc2\xbf", "\xc2\xac", "\xc2\xbd", + "\xc2\xbc", "\xc2\xa1", "\xc2\xab", "\xc2\xbb", "\xce\xb1", "\xc3\x9f", + "\xce\x93", "\xcf\x80", "\xce\xa3", "\xcf\x83", "\xc2\xb5", "\xcf\x84", + "\xce\xa6", "\xce\x98", "\xce\xa9", "\xce\xb4", "\xcf\x86", "\xce\xb5", + "\xc2\xb1", "\xc3\xb7", "\xc2\xb0", "\xc2\xb7", "\xc2\xb2", "\xc2\xb6", + "\xe2\x8c\x90", "\xe2\x82\xa7", "\xe2\x96\x91", "\xe2\x96\x92", + "\xe2\x96\x93", "\xe2\x94\x82", "\xe2\x94\xa4", "\xe2\x95\xa1", + "\xe2\x95\xa2", "\xe2\x95\x96", "\xe2\x95\x95", "\xe2\x95\xa3", + "\xe2\x95\x91", "\xe2\x95\x97", "\xe2\x95\x9d", "\xe2\x95\x9c", + "\xe2\x95\x9b", "\xe2\x94\x90", "\xe2\x94\x94", "\xe2\x94\xb4", + "\xe2\x94\xac", "\xe2\x94\x9c", "\xe2\x94\x80", "\xe2\x94\xbc", + "\xe2\x95\x9e", "\xe2\x95\x9f", "\xe2\x95\x9a", "\xe2\x95\x94", + "\xe2\x95\xa9", "\xe2\x95\xa6", "\xe2\x95\xa0", "\xe2\x95\x90", + "\xe2\x95\xac", "\xe2\x95\xa7", "\xe2\x95\xa8", "\xe2\x95\xa4", + "\xe2\x95\xa7", "\xe2\x95\x99", "\xe2\x95\x98", "\xe2\x95\x92", + "\xe2\x95\x93", "\xe2\x95\xab", "\xe2\x95\xaa", "\xe2\x94\x98", + "\xe2\x94\x8c", "\xe2\x96\x88", "\xe2\x96\x84", "\xe2\x96\x8c", + "\xe2\x96\x90", "\xe2\x96\x80", "\xe2\x88\x9e", "\xe2\x88\xa9", + "\xe2\x89\xa1", "\xe2\x89\xa5", "\xe2\x89\xa4", "\xe2\x8c\xa0", + "\xe2\x8c\xa1", "\xe2\x89\x88", "\xe2\x88\x99", "\xe2\x88\x9a", + "\xe2\x81\xbf", "\xe2\x96\xa0" +}; + +/* + * nmseffect_exec() - This function is passed a pointer to a character string + * and displays the contents of the string in a way that mimicks the + * "decrypting text" effect in the 1992 movie Sneakers. It returns the + * last character pressed by the user. + */ +char nmseffect_exec(char *string) { + struct charAttr *list_pointer = NULL; + struct charAttr *list_head = NULL; + struct charAttr *list_temp = NULL; + int i, revealed = 0; + int maxRows, maxCols, curRow, curCol, origRow = 0, origCol = 0; + char ret = 0; + + // Error if we have an empty string. + if (string == NULL || string[0] == '\0') { + fprintf(stderr, "Error. Empty string.\n"); + return 0; + } + + // Reassociate STDIN to the terminal is needed + if (!isatty(STDIN_FILENO) && !freopen ("/dev/tty", "r", stdin)) { + fprintf(stderr, "Error. Can't associate STDIN with terminal.\n"); + return 0; + } + + // Needed for UTF-8 support + setlocale(LC_ALL, ""); + + // Initialize terminal + nmsterm_init_terminal(); + + if (!nmsterm_get_clearscr()) { + // Get current row position + origRow = nmsterm_get_cursor_row(); + + // nms_get_cursor_row() may display output in some terminals. So + // we need to reposition the cursor to the start of the row. + nmsterm_move_cursor(origRow, 0); + } + + // Get terminal window rows/cols + maxRows = nmsterm_get_rows(); + maxCols = nmsterm_get_cols(); + + // Seed my random number generator with the current time + srand(time(NULL)); + + // Assign current row/col positions + curRow = origRow; + curCol = origCol; + + // Processing input + for (i = 0; string[i] != '\0'; ++i) { + + // Don't go beyond maxRows + if (curRow - origRow >= maxRows - 1) { + break; + } + + // Allocate memory for next list link + if (list_pointer == NULL) { + list_pointer = malloc(sizeof(struct charAttr)); + list_head = list_pointer; + } else { + list_pointer->next = malloc(sizeof(struct charAttr)); + list_pointer = list_pointer->next; + } + + // Get character's byte-length and store character. + if (mblen(&string[i], 4) > 0) { + list_pointer->source = malloc(mblen(&string[i], 4) + 1); + strncpy(list_pointer->source, &string[i], mblen(&string[i], 4)); + list_pointer->source[mblen(&string[i], 4)] = '\0'; + i += (mblen(&string[i], 4) - 1); + } else { + fprintf(stderr, "Unknown character encountered. Quitting.\n"); + nmsterm_restore_terminal(); + return 0; + } + + // Set flag if we have a whitespace character + if (strlen(list_pointer->source) == 1 && isspace(list_pointer->source[0])) + list_pointer->is_space = 1; + else + list_pointer->is_space = 0; + + // Set initial mask chharacter + list_pointer->mask = maskCharTable[rand() % MASK_CHAR_COUNT]; + + // Set reveal time + list_pointer->time = rand() % 5000; + + // Set character column width + wchar_t widec[sizeof(list_pointer->source)] = {}; + mbstowcs(widec, list_pointer->source, sizeof(list_pointer->source)); + list_pointer->width = wcwidth(*widec); + + // Set next node to null + list_pointer->next = NULL; + + // Track row count + if (string[i] == '\n' || (curCol += list_pointer->width) > maxCols) { + curCol = 0; + curRow++; + if (curRow == maxRows + 1 && origRow > 0) { + origRow--; + curRow--; + } + } + } + + // Print mask characters with 'type effect' + for (list_pointer = list_head; list_pointer != NULL; list_pointer = list_pointer->next) { + + // Print mask character (or space) + if (list_pointer->is_space) { + nmsterm_print_string(list_pointer->source); + continue; + } + + // print mask character + nmsterm_print_string(list_pointer->mask); + if (list_pointer->width == 2) { + nmsterm_print_string(maskCharTable[rand() % MASK_CHAR_COUNT]); + } + + // flush output and sleep + nmsterm_refresh(); + nmseffect_sleep(TYPE_EFFECT_SPEED); + } + + // Flush any input up to this point + nmsterm_clear_input(); + + // If autoDecrypt flag is set, we sleep. Otherwise require user to + // press a key to continue. + if (autoDecrypt) + sleep(1); + else + nmsterm_get_char(); + + // Jumble loop + for (i = 0; i < (JUMBLE_SECONDS * 1000) / JUMBLE_LOOP_SPEED; ++i) { + + // Move cursor to start position + nmsterm_move_cursor(origRow, origCol); + + // Print new mask for all characters + for (list_pointer = list_head; list_pointer != NULL; list_pointer = list_pointer->next) { + + // Print mask character (or space) + if (list_pointer->is_space) { + nmsterm_print_string(list_pointer->source); + continue; + } + + // print new mask character + nmsterm_print_string(maskCharTable[rand() % MASK_CHAR_COUNT]); + if (list_pointer->width == 2) { + nmsterm_print_string(maskCharTable[rand() % MASK_CHAR_COUNT]); + } + } + + // flush output and sleep + nmsterm_refresh(); + nmseffect_sleep(JUMBLE_LOOP_SPEED); + } + + // Reveal loop + while (!revealed) { + + // Move cursor to start position + nmsterm_move_cursor(origRow, origCol); + + // Set revealed flag + revealed = 1; + + for (list_pointer = list_head; list_pointer != NULL; list_pointer = list_pointer->next) { + + // Print mask character (or space) + if (list_pointer->is_space) { + nmsterm_print_string(list_pointer->source); + continue; + } + + // If we still have time before the char is revealed, display the mask + if (list_pointer->time > 0) { + + // Change the mask randomly + if (list_pointer->time < 500) { + if (rand() % 3 == 0) { + list_pointer->mask = maskCharTable[rand() % MASK_CHAR_COUNT]; + } + } else { + if (rand() % 10 == 0) { + list_pointer->mask = maskCharTable[rand() % MASK_CHAR_COUNT]; + } + } + + // Print mask + nmsterm_print_string(list_pointer->mask); + + // Decrement reveal time + list_pointer->time -= REVEAL_LOOP_SPEED; + + // Unset revealed flag + revealed = 0; + } else { + + // print source character + nmsterm_print_reveal_string(list_pointer->source, colorOn); + } + } + + // flush output and sleep + nmsterm_refresh(); + nmseffect_sleep(REVEAL_LOOP_SPEED); + } + + // Flush any input up to this point + nmsterm_clear_input(); + + // Check if user must select from a set of options + if (returnOpts != NULL && strlen(returnOpts) > 0) { + + // Position cursor if necessary + if (inputPositionY >= 0 && inputPositionX >= 0) { + nmsterm_move_cursor(inputPositionY, inputPositionX); + } + + nmsterm_show_cursor(); + + // Get and validate user selection + while (strchr(returnOpts, ret = nmsterm_get_char()) == NULL) { + nmsterm_beep(); + } + + } + + // User must press a key to continue when clearSrc is set + // without returnOpts + else if (nmsterm_get_clearscr()) { + nmsterm_get_char(); + } + + // Restore terminal + nmsterm_restore_terminal(); + + // Freeing the list. + list_pointer = list_head; + while (list_pointer != NULL) { + list_temp = list_pointer; + list_pointer = list_pointer->next; + free(list_temp->source); + free(list_temp); + } + + return ret; +} + +/* + * nmseffect_set_foreground_color() sets the foreground color of the unencrypted + * characters as they are revealed to the color indicated by the 'color' + * argument. Valid arguments are "white", "yellow", "magenta", "blue", + * "green", "red", and "cyan". This function will default to blue if + * passed an invalid color. No value is returned. + */ +void nmseffect_set_foregroundcolor(char *color) { + nmsterm_set_foregroundcolor(color); +} + +/* + * nmseffect_set_return_opts() takes a character sting and copies it to the + * returnOpts setting used by nms_exec(). + */ +void nmseffect_set_return_opts(char *opts) { + returnOpts = realloc(returnOpts, strlen(opts) + 1); + strcpy(returnOpts, opts); +} + +/* + * nmseffect_set_auto_decrypt() sets the autoDecrypt flag according to the + * true/false value of the 'setting' argument. + */ +void nmseffect_set_auto_decrypt(int setting) { + if (setting) + autoDecrypt = 1; + else + autoDecrypt = 0; +} + +/* + * nmseffect_set_clearscr() sets the clearScr flag according to the + * true/false value of the 'setting' argument. + */ +void nmseffect_set_clearscr(int s) { + nmsterm_set_clearscr(s); +} + +/* + * nmseffect_set_color() sets the colorOn flag according to the + * true/false value of the 'setting' argument. + */ +void nmseffect_set_color(int setting) { + if (setting) + colorOn = 1; + else + colorOn = 0; +} + +/* + * nmseffect_set_input_position() sets the desired coordinate of the cursor in + * the terminal when accepting user input after nms_exec() reveals the + * unencrypted characters. + */ +void nmseffect_set_input_position(int x, int y) { + if (x >= 0 && y >= 0) { + inputPositionX = x; + inputPositionY = y; + } +} + +/* + * nmseffect_sleep() sleeps for the number of miliseconds indicated by 't'. + */ +static void nmseffect_sleep(int t) { + struct timespec ts; + + ts.tv_sec = t / 1000; + ts.tv_nsec = (t % 1000) * 1000000; + + nanosleep(&ts, NULL); +} diff --git a/src/nmseffect.h b/src/nmseffect.h new file mode 100644 index 0000000..bb03225 --- /dev/null +++ b/src/nmseffect.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2017 Brian Barto + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the MIT License. See LICENSE for more details. + */ + +#ifndef NMSEFFECT_H +#define NMSEFFECT_H 1 + +// Function prototypes +char nmseffect_exec(char *); +void nmseffect_set_foregroundcolor(char *); +void nmseffect_set_return_opts(char *); +void nmseffect_set_auto_decrypt(int); +void nmseffect_set_clearscr(int); +void nmseffect_use_color(int); +void nmseffect_set_input_position(int, int); + +#endif diff --git a/src/sneakers.c b/src/sneakers.c index 95faf05..de52dd7 100644 --- a/src/sneakers.c +++ b/src/sneakers.c @@ -9,7 +9,7 @@ #include #include #include -#include "nms.h" +#include "nmseffect.h" #include "nmsterm.h" int main(void) { @@ -160,12 +160,12 @@ int main(void) { strcat(display, foot2Center); // Settings - nms_set_input_position(((termCols - strlen(foot2Center)) / 2) + 2, 18); - nms_set_return_opts("123456"); - nms_set_clearscr(1); + nmseffect_set_input_position(((termCols - strlen(foot2Center)) / 2) + 2, 18); + nmseffect_set_return_opts("123456"); + nmseffect_set_clearscr(1); // Execut effect - input = nms_exec(display); + input = nmseffect_exec(display); // Print user choice printf("You chose %c\n", input);