2012-05-12 19:57:55 +02:00
|
|
|
|
/* ponysaytruncater
|
|
|
|
|
* Output truncater used by ponysay to stop
|
|
|
|
|
* large ponies from being printed badly.
|
2012-05-07 01:57:03 +02:00
|
|
|
|
*
|
2012-05-12 19:57:55 +02:00
|
|
|
|
* Licensed under WTFPL
|
2012-05-07 01:57:03 +02:00
|
|
|
|
* See COPYING for details
|
|
|
|
|
*/
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#define String char*
|
|
|
|
|
#define boolean char
|
|
|
|
|
#define true 1
|
|
|
|
|
#define false 0
|
|
|
|
|
|
2012-05-12 19:57:55 +02:00
|
|
|
|
/* Stdin file descriptor ID */
|
2012-05-07 01:57:03 +02:00
|
|
|
|
#define STDIN 0
|
|
|
|
|
|
2012-05-12 19:57:55 +02:00
|
|
|
|
/* The number of columns on the current line */
|
2012-05-07 01:57:03 +02:00
|
|
|
|
static int x = 0;
|
|
|
|
|
|
2012-05-12 19:57:55 +02:00
|
|
|
|
/* Escape sequence state */
|
2012-05-07 01:57:03 +02:00
|
|
|
|
static int esc = 0;
|
|
|
|
|
|
2012-05-12 19:57:55 +02:00
|
|
|
|
/* Last bytes as written */
|
2012-05-07 01:57:03 +02:00
|
|
|
|
static boolean ok = true;
|
|
|
|
|
|
|
|
|
|
void write(char b, int width);
|
|
|
|
|
int toInt(String string);
|
|
|
|
|
|
|
|
|
|
|
2012-05-12 19:57:55 +02:00
|
|
|
|
/* Mane method!
|
2012-05-07 01:57:03 +02:00
|
|
|
|
* 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.
|
2012-05-12 19:57:55 +02:00
|
|
|
|
*
|
2012-05-07 01:57:03 +02:00
|
|
|
|
* @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)
|
|
|
|
|
{
|
2012-05-12 19:57:55 +02:00
|
|
|
|
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);
|
2012-05-07 01:57:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-12 19:57:55 +02:00
|
|
|
|
/* Writes a character to stdout, iff it fits within the terminal
|
2012-05-07 01:57:03 +02:00
|
|
|
|
*
|
|
|
|
|
* @param b The character (byte) to write
|
|
|
|
|
* @param width The width of the terminal
|
|
|
|
|
*/
|
|
|
|
|
void write(char b, int width)
|
|
|
|
|
{
|
2012-05-12 19:57:55 +02:00
|
|
|
|
int i;
|
|
|
|
|
char nx;
|
|
|
|
|
|
|
|
|
|
if (esc == 0)
|
2012-05-07 01:57:03 +02:00
|
|
|
|
{
|
2012-05-12 19:57:55 +02:00
|
|
|
|
if (b == '\n')
|
2012-05-07 01:57:03 +02:00
|
|
|
|
{
|
2012-05-12 19:57:55 +02:00
|
|
|
|
if (x >= width)
|
2012-05-07 01:57:03 +02:00
|
|
|
|
{
|
2012-05-12 19:57:55 +02:00
|
|
|
|
/* Reset background colour */
|
|
|
|
|
write('\e', width);
|
|
|
|
|
write('[', width);
|
|
|
|
|
write('4', width);
|
|
|
|
|
write('9', width);
|
|
|
|
|
write('m', width);
|
2012-05-07 01:57:03 +02:00
|
|
|
|
}
|
2012-05-12 19:57:55 +02:00
|
|
|
|
x = -1;
|
2012-05-07 01:57:03 +02:00
|
|
|
|
}
|
2012-05-12 19:57:55 +02:00
|
|
|
|
else if (b == '\t')
|
2012-05-07 01:57:03 +02:00
|
|
|
|
{
|
2012-05-12 19:57:55 +02:00
|
|
|
|
/* Tab to next pos ≡₈ 0 */
|
|
|
|
|
nx = 8 - (x & 7);
|
|
|
|
|
for (i = 0; i < nx; i++)
|
|
|
|
|
write(' ', width);
|
|
|
|
|
return; /* (!) */
|
2012-05-07 01:57:03 +02:00
|
|
|
|
}
|
2012-05-12 19:57:55 +02:00
|
|
|
|
else if (b == '\e')
|
|
|
|
|
esc = 1;
|
2012-05-07 01:57:03 +02:00
|
|
|
|
}
|
2012-05-12 19:57:55 +02:00
|
|
|
|
else if (esc == 1)
|
2012-05-07 01:57:03 +02:00
|
|
|
|
{
|
2012-05-12 19:57:55 +02:00
|
|
|
|
/* CSI ends with a letter, m is for colour
|
|
|
|
|
OSI, OSI P is for palett editing in Linux VT */
|
|
|
|
|
if (b == '[') esc = 2;
|
|
|
|
|
else if (b == ']') esc = 3;
|
|
|
|
|
else esc = 10; /* Nothing to see here, move along */
|
2012-05-07 01:57:03 +02:00
|
|
|
|
}
|
2012-05-12 19:57:55 +02:00
|
|
|
|
else if (esc == 2)
|
2012-05-07 01:57:03 +02:00
|
|
|
|
{
|
2012-05-12 19:57:55 +02:00
|
|
|
|
if ((('a' <= b) && (b <= 'z')) || (('A' <= b) && (b <= 'Z')))
|
|
|
|
|
esc = 10;
|
2012-05-07 01:57:03 +02:00
|
|
|
|
}
|
2012-05-12 19:57:55 +02:00
|
|
|
|
else if ((esc == 3) && (b == 'P'))
|
2012-05-07 01:57:03 +02:00
|
|
|
|
{
|
2012-05-12 19:57:55 +02:00
|
|
|
|
esc = ~0;
|
2012-05-07 01:57:03 +02:00
|
|
|
|
}
|
2012-05-12 19:57:55 +02:00
|
|
|
|
else if (esc < 0)
|
2012-05-07 01:57:03 +02:00
|
|
|
|
{
|
2012-05-12 19:57:55 +02:00
|
|
|
|
esc--;
|
|
|
|
|
if (esc == ~7)
|
|
|
|
|
esc = 10;
|
2012-05-07 01:57:03 +02:00
|
|
|
|
}
|
2012-05-12 19:57:55 +02:00
|
|
|
|
else
|
|
|
|
|
esc = 10;
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
/* Can be printed:
|
|
|
|
|
within bounds ∨
|
|
|
|
|
∨ escape sequence ∨
|
|
|
|
|
∨ last with printed ∧ not first byte in character */
|
|
|
|
|
(x < width) ||
|
|
|
|
|
(esc != 0) ||
|
|
|
|
|
(ok && ((b & 0xC0) == 0x80)))
|
2012-05-07 01:57:03 +02:00
|
|
|
|
{
|
2012-05-12 19:57:55 +02:00
|
|
|
|
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;
|
2012-05-07 01:57:03 +02:00
|
|
|
|
}
|
2012-05-12 19:57:55 +02:00
|
|
|
|
else
|
|
|
|
|
ok = false;
|
|
|
|
|
|
|
|
|
|
if (esc == 10)
|
|
|
|
|
esc = 0;
|
2012-05-07 01:57:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-12 19:57:55 +02:00
|
|
|
|
/* Converts a string to an integer
|
2012-05-07 01:57:03 +02:00
|
|
|
|
* @param string The string to convert
|
|
|
|
|
* @return The integer represented by the string
|
|
|
|
|
*/
|
|
|
|
|
int toInt(String string)
|
|
|
|
|
{
|
2012-05-12 19:57:55 +02:00
|
|
|
|
int rc = 0;
|
|
|
|
|
String str = string;
|
|
|
|
|
char c = 0;
|
|
|
|
|
|
|
|
|
|
while ((c = *str++) != 0)
|
|
|
|
|
rc = (rc << 1) + (rc << 3) - (c & 15);
|
|
|
|
|
|
|
|
|
|
return -rc;
|
2012-05-07 01:57:03 +02:00
|
|
|
|
}
|