Port of Truncater to C

This commit is contained in:
Mattias Andrée 2012-05-07 01:57:03 +02:00
parent fa5a06db88
commit 986d158bfe
2 changed files with 174 additions and 150 deletions

View file

@ -1,150 +0,0 @@
import java.io.*;
public class Truncater
{
public static void main(final String... args) throws IOException
{
final int width;
if ((width = getWidth()) > 15) //sanity
{
final OutputStream stdout = new BufferedOutputStream(System.out);
OutputStream out = new OutputStream()
{
/**
* The number of column on the current line
*/
private int x = 0;
/**
* Escape sequence state
*/
private int esc = 0;
/**
* Last bytes as written
*/
private boolean ok = true;
/**
* {@inheritDoc}
*/
@Override
public void write(final int b) throws IOException
{
if (this.esc == 0)
{
if (b == '\n')
{
if (x >= width)
{
write('\033');
write('[');
write('4');
write('9');
write('m');
}
this.x = -1;
}
else if (b == '\t')
{
int nx = 8 - (x & 7);
for (int i = 0; i < nx; i++)
write(' ');
return; //(!)
}
else if (b == '\033')
this.esc = 1;
}
else if (this.esc == 1)
{
if (b == '[') this.esc = 2;
else if (b == ']') this.esc = 3;
else this.esc = 10;
}
else if (this.esc == 2)
{
if ((('a' <= b) && (b <= 'z')) || (('A' <= b) && (b <= 'Z')))
this.esc = 10;
}
else if ((this.esc == 3) && (b == 'P'))
{
this.esc = ~0;
}
else if (this.esc < 0)
{
this.esc--;
if (this.esc == ~7)
this.esc = 10;
}
else
this.esc = 10;
if ((x < width) || (this.esc != 0) || (ok && ((b & 0xC0) == 0x80)))
{
stdout.write(b);
if (this.esc == 0)
if ((b & 0xC0) != 0x80)
x++;
ok = true;
}
else
ok = false;
if (this.esc == 10)
this.esc = 0;
}
/**
* {@inheritDoc}
*/
@Override
public void flush() throws IOException
{
stdout.flush();
}
};
System.setOut(new PrintStream(out));
}
InputStream in = System.in;
OutputStream out = System.out;
for (int d; (d = in.read()) != -1;)
out.write(d);
out.flush();
}
/**
* Gets the width of the terminal
*
* @return The width of the terminal
*/
public static int getWidth()
{
try
{
Process process = (new ProcessBuilder("/bin/sh", "-c", "tput cols 2> " + (new File("/dev/stderr")).getCanonicalPath())).start();
String rcs = new String();
InputStream stream = process.getInputStream();
int c;
while (((c = stream.read()) != '\n') && (c != -1))
rcs += (char)c;
try
{
stream.close();
}
catch (final Throwable err)
{
//Ignore
}
return Integer.parseInt(rcs);
}
catch (final Throwable err)
{
return -1;
}
}
}

174
ponysaytruncater.c Normal file
View file

@ -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 <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;
}