diff options
author | Josias <justjosias@tutanota.com> | 2020-04-22 13:37:23 +0300 |
---|---|---|
committer | Josias <justjosias@tutanota.com> | 2020-04-22 13:37:23 +0300 |
commit | f79b58016e1757164e5e3f3e4d7a0b9533981e8d (patch) | |
tree | d9a8f5f77d4bce7955bb9ef8dfdcb87a6e059cb8 | |
parent | 3140ef2a51699ebb8399bb94962148b87c4ef8cf (diff) |
Use enTangleD for literate programming
-rw-r--r-- | Makefile | 14 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | rccat.c | 42 | ||||
-rw-r--r-- | rccat.md | 197 |
4 files changed, 216 insertions, 45 deletions
@@ -2,25 +2,13 @@ PREFIX ?= /usr/local INSTALL ?= install INSTALL_PROGRAM ?= $(INSTALL) -ifneq "$(DESTDIR)" "" - PREFIX = $(DESTDIR) -endif - all: build - build: $(CC) -o rccat rccat.c -run: - ./rccat clean: $(RM) rccat -install: rccat - #$(PRE_INSTALL) +install: $(INSTALL_PROGRAM) -d $(PREFIX)/bin - - #$(NORMAL_INSTALL) $(INSTALL_PROGRAM) -m755 rccat $(PREFIX)/bin - uninstall: - #$(NORMAL_UNINSTALL) $(RM) $(PREFIX)/bin/rccat @@ -2,13 +2,17 @@ A cat-like tool to make printing files into the terminal a little more interesting. +I have now revised the program with literate programming with [enTangleD](https://entangled.github.io). It has been an interesting experience, and now you can easily read the source code of the program in [rccat.md](rccat.md). + +The generated files are also pushed (`rccat.c` and `Makefile`), so you don't need enTangleD to be able to use it. + ## Usage First compile with `make`. Then use it like, `rccat FILENAME`. -## Roadmap +## TODO - [x] Support multiple files - [ ] Implement basic options (including -v and -h) @@ -16,4 +20,4 @@ Then use it like, `rccat FILENAME`. ## Contributing -This is not a serious project, and I am using this to help me to learn C. But corrections for my errors are welcome. +This is not a serious project, and I am using this to help me to learn C (and now literate programming). But corrections for my errors are welcome. @@ -3,7 +3,7 @@ #include <string.h> #include <time.h> #include <unistd.h> - +#define BUF_SIZE 10 #define KNRM "\x1B[0m" #define KRED "\x1B[31m" #define KGRN "\x1B[32m" @@ -15,19 +15,13 @@ const char *colors[7] = {KNRM, KRED, KGRN, KYEL, KBLU, KMAG, KCYN}; -typedef struct config { - int end; -} config; - int lastcolor = 0; void printColors(char *text) { - // If the output is piped, the colors don't make much sense if (!(isatty(STDOUT_FILENO))) { printf("%s", text); return; } - // Normal operation if (text) { for (int i = 0; i < strlen(text); ++i) { int color = 0; @@ -35,48 +29,36 @@ void printColors(char *text) color = rand() % 6; } while (color == lastcolor); lastcolor = color; - // for the future - //if (text[i] == '\n') - // printf("$"); printf("%s%c", colors[color], text[i]); } } - printf("%s", KWHT); // reset to default colors + printf("%s", KWHT); } - -const int BUF_SIZE = 10; - int main(int argc, char *argv[]) { srand(time(NULL)); - - char buffer[10] = {""}; + char buffer[BUF_SIZE] = {""}; for (int i = 0; i < argc; ++i) { if (strcmp(argv[i], "-") == 0 || argc == 1) { - while (fgets(buffer, BUF_SIZE, stdin) != NULL) { - printColors(buffer); - } - clearerr(stdin); + } else if (i >= 1) { FILE *fp; fp = fopen(argv[i], "r"); - - if (fp) { - size_t got; - while ((got = fread(buffer, 1, BUF_SIZE -1, fp))) { - buffer[got] = '\0'; + if (!(fp)) { + fprintf(stderr, "rccat: %s: no such file or directory.\n", argv[i]); + } + size_t got; + while ((got = fread(buffer, 1, BUF_SIZE -1, fp))) { + buffer[got] = '\0'; printColors(buffer); } printf("%s", KWHT); if (ferror(fp)) fprintf(stderr, "Error: can't read %s\n", argv[1]); - fclose(fp); - } else { - fprintf(stderr, "rccat: %s: no such file or directory.\n", argv[1]); - } + fclose(fp); } } - return 0; + return EXIT_SUCCESS; } diff --git a/rccat.md b/rccat.md new file mode 100644 index 0000000..69520b8 --- /dev/null +++ b/rccat.md @@ -0,0 +1,197 @@ +# rccat + +This program will provide a `cat`-like utility for printing text from a file to `stdout`. Except that output will be randomly colorized. + +Thus the name: Randomly Colored Cat. + +Here is the basic structure of the program: + +``` {.c file=rccat.c} +<<includes>> +<<constants>> + +<<colors-function>> +<<main-function>> +``` + +Now for the includes: + +``` {.c #includes} +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +``` + +`unistd.h`, `stdlib.h`, and `time.h` are required for randomness, `stdio.h` for `printf`, and `string.h` for `strcmp` and `strlen`. + +Some constants that will be the same throughout the program: +``` {.c #constants} +#define BUF_SIZE 10 +<<colors>> +``` + +Now the colors: + +``` {.c #colors} +#define KNRM "\x1B[0m" +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KYEL "\x1B[33m" +#define KBLU "\x1B[34m" +#define KMAG "\x1B[35m" +#define KCYN "\x1B[36m" +#define KWHT "\x1B[37m" + +const char *colors[7] = {KNRM, KRED, KGRN, KYEL, KBLU, KMAG, KCYN}; +``` + +These are all the codes for the colors we want, and an array to order them nicely to randomly index them. + +## Print Colors + +``` {.c #colors-function} +int lastcolor = 0; +void printColors(char *text) +{ + <<notty>> + if (text) { + <<normal>> + } + <<reset>> +} +``` + +If the output is piped (and thus isn't a tty), the colors don't make much sense. +``` {.c #notty} +if (!(isatty(STDOUT_FILENO))) { + printf("%s", text); + return; +} +``` + +Go through the text character by character and print it with a random color between 0 and 6 (the index of colors). It also makes sure that the color is not the same as the last one. +``` {.c #normal} +for (int i = 0; i < strlen(text); ++i) { + int color = 0; + do { + color = rand() % 6; + } while (color == lastcolor); + lastcolor = color; + printf("%s%c", colors[color], text[i]); +} +``` + +Now we have to reset the terminal to the normal colors. +``` {.c #reset} +printf("%s", KWHT); +``` + +## Main + +The main function that every C program must have. + +``` {.c #main-function} +int main(int argc, char *argv[]) +{ + <<main-body>> + + return EXIT_SUCCESS; +} +``` + +Initialize random and buffer, and loop through the arguments. +``` {.c #main-body} +srand(time(NULL)); +char buffer[BUF_SIZE] = {""}; + +for (int i = 0; i < argc; ++i) { + <<parse-arg>> +} +``` + +Determine whether or not the argument is `-`. If so, get the input from `stdin` instead of a file. In addition, it should not try to read the file from `argv[0]`, since that is itself. +``` {.c #parse-arg} +if (strcmp(argv[i], "-") == 0 || argc == 1) { + <<print-from-stdin>> +} else if (i >= 1) { + <<open-file>> + <<read-file>> + <<close-file>> +} +``` + +``` {.c #read-file} +size_t got; +while ((got = fread(buffer, 1, BUF_SIZE -1, fp))) { + buffer[got] = '\0'; + printColors(buffer); + } + printf("%s", KWHT); + if (ferror(fp)) + fprintf(stderr, "Error: can't read %s\n", argv[1]); +``` + +Prepare a file pointer and make sure the file exists. If not, write an error to `stderr`. +``` {.c #open-file} +FILE *fp; +fp = fopen(argv[i], "r"); +if (!(fp)) { + fprintf(stderr, "rccat: %s: no such file or directory.\n", argv[i]); +} +``` + +``` {.c #close-file} +fclose(fp); +``` + +## Building + +To compile with your C compiler directly, you can use `gcc -o rccat rccat.c`, but that isn't as useful as a Makefile. + +The complete Makefile: + +``` {.make file=Makefile} +PREFIX ?= /usr/local +INSTALL ?= install +INSTALL_PROGRAM ?= $(INSTALL) + +<<make-all>> +<<make-build>> +<<make-clean>> +<<make-install>> +<<make-uninstall>> +``` + +`PREFIX` determines where you want the program to be installed when `make install` is run. + +If you just want to run `make`, it automatically calls build. +``` {.make #make-all} +all: build +``` + +Compiling the program with your C compiler. +``` {.make #make-build} +build: + $(CC) -o rccat rccat.c +``` + +A simple way to delete the `rccat` file, and any other generated files (in the future). +``` {.make #make-clean} +clean: + $(RM) rccat +``` + +Install the program to `PREFIX` (as mentioned above). It first prepares the install and then copies over the file to `PREFIX/bin`. +``` {.make #make-install} +install: + $(INSTALL_PROGRAM) -d $(PREFIX)/bin + $(INSTALL_PROGRAM) -m755 rccat $(PREFIX)/bin +``` + +Uninstall the program from `PREFIX/bin`. +``` {.make #make-uninstall} +uninstall: + $(RM) $(PREFIX)/bin/rccat +``` |