diff --git a/Makefile b/Makefile index 3798818..ef09b34 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ CFLAGS ?= -Wextra -Wall -O2 .PHONY: all install uninstall clean -nms: $(OBJ)/nmscharset.o $(OBJ)/nmstermio.o $(OBJ)/nmseffect.o $(OBJ)/nms.o | $(BIN) +nms: $(OBJ)/input.o $(OBJ)/error.o $(OBJ)/nmscharset.o $(OBJ)/nmstermio.o $(OBJ)/nmseffect.o $(OBJ)/nms.o | $(BIN) $(CC) $(CFLAGS) -o $(BIN)/$@ $^ sneakers: $(OBJ)/nmscharset.o $(OBJ)/nmstermio.o $(OBJ)/nmseffect.o $(OBJ)/sneakers.o | $(BIN) diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..b3a8e88 --- /dev/null +++ b/src/error.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 Brian Barto + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GPL License. See LICENSE for more details. + */ + +#include +#include +#include + +#define ERROR_LIST_MAX 20 +#define ERROR_LENGTH_MAX 100 + +static char error_stack[ERROR_LIST_MAX][ERROR_LENGTH_MAX]; +static int N = 0; + +void error_log(char *error, ...) +{ + va_list argList; + + if (N < ERROR_LIST_MAX) + { + va_start(argList, error); + vsnprintf(error_stack[N++], ERROR_LENGTH_MAX - 1, error, argList); + va_end(argList); + } +} + +void error_print(void) +{ + int i; + + for (i = N-1; i >= 0; --i) + { + fprintf(stderr, "%s ", error_stack[i]); + } + fprintf(stderr, "\n"); +} + +char *error_get(void) +{ + if (N > 0) + { + return error_stack[--N]; + } + else + { + return NULL; + } +} + +void error_clear(void) +{ + N = 0; +} \ No newline at end of file diff --git a/src/error.h b/src/error.h new file mode 100644 index 0000000..daeec2e --- /dev/null +++ b/src/error.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2017 Brian Barto + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GPL License. See LICENSE for more details. + */ + +#ifndef ERROR_H +#define ERROR_H 1 + +void error_log(char *, ...); +void error_print(void); +char *error_get(void); +void error_clear(void); + +#endif \ No newline at end of file diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..e93a9fe --- /dev/null +++ b/src/input.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2017 Brian Barto + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GPL License. See LICENSE for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "input.h" +#include "error.h" + +int input_get(unsigned char** dest, char *prompt) +{ + int r, input_len; + fd_set input_stream; + struct timeval timeout; + void *timeout_p; + + FD_ZERO(&input_stream); + input_len = 0; + + timeout.tv_sec = 10; + timeout.tv_usec = 0; + + if (isatty(STDIN_FILENO)) + { + timeout_p = NULL; + if (prompt != NULL) + { + printf("%s", prompt); + fflush(stdout); + } + } + else + { + timeout_p = &timeout; + } + + FD_SET(STDIN_FILENO, &input_stream); + r = select(FD_SETSIZE, &input_stream, NULL, NULL, timeout_p); + if (r < 0) + { + error_log("Error while waiting for input data. Errno: %i", errno); + return -1; + } + if (r > 0) + { + r = ioctl(STDIN_FILENO, FIONREAD, &input_len); + if (r < 0) + { + error_log("Could not determine length of input. Errno: %i", errno); + return -1; + } + if (input_len > 0) + { + *dest = malloc(input_len); + if (*dest == NULL) + { + error_log("Memory allocation error."); + return -1; + } + r = read(STDIN_FILENO, *dest, input_len); + if (r < 0) + { + error_log("Input read error. Errno: %i", errno); + return -1; + } + } + } + + FD_CLR(STDIN_FILENO, &input_stream); + + return input_len; +} + +int input_get_str(char** dest, char *prompt) +{ + int r, i, input_len; + unsigned char *input; + + r = input_get(&input, prompt); + if (r < 0) + { + error_log("Could not get input."); + return -1; + } + + if (r > 0) + { + if (input[r - 1] == '\n') + { + --r; + if (r > 0 && input[r - 1] == '\r') + { + --r; + } + } + } + + if (r == 0) + { + error_log("No input provided."); + return -1; + } + + input_len = r; + + *dest = malloc(input_len + 1); + if (*dest == NULL) + { + error_log("Memory allocation error."); + return -1; + } + + memset(*dest, 0, input_len + 1); + + for (i = 0; i < input_len; ++i) + { + if (isascii(input[i])) + { + (*dest)[i] = input[i]; + } + else + { + error_log("Input contains non-ascii characters."); + return -1; + } + } + + free(input); + + return input_len; +} + +int input_get_from_pipe(unsigned char** dest) +{ + int r; + + if (isatty(STDIN_FILENO)) + { + error_log("Input data from a piped or redirected source is required."); + return -1; + } + + r = input_get(dest, NULL); + if (r < 0) + { + error_log("Could not get input."); + return -1; + } + if (r == 0) + { + error_log("No input provided."); + return -1; + } + + return r; +} \ No newline at end of file diff --git a/src/input.h b/src/input.h new file mode 100644 index 0000000..c774ca5 --- /dev/null +++ b/src/input.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2017 Brian Barto + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GPL License. See LICENSE for more details. + */ + +#ifndef INPUT_H +#define INPUT_H 1 + +int input_get(unsigned char** dest, char *prompt); +int input_get_str(char** dest, char *prompt); +int input_get_from_pipe(unsigned char** dest); + +#endif \ No newline at end of file diff --git a/src/nms.c b/src/nms.c index 8a57efa..c7c1a44 100644 --- a/src/nms.c +++ b/src/nms.c @@ -10,16 +10,17 @@ #include #include #include "nmseffect.h" +#include "input.h" +#include "error.h" #define VERSION "0.3.3" -#define INITIAL_CAPACITY 50 -#define INPUT_GROWTH_FACTOR 2 int main(int argc, char *argv[]) { - int c, o, i, inCapacity = INITIAL_CAPACITY; - char *input = NULL; + int r, o; + unsigned char *input; + + input = NULL; - // Processing command arguments while ((o = getopt(argc, argv, "f:ascv")) != -1) { switch (o) { case 'f': @@ -45,32 +46,24 @@ int main(int argc, char *argv[]) { return 1; } } - - // Allocate memory for our input buffer - if ((input = malloc(inCapacity + 1)) == NULL) { - fprintf (stderr, "Memory Allocation Error! Quitting...\n"); - return 1; + + r = input_get(&input, "Enter input: "); + if (r < 0) + { + error_log("Could not get input."); + error_print(); + return EXIT_FAILURE; + } + else if (r == 0) + { + error_log("Input is empty."); + error_print(); + return EXIT_FAILURE; } - // Geting input - for (i = 0; (c = getchar()) != EOF; ++i) { - if (i >= inCapacity) { - inCapacity *= INPUT_GROWTH_FACTOR; - input = realloc(input, inCapacity + 1); - if (input == NULL) { - fprintf (stderr, "Memory Allocation Error! Quitting...\n"); - return 1; - } - } - input[i] = c; - input[i+1] = '\0'; - } + r = nmseffect_exec(input, r); - // Execute effect - c = nmseffect_exec(input); - - // Free allocated memory (not necessary here, but good practice) free(input); - return 0; + return EXIT_SUCCESS; } diff --git a/src/nmseffect.c b/src/nmseffect.c index b0eeb06..b86237c 100644 --- a/src/nmseffect.c +++ b/src/nmseffect.c @@ -58,19 +58,13 @@ static void nmseffect_sleep(int); * string that is provided as an argument. It returns the last character * pressed by the user. */ -char nmseffect_exec(char *string) { +char nmseffect_exec(unsigned char *string, int string_len) { struct charAttr *list_pointer = NULL; struct charAttr *list_head = NULL; struct charAttr *list_temp = NULL; - int i, revealed = 0; + int i, l, 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 if needed if (!isatty(STDIN_FILENO) && !freopen ("/dev/tty", "r", stdin)) { @@ -108,8 +102,8 @@ char nmseffect_exec(char *string) { curCol = origCol; // Processing input - for (i = 0; string[i] != '\0'; ++i) { - + for (i = 0; i < string_len; ++i) { + // Don't go beyond maxRows if (curRow - origRow >= maxRows - 1) { break; @@ -125,11 +119,12 @@ char nmseffect_exec(char *string) { } // 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); + l = mblen((char *)&string[i], 4); + if (l > 0) { + list_pointer->source = malloc(l + 1); + memcpy(list_pointer->source, &string[i], l); + list_pointer->source[l] = '\0'; + i += (l - 1); } else { fprintf(stderr, "Unknown character encountered. Quitting.\n"); nmstermio_restore_terminal(); diff --git a/src/nmseffect.h b/src/nmseffect.h index 5c04c3d..69e93b4 100644 --- a/src/nmseffect.h +++ b/src/nmseffect.h @@ -9,7 +9,7 @@ #define NMSEFFECT_H 1 // Function prototypes -char nmseffect_exec(char *); +char nmseffect_exec(unsigned char *, int string_len); void nmseffect_set_foregroundcolor(char *); void nmseffect_set_returnopts(char *); void nmseffect_set_autodecrypt(int);