blob: 987ba691d03246d884f111e4fd563a0c18a1b48e [file] [log] [blame]
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <unistd.h>
#include "vterm.h"
#define DEFINE_INLINES
#include "../src/utf8.h" // fill_utf8
#define streq(a,b) (!strcmp(a,b))
static VTerm *vt;
static VTermScreen *vts;
static int cols;
static int rows;
static enum {
FORMAT_PLAIN,
FORMAT_SGR,
} format = FORMAT_PLAIN;
static int col2index(VTermColor target)
{
int index;
for(index = 0; index < 256; index++) {
VTermColor col;
vterm_state_get_palette_color(NULL, index, &col);
if(col.red == target.red && col.green == target.green && col.blue == target.blue)
return index;
}
return -1;
}
static void dump_cell(const VTermScreenCell *cell, const VTermScreenCell *prevcell)
{
switch(format) {
case FORMAT_PLAIN:
break;
case FORMAT_SGR:
{
// If all 7 attributes change, that means 7 SGRs max
// Each colour could consume up to 3
int sgr[7 + 2*3]; int sgri = 0;
if(!prevcell->attrs.bold && cell->attrs.bold)
sgr[sgri++] = 1;
if(prevcell->attrs.bold && !cell->attrs.bold)
sgr[sgri++] = 22;
if(!prevcell->attrs.underline && cell->attrs.underline)
sgr[sgri++] = 4;
if(prevcell->attrs.underline && !cell->attrs.underline)
sgr[sgri++] = 24;
if(!prevcell->attrs.italic && cell->attrs.italic)
sgr[sgri++] = 3;
if(prevcell->attrs.italic && !cell->attrs.italic)
sgr[sgri++] = 23;
if(!prevcell->attrs.blink && cell->attrs.blink)
sgr[sgri++] = 5;
if(prevcell->attrs.blink && !cell->attrs.blink)
sgr[sgri++] = 25;
if(!prevcell->attrs.reverse && cell->attrs.reverse)
sgr[sgri++] = 7;
if(prevcell->attrs.reverse && !cell->attrs.reverse)
sgr[sgri++] = 27;
if(!prevcell->attrs.strike && cell->attrs.strike)
sgr[sgri++] = 9;
if(prevcell->attrs.strike && !cell->attrs.strike)
sgr[sgri++] = 29;
if(!prevcell->attrs.font && cell->attrs.font)
sgr[sgri++] = 10 + cell->attrs.font;
if(prevcell->attrs.font && !cell->attrs.font)
sgr[sgri++] = 10;
if(prevcell->fg.red != cell->fg.red ||
prevcell->fg.green != cell->fg.green ||
prevcell->fg.blue != cell->fg.blue) {
int index = col2index(cell->fg);
if(index == -1)
sgr[sgri++] = 39;
else if(index < 8)
sgr[sgri++] = 30 + index;
else if(index < 16)
sgr[sgri++] = 90 + (index - 8);
else {
sgr[sgri++] = 38;
sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE;
sgr[sgri++] = index | CSI_ARG_FLAG_MORE;
}
}
if(prevcell->bg.red != cell->bg.red ||
prevcell->bg.green != cell->bg.green ||
prevcell->bg.blue != cell->bg.blue) {
int index = col2index(cell->bg);
if(index == -1)
sgr[sgri++] = 49;
else if(index < 8)
sgr[sgri++] = 40 + index;
else if(index < 16)
sgr[sgri++] = 100 + (index - 8);
else {
sgr[sgri++] = 48;
sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE;
sgr[sgri++] = index | CSI_ARG_FLAG_MORE;
}
}
if(!sgri)
break;
printf("\x1b[");
{
int i;
for(i = 0; i < sgri; i++)
printf(!i ? "%d" :
CSI_ARG_HAS_MORE(sgr[i]) ? ":%d" :
";%d",
CSI_ARG(sgr[i]));
}
printf("m");
}
break;
}
{
int i;
for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) {
char bytes[6];
bytes[fill_utf8(cell->chars[i], bytes)] = 0;
printf("%s", bytes);
}
}
}
static void dump_eol(const VTermScreenCell *prevcell)
{
switch(format) {
case FORMAT_PLAIN:
break;
case FORMAT_SGR:
if(prevcell->attrs.bold || prevcell->attrs.underline || prevcell->attrs.italic ||
prevcell->attrs.blink || prevcell->attrs.reverse || prevcell->attrs.strike ||
prevcell->attrs.font)
printf("\x1b[m");
break;
}
printf("\n");
}
void dump_row(int row)
{
VTermPos pos;
VTermScreenCell prevcell;
pos.row = row;
pos.col = 0;
memset(&prevcell, 0, sizeof(prevcell));
vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg);
while(pos.col < cols) {
VTermScreenCell cell;
vterm_screen_get_cell(vts, pos, &cell);
dump_cell(&cell, &prevcell);
pos.col += cell.width;
prevcell = cell;
}
dump_eol(&prevcell);
}
static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
{
VTermScreenCell prevcell;
int col;
memset(&prevcell, 0, sizeof(prevcell));
vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg);
for(col = 0; col < cols; col++) {
dump_cell(cells + col, &prevcell);
prevcell = cells[col];
}
dump_eol(&prevcell);
return 1;
}
static int screen_resize(int new_rows, int new_cols, void *user)
{
rows = new_rows;
cols = new_cols;
return 1;
}
static VTermScreenCallbacks cb_screen = {
NULL, // damage
NULL, // moverect
NULL, // movecursor
NULL, // settermprop
NULL, // bell
&screen_resize, // resize
&screen_sb_pushline, // sb_pushline
NULL, // popline
};
int main(int argc, char *argv[])
{
int opt;
const char *file;
int fd;
int len;
char buffer[1024];
int row;
rows = 25;
cols = 80;
while((opt = getopt(argc, argv, "f:l:c:")) != -1) {
switch(opt) {
case 'f':
if(streq(optarg, "plain"))
format = FORMAT_PLAIN;
else if(streq(optarg, "sgr"))
format = FORMAT_SGR;
else {
fprintf(stderr, "Unrecognised format '%s'\n", optarg);
exit(1);
}
break;
case 'l':
rows = atoi(optarg);
if(!rows)
rows = 25;
break;
case 'c':
cols = atoi(optarg);
if(!cols)
cols = 80;
break;
}
}
file = argv[optind++];
fd = open(file, O_RDONLY);
if(fd == -1) {
fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno));
exit(1);
}
vt = vterm_new(rows, cols);
vterm_set_utf8(vt, TRUE);
vts = vterm_obtain_screen(vt);
vterm_screen_set_callbacks(vts, &cb_screen, NULL);
vterm_screen_reset(vts, 1);
while((len = read(fd, buffer, sizeof(buffer))) > 0) {
vterm_input_write(vt, buffer, len);
}
for(row = 0; row < rows; row++) {
dump_row(row);
}
close(fd);
vterm_free(vt);
return 0;
}