ponysay/ponysaytruncater.c
2012-05-07 01:57:03 +02:00

174 lines
3.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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 <stdio.h>
#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);
/**
* <p>Mane method!</p>
* <p>
* The only argument, in addition to the executed file,
* should be the width of the terminal which you get by
* adding <code>`tput cols || echo 0`</code> as and argument.
* </p>
*
* @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;
}