From 986d158bfe01d296a88c4c52f99f48313e6a4783 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Mon, 7 May 2012 01:57:03 +0200 Subject: Port of Truncater to C --- ponysaytruncater.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 ponysaytruncater.c (limited to 'ponysaytruncater.c') diff --git a/ponysaytruncater.c b/ponysaytruncater.c new file mode 100644 index 0000000..9c7191e --- /dev/null +++ b/ponysaytruncater.c @@ -0,0 +1,174 @@ +/** + * ponysaytruncater — Output truncater used by ponysay to stop large ponies from being printed badly. + * + * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + * See COPYING for details + */ +#include + + +#define String char* +#define boolean char + +#define true 1 +#define false 0 + + + +/** + * Stdin file descriptor ID + */ +#define STDIN 0 + + + +/** + * The number of columns on the current line + */ +static int x = 0; + +/** + * Escape sequence state + */ +static int esc = 0; + +/** + * Last bytes as written + */ +static boolean ok = true; + + + + +void write(char b, int width); +int toInt(String string); + + + +/** + *

Mane method!

+ *

+ * The only argument, in addition to the executed file, + * should be the width of the terminal which you get by + * adding `tput cols || echo 0` as and argument. + *

+ * + * @param argc The number of startup arguments + * @param argv The startup arguments, the first is the file itself + * + * @author Mattias Andrée, maandree@kth.se + */ +void main(int argc, String* argv) +{ + int width = 0; + if (argc > 1) + width = toInt(*(argv + 1)); + + char b = 0; + + if (width > 15) //sanity + while (read(STDIN, &b, 1)) + write(b, width); + else + while (read(STDIN, &b, 1)) + printf("%c", b); +} + + +/** + * Writes a character to stdout, iff it fits within the terminal + * + * @param b The character (byte) to write + * @param width The width of the terminal + */ +void write(char b, int width) +{ + int i; + char nx; + + if (esc == 0) + { + if (b == '\n') + { + if (x >= width) + { + // Reset background colour + write('\e', width); + write('[', width); + write('4', width); + write('9', width); + write('m', width); + } + x = -1; + } + else if (b == '\t') + { + // Tab to next pos ≡₈ 0 + nx = 8 - (x & 7); + for (i = 0; i < nx; i++) + write(' ', width); + return; //(!) + } + else if (b == '\e') + esc = 1; + } + else if (esc == 1) + { + if (b == '[') esc = 2; //CSI ends with a letter, m is for colour + else if (b == ']') esc = 3; //OSI, OSI P is for palett editing in Linux VT + else esc = 10; //Nothing to see here, move along + } + else if (esc == 2) + { + if ((('a' <= b) && (b <= 'z')) || (('A' <= b) && (b <= 'Z'))) + esc = 10; + } + else if ((esc == 3) && (b == 'P')) + { + esc = ~0; + } + else if (esc < 0) + { + esc--; + if (esc == ~7) + esc = 10; + } + else + esc = 10; + + if ( // Can be printed: + (x < width) || // within bounds ∨ + (esc != 0) || // ∨ escape sequence ∨ + (ok && ((b & 0xC0) == 0x80))) // ∨ last with printed ∧ not first byte in character + { + printf("%c", b); + if ((esc == 0) && ((b & 0xC0) != 0x80)) // Count up columns of not in escape sequnce and + x++; // the byte is not the first byte in the character + ok = true; + } + else + ok = false; + + if (esc == 10) + esc = 0; +} + + +/** + * Converts a string to an integer + * + * @param string The string to convert + * @return The integer represented by the string + */ +int toInt(String string) +{ + int rc = 0; + String str = string; + char c = 0; + + while ((c = *str++) != 0) + rc = (rc << 1) + (rc << 3) - (c & 15); + + return -rc; +} + -- cgit