ponysay/truncater.c

154 lines
3.2 KiB
C
Raw Permalink Normal View History

/* ponysaytruncater
* Output truncater used by ponysay to stop
* large ponies from being printed badly.
2012-05-07 01:57:03 +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
/* Stdin file descriptor ID */
2012-05-07 01:57:03 +02:00
#define STDIN 0
/* The number of columns on the current line */
static int col = 0;
2012-05-07 01:57:03 +02:00
/* Escape sequence state */
2012-05-07 01:57:03 +02:00
static int esc = 0;
/* 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);
/* 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 an argument.
*
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)
{
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
}
/* 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)
{
int i;
char tabstop;
if (esc == 0)
2012-05-07 01:57:03 +02:00
{
if (b == '\n')
2012-05-07 01:57:03 +02:00
{
if (col >= width)
2012-05-07 01:57:03 +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
}
col = -1;
2012-05-07 01:57:03 +02:00
}
else if (b == '\t')
2012-05-07 01:57:03 +02:00
{
/* Tab to next pos ≡₈ 0 */
tabstop = 8 - (col & 7);
for (i = 0; i < tabstop; i++)
write(' ', width);
return; /* (!) */
2012-05-07 01:57:03 +02:00
}
else if (b == '\e')
esc = 1;
2012-05-07 01:57:03 +02:00
}
else if (esc == 1)
2012-05-07 01:57:03 +02:00
{
2012-05-12 19:24:10 +02:00
if (b == '[') esc = 2; /* CSI: CSI ends with a letter, m is for colour */
else if (b == ']') esc = 3; /* OSI: OSI P is for palette editing in Linux VT */
else esc = 10; /* Nothing to see here, move along */
2012-05-07 01:57:03 +02:00
}
else if (esc == 2)
2012-05-07 01:57:03 +02:00
{
if ((('a' <= b) && (b <= 'z')) || (('A' <= b) && (b <= 'Z')))
esc = 10;
2012-05-07 01:57:03 +02:00
}
else if ((esc == 3) && (b == 'P'))
2012-05-07 01:57:03 +02:00
{
esc = ~0;
2012-05-07 01:57:03 +02:00
}
else if (esc < 0)
2012-05-07 01:57:03 +02:00
{
esc--;
if (esc == ~7)
esc = 10;
2012-05-07 01:57:03 +02:00
}
else
esc = 10;
if (
/* Can be printed:
2012-05-12 19:24:10 +02:00
within bounds
escape sequence
last with printed not first byte in character */
(col < width) ||
(esc != 0) ||
(ok && ((b & 0xC0) == 0x80)))
2012-05-07 01:57:03 +02:00
{
printf("%c", b);
if ((esc == 0) && ((b & 0xC0) != 0x80))
/* Count up columns of not in escape sequnce and */
col++; /* the byte is not the first byte in the character */
ok = true;
2012-05-07 01:57:03 +02:00
}
else
ok = false;
if (esc == 10)
esc = 0;
2012-05-07 01:57:03 +02:00
}
/* Converts a string to an integer
2012-05-12 19:24:10 +02:00
*
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)
{
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
}